Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "ndtxt.hxx"
21 : #include "flyfrm.hxx"
22 : #include "paratr.hxx"
23 : #include <vcl/outdev.hxx>
24 : #include <editeng/paravertalignitem.hxx>
25 :
26 : #include "pormulti.hxx"
27 : #include <pagefrm.hxx>
28 : #include <pagedesc.hxx>
29 : #include <tgrditem.hxx>
30 : #include <porfld.hxx>
31 :
32 : #include "itrtxt.hxx"
33 : #include "txtfrm.hxx"
34 : #include "porfly.hxx"
35 :
36 184833 : void SwTextIter::CtorInitTextIter( SwTextFrm *pNewFrm, SwTextInfo *pNewInf )
37 : {
38 184833 : SwTextNode *pNode = pNewFrm->GetTextNode();
39 :
40 : OSL_ENSURE( pNewFrm->GetPara(), "No paragraph" );
41 :
42 184833 : CtorInitAttrIter( *pNode, pNewFrm->GetPara()->GetScriptInfo(), pNewFrm );
43 :
44 184833 : pFrm = pNewFrm;
45 184833 : pInf = pNewInf;
46 184833 : aLineInf.CtorInitLineInfo( pNode->GetSwAttrSet(), *pNode );
47 184833 : nFrameStart = pFrm->Frm().Pos().Y() + pFrm->Prt().Pos().Y();
48 184833 : SwTextIter::Init();
49 :
50 : // Order is important: only execute FillRegister if GetValue!=0
51 184833 : bRegisterOn = pNode->GetSwAttrSet().GetRegister().GetValue()
52 184833 : && pFrm->FillRegister( nRegStart, nRegDiff );
53 184833 : }
54 :
55 186247 : void SwTextIter::Init()
56 : {
57 186247 : pCurr = pInf->GetParaPortion();
58 186247 : nStart = pInf->GetTextStart();
59 186247 : nY = nFrameStart;
60 186247 : bPrev = true;
61 186247 : pPrev = 0;
62 186247 : nLineNr = 1;
63 186247 : }
64 :
65 92627 : void SwTextIter::CalcAscentAndHeight( sal_uInt16 &rAscent, sal_uInt16 &rHeight ) const
66 : {
67 92627 : rHeight = GetLineHeight();
68 92627 : rAscent = pCurr->GetAscent() + rHeight - pCurr->Height();
69 92627 : }
70 :
71 82 : SwLineLayout *SwTextIter::_GetPrev()
72 : {
73 82 : pPrev = 0;
74 82 : bPrev = true;
75 82 : SwLineLayout *pLay = pInf->GetParaPortion();
76 82 : if( pCurr == pLay )
77 10 : return 0;
78 1836 : while( pLay->GetNext() != pCurr )
79 1692 : pLay = pLay->GetNext();
80 72 : return pPrev = pLay;
81 : }
82 :
83 48244 : const SwLineLayout *SwTextIter::GetPrev()
84 : {
85 48244 : if(! bPrev)
86 0 : _GetPrev();
87 48244 : return pPrev;
88 : }
89 :
90 4578 : const SwLineLayout *SwTextIter::Prev()
91 : {
92 4578 : if( !bPrev )
93 82 : _GetPrev();
94 4578 : if( pPrev )
95 : {
96 1898 : bPrev = false;
97 1898 : pCurr = pPrev;
98 1898 : nStart = nStart - pCurr->GetLen();
99 1898 : nY = nY - GetLineHeight();
100 1898 : if( !pCurr->IsDummy() && !(--nLineNr) )
101 4 : ++nLineNr;
102 1898 : return pCurr;
103 : }
104 : else
105 2680 : return 0;
106 : }
107 :
108 664488 : const SwLineLayout *SwTextIter::Next()
109 : {
110 664488 : if(pCurr->GetNext())
111 : {
112 462057 : pPrev = pCurr;
113 462057 : bPrev = true;
114 462057 : nStart = nStart + pCurr->GetLen();
115 462057 : nY += GetLineHeight();
116 462057 : if( pCurr->GetLen() || ( nLineNr>1 && !pCurr->IsDummy() ) )
117 460735 : ++nLineNr;
118 462057 : return pCurr = pCurr->GetNext();
119 : }
120 : else
121 202431 : return 0;
122 : }
123 :
124 16 : const SwLineLayout *SwTextIter::NextLine()
125 : {
126 16 : const SwLineLayout *pNext = Next();
127 32 : while( pNext && pNext->IsDummy() && pNext->GetNext() )
128 : {
129 0 : pNext = Next();
130 : }
131 16 : return pNext;
132 : }
133 :
134 58855 : const SwLineLayout *SwTextIter::GetNextLine() const
135 : {
136 58855 : const SwLineLayout *pNext = pCurr->GetNext();
137 117746 : while( pNext && pNext->IsDummy() && pNext->GetNext() )
138 : {
139 36 : pNext = pNext->GetNext();
140 : }
141 58855 : return pNext;
142 : }
143 :
144 11 : const SwLineLayout *SwTextIter::GetPrevLine()
145 : {
146 11 : const SwLineLayout *pRoot = pInf->GetParaPortion();
147 11 : if( pRoot == pCurr )
148 10 : return 0;
149 1 : const SwLineLayout *pLay = pRoot;
150 :
151 3 : while( pLay->GetNext() != pCurr )
152 1 : pLay = pLay->GetNext();
153 :
154 1 : if( pLay->IsDummy() )
155 : {
156 1 : const SwLineLayout *pTmp = pRoot;
157 1 : pLay = pRoot->IsDummy() ? 0 : pRoot;
158 3 : while( pTmp->GetNext() != pCurr )
159 : {
160 1 : if( !pTmp->IsDummy() )
161 0 : pLay = pTmp;
162 1 : pTmp = pTmp->GetNext();
163 : }
164 : }
165 :
166 : // Wenn sich nichts getan hat, dann gibt es nur noch Dummys
167 1 : return pLay;
168 : }
169 :
170 1436 : const SwLineLayout *SwTextIter::PrevLine()
171 : {
172 1436 : const SwLineLayout *pMyPrev = Prev();
173 1436 : if( !pMyPrev )
174 312 : return 0;
175 :
176 1124 : const SwLineLayout *pLast = pMyPrev;
177 2259 : while( pMyPrev && pMyPrev->IsDummy() )
178 : {
179 11 : pLast = pMyPrev;
180 11 : pMyPrev = Prev();
181 : }
182 1124 : return pMyPrev ? pMyPrev : pLast;
183 : }
184 :
185 97067 : void SwTextIter::Bottom()
186 : {
187 97067 : while( Next() )
188 : {
189 : // nothing
190 : }
191 97067 : }
192 :
193 116917 : void SwTextIter::CharToLine(const sal_Int32 nChar)
194 : {
195 116917 : while( nStart + pCurr->GetLen() <= nChar && Next() )
196 : ;
197 116917 : while( nStart > nChar && Prev() )
198 : ;
199 116917 : }
200 :
201 : // 1170: beruecksichtigt Mehrdeutigkeiten:
202 70172 : const SwLineLayout *SwTextCursor::CharCrsrToLine( const sal_Int32 nPosition )
203 : {
204 70172 : CharToLine( nPosition );
205 70172 : if( nPosition != nStart )
206 25275 : bRightMargin = false;
207 70172 : bool bPrevious = bRightMargin && pCurr->GetLen() && GetPrev() &&
208 70172 : GetPrev()->GetLen();
209 70172 : if( bPrevious && nPosition && CH_BREAK == GetInfo().GetChar( nPosition-1 ) )
210 0 : bPrevious = false;
211 70172 : return bPrevious ? PrevLine() : pCurr;
212 : }
213 :
214 58207 : sal_uInt16 SwTextCursor::AdjustBaseLine( const SwLineLayout& rLine,
215 : const SwLinePortion* pPor,
216 : sal_uInt16 nPorHeight, sal_uInt16 nPorAscent,
217 : const bool bAutoToCentered ) const
218 : {
219 58207 : if ( pPor )
220 : {
221 1030 : nPorHeight = pPor->Height();
222 1030 : nPorAscent = pPor->GetAscent();
223 : }
224 :
225 58207 : sal_uInt16 nOfst = rLine.GetRealHeight() - rLine.Height();
226 :
227 58207 : SwTextGridItem const*const pGrid(GetGridItem(pFrm->FindPageFrm()));
228 :
229 58207 : if ( pGrid && GetInfo().SnapToGrid() )
230 : {
231 1099 : const sal_uInt16 nRubyHeight = pGrid->GetRubyHeight();
232 1099 : const bool bRubyTop = ! pGrid->GetRubyTextBelow();
233 :
234 1099 : if ( GetInfo().IsMulti() )
235 : // we are inside the GetCharRect recursion for multi portions
236 : // we center the portion in its surrounding line
237 0 : nOfst = ( pCurr->Height() - nPorHeight ) / 2 + nPorAscent;
238 : else
239 : {
240 : // We have to take care for ruby portions.
241 : // The ruby portion is NOT centered
242 1099 : nOfst = nOfst + nPorAscent;
243 :
244 1099 : if ( ! pPor || ! pPor->IsMultiPortion() ||
245 0 : ! static_cast<const SwMultiPortion*>(pPor)->IsRuby() )
246 : {
247 : // Portions which are bigger than on grid distance are
248 : // centered inside the whole line.
249 :
250 : //for text refactor
251 1099 : const sal_uInt16 nLineNet = rLine.Height() - nRubyHeight;
252 : //const sal_uInt16 nLineNet = ( nPorHeight > nGridWidth ) ?
253 : // rLine.Height() - nRubyHeight :
254 : // nGridWidth;
255 1099 : nOfst += ( nLineNet - nPorHeight ) / 2;
256 1099 : if ( bRubyTop )
257 1099 : nOfst += nRubyHeight;
258 : }
259 : }
260 : }
261 : else
262 : {
263 57108 : switch ( GetLineInfo().GetVertAlign() ) {
264 : case SvxParaVertAlignItem::TOP :
265 0 : nOfst = nOfst + nPorAscent;
266 0 : break;
267 : case SvxParaVertAlignItem::CENTER :
268 : OSL_ENSURE( rLine.Height() >= nPorHeight, "Portion height > Line height");
269 0 : nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent;
270 0 : break;
271 : case SvxParaVertAlignItem::BOTTOM :
272 0 : nOfst += rLine.Height() - nPorHeight + nPorAscent;
273 0 : break;
274 : case SvxParaVertAlignItem::AUTOMATIC :
275 57004 : if ( bAutoToCentered || GetInfo().GetTextFrm()->IsVertical() )
276 : {
277 0 : if( GetInfo().GetTextFrm()->IsVertLR() )
278 0 : nOfst += rLine.Height() - ( rLine.Height() - nPorHeight ) / 2 - nPorAscent;
279 : else
280 0 : nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent;
281 0 : break;
282 : }
283 : case SvxParaVertAlignItem::BASELINE :
284 : // base line
285 57108 : nOfst = nOfst + rLine.GetAscent();
286 57108 : break;
287 : }
288 : }
289 :
290 58207 : return nOfst;
291 : }
292 :
293 12789 : const SwLineLayout *SwTextIter::TwipsToLine( const SwTwips y)
294 : {
295 12789 : while( nY + GetLineHeight() <= y && Next() )
296 : ;
297 12789 : while( nY > y && Prev() )
298 : ;
299 12789 : return pCurr;
300 : }
301 :
302 : // Local helper function to check, if pCurr needs a field rest portion:
303 257 : static bool lcl_NeedsFieldRest( const SwLineLayout* pCurr )
304 : {
305 257 : const SwLinePortion *pPor = pCurr->GetPortion();
306 257 : bool bRet = false;
307 515 : while( pPor && !bRet )
308 : {
309 138 : bRet = pPor->InFieldGrp() && static_cast<const SwFieldPortion*>(pPor)->HasFollow();
310 138 : if( !pPor->GetPortion() || !pPor->GetPortion()->InFieldGrp() )
311 137 : break;
312 1 : pPor = pPor->GetPortion();
313 : }
314 257 : return bRet;
315 : }
316 :
317 51798 : void SwTextIter::TruncLines( bool bNoteFollow )
318 : {
319 51798 : SwLineLayout *pDel = pCurr->GetNext();
320 51798 : const sal_Int32 nEnd = nStart + pCurr->GetLen();
321 :
322 51798 : if( pDel )
323 : {
324 1171 : pCurr->SetNext( 0 );
325 1171 : if( GetHints() && bNoteFollow )
326 : {
327 771 : GetInfo().GetParaPortion()->SetFollowField( pDel->IsRest() ||
328 771 : lcl_NeedsFieldRest( pCurr ) );
329 :
330 : // bug 88534: wrong positioning of flys
331 257 : SwTextFrm* pFollow = GetTextFrm()->GetFollow();
332 496 : if ( pFollow && ! pFollow->IsLocked() &&
333 239 : nEnd == pFollow->GetOfst() )
334 : {
335 191 : sal_Int32 nRangeEnd = nEnd;
336 191 : SwLineLayout* pLine = pDel;
337 :
338 : // determine range to be searched for flys anchored as characters
339 573 : while ( pLine )
340 : {
341 191 : nRangeEnd = nRangeEnd + pLine->GetLen();
342 191 : pLine = pLine->GetNext();
343 : }
344 :
345 191 : SwpHints* pTmpHints = GetTextFrm()->GetTextNode()->GetpSwpHints();
346 :
347 : // examine hints in range nEnd - (nEnd + nRangeChar)
348 710 : for( size_t i = 0; i < pTmpHints->Count(); ++i )
349 : {
350 519 : const SwTextAttr* pHt = pTmpHints->GetTextHint( i );
351 519 : if( RES_TXTATR_FLYCNT == pHt->Which() )
352 : {
353 : // check, if hint is in our range
354 28 : const sal_uInt16 nTmpPos = pHt->GetStart();
355 28 : if ( nEnd <= nTmpPos && nTmpPos < nRangeEnd )
356 : pFollow->_InvalidateRange(
357 11 : SwCharRange( nTmpPos, nTmpPos ), 0 );
358 : }
359 : }
360 : }
361 : }
362 1171 : delete pDel;
363 : }
364 115389 : if( pCurr->IsDummy() &&
365 63447 : !pCurr->GetLen() &&
366 11649 : nStart < GetTextFrm()->GetText().getLength() )
367 9 : pCurr->SetRealHeight( 1 );
368 51798 : if( GetHints() )
369 25892 : pFrm->RemoveFootnote( nEnd );
370 51798 : }
371 :
372 1 : void SwTextIter::CntHyphens( sal_uInt8 &nEndCnt, sal_uInt8 &nMidCnt) const
373 : {
374 1 : nEndCnt = 0;
375 1 : nMidCnt = 0;
376 1 : if ( bPrev && pPrev && !pPrev->IsEndHyph() && !pPrev->IsMidHyph() )
377 0 : return;
378 1 : SwLineLayout *pLay = pInf->GetParaPortion();
379 1 : if( pCurr == pLay )
380 1 : return;
381 0 : while( pLay != pCurr )
382 : {
383 0 : if ( pLay->IsEndHyph() )
384 0 : nEndCnt++;
385 : else
386 0 : nEndCnt = 0;
387 0 : if ( pLay->IsMidHyph() )
388 0 : nMidCnt++;
389 : else
390 0 : nMidCnt = 0;
391 0 : pLay = pLay->GetNext();
392 : }
393 : }
394 :
395 : // Change current output device to formatting device, this has to be done before
396 : // formatting.
397 84215 : SwHookOut::SwHookOut( SwTextSizeInfo& rInfo ) :
398 : pInf( &rInfo ),
399 : pOut( rInfo.GetOut() ),
400 84215 : bOnWin( rInfo.OnWin() )
401 : {
402 : OSL_ENSURE( rInfo.GetRefDev(), "No reference device for text formatting" );
403 :
404 : // set new values
405 84215 : rInfo.SetOut( rInfo.GetRefDev() );
406 84215 : rInfo.SetOnWin( false );
407 84215 : }
408 :
409 168430 : SwHookOut::~SwHookOut()
410 : {
411 84215 : pInf->SetOut( pOut );
412 84215 : pInf->SetOnWin( bOnWin );
413 84392 : }
414 :
415 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|