xref: /AOO41X/main/sw/source/core/text/itrtxt.cxx (revision efeef26f81c84063fb0a91bde3856d4a51172d90)
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