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