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