1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26
27
28 #include "ndtxt.hxx"
29 #include "flyfrm.hxx"
30 #include "paratr.hxx"
31 #include "errhdl.hxx"
32 #include <vcl/outdev.hxx>
33 #include <editeng/paravertalignitem.hxx>
34
35 #include "pormulti.hxx"
36 #include <pagefrm.hxx>
37 #include <pagedesc.hxx> // SwPageDesc
38 #include <tgrditem.hxx>
39 #include <porfld.hxx>
40
41 #include "txtcfg.hxx"
42 #include "itrtxt.hxx"
43 #include "txtfrm.hxx"
44 #include "porfly.hxx"
45
46 #if OSL_DEBUG_LEVEL > 1
47 # include "txtfrm.hxx" // GetFrmID,
48 #endif
49
50 /*************************************************************************
51 * SwTxtIter::CtorInitTxtIter()
52 *************************************************************************/
53
CtorInitTxtIter(SwTxtFrm * pNewFrm,SwTxtInfo * pNewInf)54 void SwTxtIter::CtorInitTxtIter( SwTxtFrm *pNewFrm, SwTxtInfo *pNewInf )
55 {
56 #ifdef DBGTXT
57 // nStopAt laesst sich vom CV bearbeiten.
58 static MSHORT nStopAt = 0;
59 if( nStopAt == pNewFrm->GetFrmId() )
60 {
61 int i = pNewFrm->GetFrmId();
62 }
63 #endif
64
65 SwTxtNode *pNode = pNewFrm->GetTxtNode();
66
67 ASSERT( pNewFrm->GetPara(), "No paragraph" );
68
69 CtorInitAttrIter( *pNode, pNewFrm->GetPara()->GetScriptInfo(), pNewFrm );
70
71 pFrm = pNewFrm;
72 pInf = pNewInf;
73 // --> OD 2008-01-17 #newlistlevelattrs#
74 aLineInf.CtorInitLineInfo( pNode->GetSwAttrSet(), *pNode );
75 // <--
76 nFrameStart = pFrm->Frm().Pos().Y() + pFrm->Prt().Pos().Y();
77 SwTxtIter::Init();
78 if( pNode->GetSwAttrSet().GetRegister().GetValue() )
79 bRegisterOn = pFrm->FillRegister( nRegStart, nRegDiff );
80 else
81 bRegisterOn = sal_False;
82 }
83
84 /*************************************************************************
85 * SwTxtIter::Init()
86 *************************************************************************/
87
Init()88 void SwTxtIter::Init()
89 {
90 pCurr = pInf->GetParaPortion();
91 nStart = pInf->GetTxtStart();
92 nY = nFrameStart;
93 bPrev = sal_True;
94 pPrev = 0;
95 nLineNr = 1;
96 }
97
98 /*************************************************************************
99 * SwTxtIter::_GetHeightAndAscent()
100 *************************************************************************/
101
CalcAscentAndHeight(KSHORT & rAscent,KSHORT & rHeight) const102 void SwTxtIter::CalcAscentAndHeight( KSHORT &rAscent, KSHORT &rHeight ) const
103 {
104 rHeight = GetLineHeight();
105 rAscent = pCurr->GetAscent() + rHeight - pCurr->Height();
106 }
107
108 /*************************************************************************
109 * SwTxtIter::_GetPrev()
110 *************************************************************************/
111
_GetPrev()112 SwLineLayout *SwTxtIter::_GetPrev()
113 {
114 pPrev = 0;
115 bPrev = sal_True;
116 SwLineLayout *pLay = pInf->GetParaPortion();
117 if( pCurr == pLay )
118 return 0;
119 while( pLay->GetNext() != pCurr )
120 pLay = pLay->GetNext();
121 return pPrev = pLay;
122 }
123
124 /*************************************************************************
125 * SwTxtIter::GetPrev()
126 *************************************************************************/
127
GetPrev()128 const SwLineLayout *SwTxtIter::GetPrev()
129 {
130 if(! bPrev)
131 _GetPrev();
132 return pPrev;
133 }
134
135 /*************************************************************************
136 * SwTxtIter::Prev()
137 *************************************************************************/
138
Prev()139 const SwLineLayout *SwTxtIter::Prev()
140 {
141 if( !bPrev )
142 _GetPrev();
143 if( pPrev )
144 {
145 bPrev = sal_False;
146 pCurr = pPrev;
147 nStart = nStart - pCurr->GetLen();
148 nY = nY - GetLineHeight();
149 if( !pCurr->IsDummy() && !(--nLineNr) )
150 ++nLineNr;
151 return pCurr;
152 }
153 else
154 return 0;
155 }
156
157 /*************************************************************************
158 * SwTxtIter::Next()
159 *************************************************************************/
160
Next()161 const SwLineLayout *SwTxtIter::Next()
162 {
163 if(pCurr->GetNext())
164 {
165 pPrev = pCurr;
166 bPrev = sal_True;
167 nStart = nStart + pCurr->GetLen();
168 nY += GetLineHeight();
169 if( pCurr->GetLen() || ( nLineNr>1 && !pCurr->IsDummy() ) )
170 ++nLineNr;
171 return pCurr = pCurr->GetNext();
172 }
173 else
174 return 0;
175 }
176
177 /*************************************************************************
178 * SwTxtIter::NextLine()
179 *************************************************************************/
180
NextLine()181 const SwLineLayout *SwTxtIter::NextLine()
182 {
183 const SwLineLayout *pNext = Next();
184 while( pNext && pNext->IsDummy() && pNext->GetNext() )
185 {
186 DBG_LOOP;
187 pNext = Next();
188 }
189 return pNext;
190 }
191
192 /*************************************************************************
193 * SwTxtIter::GetNextLine()
194 *************************************************************************/
195
GetNextLine() const196 const SwLineLayout *SwTxtIter::GetNextLine() const
197 {
198 const SwLineLayout *pNext = pCurr->GetNext();
199 while( pNext && pNext->IsDummy() && pNext->GetNext() )
200 {
201 DBG_LOOP;
202 pNext = pNext->GetNext();
203 }
204 return (SwLineLayout*)pNext;
205 }
206
207 /*************************************************************************
208 * SwTxtIter::GetPrevLine()
209 *************************************************************************/
210
GetPrevLine()211 const SwLineLayout *SwTxtIter::GetPrevLine()
212 {
213 const SwLineLayout *pRoot = pInf->GetParaPortion();
214 if( pRoot == pCurr )
215 return 0;
216 const SwLineLayout *pLay = pRoot;
217
218 while( pLay->GetNext() != pCurr )
219 pLay = pLay->GetNext();
220
221 if( pLay->IsDummy() )
222 {
223 const SwLineLayout *pTmp = pRoot;
224 pLay = pRoot->IsDummy() ? 0 : pRoot;
225 while( pTmp->GetNext() != pCurr )
226 {
227 if( !pTmp->IsDummy() )
228 pLay = pTmp;
229 pTmp = pTmp->GetNext();
230 }
231 }
232
233 // Wenn sich nichts getan hat, dann gibt es nur noch Dummys
234 return (SwLineLayout*)pLay;
235 }
236
237 /*************************************************************************
238 * SwTxtIter::PrevLine()
239 *************************************************************************/
240
PrevLine()241 const SwLineLayout *SwTxtIter::PrevLine()
242 {
243 const SwLineLayout *pMyPrev = Prev();
244 if( !pMyPrev )
245 return 0;
246
247 const SwLineLayout *pLast = pMyPrev;
248 while( pMyPrev && pMyPrev->IsDummy() )
249 {
250 DBG_LOOP;
251 pLast = pMyPrev;
252 pMyPrev = Prev();
253 }
254 return (SwLineLayout*)(pMyPrev ? pMyPrev : pLast);
255 }
256
257 /*************************************************************************
258 * SwTxtIter::Bottom()
259 *************************************************************************/
260
Bottom()261 void SwTxtIter::Bottom()
262 {
263 while( Next() )
264 {
265 DBG_LOOP;
266 }
267 }
268
269 /*************************************************************************
270 * SwTxtIter::CharToLine()
271 *************************************************************************/
272
CharToLine(const xub_StrLen nChar)273 void SwTxtIter::CharToLine(const xub_StrLen nChar)
274 {
275 while( nStart + pCurr->GetLen() <= nChar && Next() )
276 ;
277 while( nStart > nChar && Prev() )
278 ;
279 }
280
281 /*************************************************************************
282 * SwTxtIter::CharCrsrToLine()
283 *************************************************************************/
284
285 // 1170: beruecksichtigt Mehrdeutigkeiten:
CharCrsrToLine(const xub_StrLen nPosition)286 const SwLineLayout *SwTxtCursor::CharCrsrToLine( const xub_StrLen nPosition )
287 {
288 CharToLine( nPosition );
289 if( nPosition != nStart )
290 bRightMargin = sal_False;
291 sal_Bool bPrevious = bRightMargin && pCurr->GetLen() && GetPrev() &&
292 GetPrev()->GetLen();
293 if( bPrevious && nPosition && CH_BREAK == GetInfo().GetChar( nPosition-1 ) )
294 bPrevious = sal_False;
295 return bPrevious ? PrevLine() : pCurr;
296 }
297
298 /*************************************************************************
299 * SwTxtCrsr::AdjustBaseLine()
300 *************************************************************************/
301
AdjustBaseLine(const SwLineLayout & rLine,const SwLinePortion * pPor,sal_uInt16 nPorHeight,sal_uInt16 nPorAscent,const sal_Bool bAutoToCentered) const302 sal_uInt16 SwTxtCursor::AdjustBaseLine( const SwLineLayout& rLine,
303 const SwLinePortion* pPor,
304 sal_uInt16 nPorHeight, sal_uInt16 nPorAscent,
305 const sal_Bool bAutoToCentered ) const
306 {
307 if ( pPor )
308 {
309 nPorHeight = pPor->Height();
310 nPorAscent = pPor->GetAscent();
311 }
312
313 sal_uInt16 nOfst = rLine.GetRealHeight() - rLine.Height();
314
315 GETGRID( pFrm->FindPageFrm() )
316 const sal_Bool bHasGrid = pGrid && GetInfo().SnapToGrid();
317
318 if ( bHasGrid )
319 {
320 const sal_uInt16 nRubyHeight = pGrid->GetRubyHeight();
321 const sal_Bool bRubyTop = ! pGrid->GetRubyTextBelow();
322
323 if ( GetInfo().IsMulti() )
324 // we are inside the GetCharRect recursion for multi portions
325 // we center the portion in its surrounding line
326 nOfst = ( pCurr->Height() - nPorHeight ) / 2 + nPorAscent;
327 else
328 {
329 // We have to take care for ruby portions.
330 // The ruby portion is NOT centered
331 nOfst = nOfst + nPorAscent;
332
333 if ( ! pPor || ! pPor->IsMultiPortion() ||
334 ! ((SwMultiPortion*)pPor)->IsRuby() )
335 {
336 // Portions which are bigger than on grid distance are
337 // centered inside the whole line.
338
339 //for text refactor
340 const sal_uInt16 nLineNetto = rLine.Height() - nRubyHeight;
341 //const sal_uInt16 nLineNetto = ( nPorHeight > nGridWidth ) ?
342 // rLine.Height() - nRubyHeight :
343 // nGridWidth;
344 nOfst += ( nLineNetto - nPorHeight ) / 2;
345 if ( bRubyTop )
346 nOfst = nOfst + nRubyHeight;
347 }
348 }
349 }
350 else
351 {
352 switch ( GetLineInfo().GetVertAlign() ) {
353 case SvxParaVertAlignItem::TOP :
354 nOfst = nOfst + nPorAscent;
355 break;
356 case SvxParaVertAlignItem::CENTER :
357 ASSERT( rLine.Height() >= nPorHeight, "Portion height > Line height");
358 nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent;
359 break;
360 case SvxParaVertAlignItem::BOTTOM :
361 nOfst += rLine.Height() - nPorHeight + nPorAscent;
362 break;
363 case SvxParaVertAlignItem::AUTOMATIC :
364 if ( bAutoToCentered || GetInfo().GetTxtFrm()->IsVertical() )
365 {
366 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
367 if( GetInfo().GetTxtFrm()->IsVertLR() )
368 nOfst += rLine.Height() - ( rLine.Height() - nPorHeight ) / 2 - nPorAscent;
369 else
370 nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent;
371 break;
372 }
373 case SvxParaVertAlignItem::BASELINE :
374 // base line
375 nOfst = nOfst + rLine.GetAscent();
376 break;
377 }
378 }
379
380 return nOfst;
381 }
382
383 /*************************************************************************
384 * SwTxtIter::TwipsToLine()
385 *************************************************************************/
386
TwipsToLine(const SwTwips y)387 const SwLineLayout *SwTxtIter::TwipsToLine( const SwTwips y)
388 {
389 while( nY + GetLineHeight() <= y && Next() )
390 ;
391 while( nY > y && Prev() )
392 ;
393 return pCurr;
394 }
395
396 //
397 // Local helper function to check, if pCurr needs a field rest portion:
398 //
lcl_NeedsFieldRest(const SwLineLayout * pCurr)399 sal_Bool lcl_NeedsFieldRest( const SwLineLayout* pCurr )
400 {
401 const SwLinePortion *pPor = pCurr->GetPortion();
402 sal_Bool bRet = sal_False;
403 while( pPor && !bRet )
404 {
405 bRet = pPor->InFldGrp() && ((SwFldPortion*)pPor)->HasFollow();
406 if( !pPor->GetPortion() || !pPor->GetPortion()->InFldGrp() )
407 break;
408 pPor = pPor->GetPortion();
409 }
410 return bRet;
411 }
412
413 /*************************************************************************
414 * SwTxtIter::TruncLines()
415 *************************************************************************/
416
TruncLines(sal_Bool bNoteFollow)417 void SwTxtIter::TruncLines( sal_Bool bNoteFollow )
418 {
419 SwLineLayout *pDel = pCurr->GetNext();
420 const xub_StrLen nEnd = nStart + pCurr->GetLen();
421
422 if( pDel )
423 {
424 pCurr->SetNext( 0 );
425 if( GetHints() && bNoteFollow )
426 {
427 GetInfo().GetParaPortion()->SetFollowField( pDel->IsRest() ||
428 lcl_NeedsFieldRest( pCurr ) );
429
430 // bug 88534: wrong positioning of flys
431 SwTxtFrm* pFollow = GetTxtFrm()->GetFollow();
432 if ( pFollow && ! pFollow->IsLocked() &&
433 nEnd == pFollow->GetOfst() )
434 {
435 xub_StrLen nRangeEnd = nEnd;
436 SwLineLayout* pLine = pDel;
437
438 // determine range to be searched for flys anchored as characters
439 while ( pLine )
440 {
441 nRangeEnd = nRangeEnd + pLine->GetLen();
442 pLine = pLine->GetNext();
443 }
444
445 SwpHints* pTmpHints = GetTxtFrm()->GetTxtNode()->GetpSwpHints();
446
447 // examine hints in range nEnd - (nEnd + nRangeChar)
448 for( sal_uInt16 i = 0; i < pTmpHints->Count(); i++ )
449 {
450 const SwTxtAttr* pHt = pTmpHints->GetTextHint( i );
451 if( RES_TXTATR_FLYCNT == pHt->Which() )
452 {
453 // check, if hint is in our range
454 const sal_uInt16 nTmpPos = *pHt->GetStart();
455 if ( nEnd <= nTmpPos && nTmpPos < nRangeEnd )
456 pFollow->_InvalidateRange(
457 SwCharRange( nTmpPos, nTmpPos ), 0 );
458 }
459 }
460 }
461 }
462 delete pDel;
463 }
464 if( pCurr->IsDummy() &&
465 !pCurr->GetLen() &&
466 nStart < GetTxtFrm()->GetTxt().Len() )
467 pCurr->SetRealHeight( 1 );
468 if( GetHints() )
469 pFrm->RemoveFtn( nEnd );
470 }
471
472 /*************************************************************************
473 * SwTxtIter::CntHyphens()
474 *************************************************************************/
475
CntHyphens(sal_uInt8 & nEndCnt,sal_uInt8 & nMidCnt) const476 void SwTxtIter::CntHyphens( sal_uInt8 &nEndCnt, sal_uInt8 &nMidCnt) const
477 {
478 nEndCnt = 0;
479 nMidCnt = 0;
480 if ( bPrev && pPrev && !pPrev->IsEndHyph() && !pPrev->IsMidHyph() )
481 return;
482 SwLineLayout *pLay = pInf->GetParaPortion();
483 if( pCurr == pLay )
484 return;
485 while( pLay != pCurr )
486 {
487 DBG_LOOP;
488 if ( pLay->IsEndHyph() )
489 nEndCnt++;
490 else
491 nEndCnt = 0;
492 if ( pLay->IsMidHyph() )
493 nMidCnt++;
494 else
495 nMidCnt = 0;
496 pLay = pLay->GetNext();
497 }
498 }
499
500 /*************************************************************************
501 * SwHookOut
502 *
503 * Change current output device to formatting device, this has to be done before
504 * formatting.
505 *************************************************************************/
506
SwHookOut(SwTxtSizeInfo & rInfo)507 SwHookOut::SwHookOut( SwTxtSizeInfo& rInfo ) :
508 pInf( &rInfo ),
509 pOut( rInfo.GetOut() ),
510 bOnWin( rInfo.OnWin() )
511 {
512 ASSERT( rInfo.GetRefDev(), "No reference device for text formatting" )
513
514 // set new values
515 rInfo.SetOut( rInfo.GetRefDev() );
516 rInfo.SetOnWin( sal_False );
517 }
518
~SwHookOut()519 SwHookOut::~SwHookOut()
520 {
521 pInf->SetOut( pOut );
522 pInf->SetOnWin( bOnWin );
523 }
524