xref: /aoo4110/main/sw/source/core/text/itrcrsr.cxx (revision b1cdbd2c)
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 #include "hintids.hxx"
28 #include "errhdl.hxx"
29 #include "ndtxt.hxx"
30 #include "frmfmt.hxx"
31 #include "paratr.hxx"
32 #include "flyfrm.hxx"
33 #include "pam.hxx"
34 #include "swselectionlist.hxx"
35 #include <sortedobjs.hxx>
36 #include <editeng/protitem.hxx>
37 #include <editeng/adjitem.hxx>
38 #include <editeng/lspcitem.hxx>
39 #include <editeng/lrspitem.hxx>
40 #include <frmatr.hxx>
41 #include <pagedesc.hxx> // SwPageDesc
42 #include <tgrditem.hxx>
43 #include <IDocumentSettingAccess.hxx>
44 #include <pagefrm.hxx>
45 
46 #include "txtcfg.hxx"
47 #include "itrtxt.hxx"
48 #include "txtfrm.hxx"
49 #include "flyfrms.hxx"
50 #include "porglue.hxx"		// SwFlyCnt
51 #include "porfld.hxx"		// SwFldPortion::IsFollow()
52 #include "porfly.hxx"		// GetFlyCrsrOfst()
53 #include "pordrop.hxx"
54 #include "crstate.hxx"      // SwCrsrMoveState
55 #include <pormulti.hxx> 	// SwMultiPortion
56 // --> OD 2010-05-05 #i111284#
57 #include <numrule.hxx>
58 // <--
59 
60 // Nicht reentrant !!!
61 // wird in GetCharRect gesetzt und im UnitUp/Down ausgewertet.
62 sal_Bool SwTxtCursor::bRightMargin = sal_False;
63 
64 
65 /*************************************************************************
66  *                    lcl_GetCharRectInsideField
67  *
68  * After calculating the position of a character during GetCharRect
69  * this function allows to find the coordinates of a position (defined
70  * in pCMS->pSpecialPos) inside a special portion (e.g., a field)
71  *************************************************************************/
lcl_GetCharRectInsideField(SwTxtSizeInfo & rInf,SwRect & rOrig,const SwCrsrMoveState & rCMS,const SwLinePortion & rPor)72 void lcl_GetCharRectInsideField( SwTxtSizeInfo& rInf, SwRect& rOrig,
73                                  const SwCrsrMoveState& rCMS,
74                                  const SwLinePortion& rPor )
75 {
76     ASSERT( rCMS.pSpecialPos, "Information about special pos missing" )
77 
78     if ( rPor.InFldGrp() && ((SwFldPortion&)rPor).GetExp().Len() )
79     {
80         const sal_uInt16 nCharOfst = rCMS.pSpecialPos->nCharOfst;
81         sal_uInt16 nFldIdx = 0;
82         sal_uInt16 nFldLen = 0;
83 
84         const XubString* pString = 0;
85         const SwLinePortion* pPor = &rPor;
86         do
87         {
88             if ( pPor->InFldGrp() )
89             {
90                 pString = &((SwFldPortion*)pPor)->GetExp();
91                 nFldLen = pString->Len();
92             }
93             else
94             {
95                 pString = 0;
96                 nFldLen = 0;
97             }
98 
99             if ( ! pPor->GetPortion() || nFldIdx + nFldLen > nCharOfst )
100                 break;
101 
102             nFldIdx = nFldIdx + nFldLen;
103             rOrig.Pos().X() += pPor->Width();
104             pPor = pPor->GetPortion();
105 
106         } while ( sal_True );
107 
108         ASSERT( nCharOfst >= nFldIdx, "Request of position inside field failed" )
109         sal_uInt16 nLen = nCharOfst - nFldIdx + 1;
110 
111         if ( pString )
112         {
113             // get script for field portion
114             rInf.GetFont()->SetActual( SwScriptInfo::WhichFont( 0, pString, 0 ) );
115 
116             xub_StrLen nOldLen = pPor->GetLen();
117             ((SwLinePortion*)pPor)->SetLen( nLen - 1 );
118             const SwTwips nX1 = pPor->GetLen() ?
119                                 pPor->GetTxtSize( rInf ).Width() :
120                                 0;
121 
122             SwTwips nX2 = 0;
123             if ( rCMS.bRealWidth )
124             {
125                 ((SwLinePortion*)pPor)->SetLen( nLen );
126                 nX2 = pPor->GetTxtSize( rInf ).Width();
127             }
128 
129             ((SwLinePortion*)pPor)->SetLen( nOldLen );
130 
131             rOrig.Pos().X() += nX1;
132             rOrig.Width( ( nX2 > nX1 ) ?
133                          ( nX2 - nX1 ) :
134                            1 );
135         }
136     }
137     else
138     {
139         // special cases: no common fields, e.g., graphic number portion,
140         // FlyInCntPortions, Notes
141         rOrig.Width( rCMS.bRealWidth && rPor.Width() ? rPor.Width() : 1 );
142     }
143 }
144 
145 // --> OD 2010-05-05 #i111284#
146 namespace {
AreListLevelIndentsApplicableAndLabelAlignmentActive(const SwTxtNode & rTxtNode)147     bool AreListLevelIndentsApplicableAndLabelAlignmentActive( const SwTxtNode& rTxtNode )
148     {
149         bool bRet( false );
150 
151         if ( rTxtNode.AreListLevelIndentsApplicable() )
152         {
153             const SwNumFmt& rNumFmt =
154                     rTxtNode.GetNumRule()->Get( static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()) );
155             if ( rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
156             {
157                 bRet = true;
158             }
159         }
160 
161         return bRet;
162     }
163 } // end of anonymous namespace
164 // <--
165 
166 /*************************************************************************
167  *				  SwTxtMargin::CtorInitTxtMargin()
168  *************************************************************************/
CtorInitTxtMargin(SwTxtFrm * pNewFrm,SwTxtSizeInfo * pNewInf)169 void SwTxtMargin::CtorInitTxtMargin( SwTxtFrm *pNewFrm, SwTxtSizeInfo *pNewInf )
170 {
171 	CtorInitTxtIter( pNewFrm, pNewInf );
172 
173 	pInf = pNewInf;
174 	GetInfo().SetFont( GetFnt() );
175 	const SwTxtNode *pNode = pFrm->GetTxtNode();
176 
177     const SvxLRSpaceItem &rSpace = pFrm->GetTxtNode()->GetSwAttrSet().GetLRSpace();
178     // --> OD 2009-09-08 #i95907#, #b6879723#
179     // --> OD 2010-05-05 #i111284#
180     const bool bListLevelIndentsApplicableAndLabelAlignmentActive(
181         AreListLevelIndentsApplicableAndLabelAlignmentActive( *(pFrm->GetTxtNode()) ) );
182     // <--
183 
184     //
185     // Carefully adjust the text formatting ranges.
186     //
187     // This whole area desperately needs some rework. There are
188     // quite a couple of values that need to be considered:
189     // 1. paragraph indent
190     // 2. paragraph first line indent
191     // 3. numbering indent
192     // 4. numbering spacing to text
193     // 5. paragraph border
194     // Note: These values have already been used during calculation
195     // of the printing area of the paragraph.
196     const int nLMWithNum = pNode->GetLeftMarginWithNum( sal_True );
197     if ( pFrm->IsRightToLeft() )
198     {
199         // --> OD 2008-01-23 #newlistlevelattrs#
200         // this calculation is identical this the calculation for L2R layout - see below
201         nLeft = pFrm->Frm().Left() +
202                 pFrm->Prt().Left() +
203                 nLMWithNum -
204                 pNode->GetLeftMarginWithNum( sal_False ) -
205                 // --> OD 2009-09-08 #i95907#, #b6879723#
206                 // --> OD 2010-05-05 #i111284#
207 //                rSpace.GetLeft() +
208 //                rSpace.GetTxtLeft();
209                 ( bListLevelIndentsApplicableAndLabelAlignmentActive
210                   ? 0
211                   : ( rSpace.GetLeft() - rSpace.GetTxtLeft() ) );
212                 // <--
213     }
214     else
215     {
216         // --> OD 2009-09-08 #i95907#, #b6879723#
217         // --> OD 2010-05-05 #i111284#
218 //        if ( !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
219         if ( bListLevelIndentsApplicableAndLabelAlignmentActive ||
220              !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
221         // <--
222         {
223             // this calculation is identical this the calculation for R2L layout - see above
224             nLeft = pFrm->Frm().Left() +
225                     pFrm->Prt().Left() +
226                     nLMWithNum -
227                     pNode->GetLeftMarginWithNum( sal_False ) -
228                     // --> OD 2009-09-08 #i95907#, #b6879723#
229                     // --> OD 2010-05-05 #i111284#
230 //                    rSpace.GetLeft() +
231 //                    rSpace.GetTxtLeft();
232                     ( bListLevelIndentsApplicableAndLabelAlignmentActive
233                       ? 0
234                       : ( rSpace.GetLeft() - rSpace.GetTxtLeft() ) );
235                     // <--
236         }
237         else
238         {
239             nLeft = pFrm->Frm().Left() +
240                     Max( long( rSpace.GetTxtLeft() + nLMWithNum ),
241                          pFrm->Prt().Left() );
242         }
243     }
244 
245     nRight = pFrm->Frm().Left() + pFrm->Prt().Left() + pFrm->Prt().Width();
246 
247 	if( nLeft >= nRight &&
248          // --> FME 2005-08-10 #i53066# Omit adjustment of nLeft for numbered
249          // paras inside cells inside new documents:
250         ( pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) ||
251           !pFrm->IsInTab() ||
252           !nLMWithNum ) )
253          // <--
254     {
255 		nLeft = pFrm->Prt().Left() + pFrm->Frm().Left();
256 	    if( nLeft >= nRight )   // z.B. bei grossen Absatzeinzuegen in schmalen Tabellenspalten
257 		    nRight = nLeft + 1; // einen goennen wir uns immer
258     }
259 
260 	if( pFrm->IsFollow() && pFrm->GetOfst() )
261 		nFirst = nLeft;
262 	else
263 	{
264         short nFLOfst = 0;
265         long nFirstLineOfs = 0;
266 		if( !pNode->GetFirstLineOfsWithNum( nFLOfst ) &&
267 			rSpace.IsAutoFirst() )
268 		{
269 			nFirstLineOfs = GetFnt()->GetSize( GetFnt()->GetActual() ).Height();
270 			const SvxLineSpacingItem *pSpace = aLineInf.GetLineSpacing();
271 			if( pSpace )
272 			{
273 				switch( pSpace->GetLineSpaceRule() )
274 				{
275 					case SVX_LINE_SPACE_AUTO:
276 					break;
277 					case SVX_LINE_SPACE_MIN:
278 					{
279 						if( nFirstLineOfs < KSHORT( pSpace->GetLineHeight() ) )
280 							nFirstLineOfs = pSpace->GetLineHeight();
281 						break;
282 					}
283 					case SVX_LINE_SPACE_FIX:
284 						nFirstLineOfs = pSpace->GetLineHeight();
285 					break;
286 					default: ASSERT( sal_False, ": unknown LineSpaceRule" );
287 				}
288 				switch( pSpace->GetInterLineSpaceRule() )
289 				{
290 					case SVX_INTER_LINE_SPACE_OFF:
291 					break;
292 					case SVX_INTER_LINE_SPACE_PROP:
293 					{
294 						long nTmp = pSpace->GetPropLineSpace();
295 						// 50% ist das Minimum, bei 0% schalten wir auf
296 						// den Defaultwert 100% um ...
297 						if( nTmp < 50 )
298 							nTmp = nTmp ? 50 : 100;
299 
300 						nTmp *= nFirstLineOfs;
301 						nTmp /= 100;
302 						if( !nTmp )
303 							++nTmp;
304 						nFirstLineOfs = (KSHORT)nTmp;
305 						break;
306 					}
307 					case SVX_INTER_LINE_SPACE_FIX:
308 					{
309 						nFirstLineOfs += pSpace->GetInterLineSpace();
310 						break;
311 					}
312 					default: ASSERT( sal_False, ": unknown InterLineSpaceRule" );
313 				}
314 			}
315 		}
316 		else
317 			nFirstLineOfs = nFLOfst;
318 
319         // --> OD 2009-09-08 #i95907#, #b6879723#
320         // --> OD 2010-05-05 #i111284#
321 //        if ( pFrm->IsRightToLeft() ||
322 //             !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
323         if ( pFrm->IsRightToLeft() ||
324              bListLevelIndentsApplicableAndLabelAlignmentActive ||
325              !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
326         // <--
327         {
328             nFirst = nLeft + nFirstLineOfs;
329         }
330         else
331         {
332       	    nFirst = pFrm->Frm().Left() +
333                      Max( rSpace.GetTxtLeft() + nLMWithNum+ nFirstLineOfs,
334                           pFrm->Prt().Left() );
335         }
336 
337         // --> OD 2008-01-31 #newlistlevelattrs#
338         // Note: <SwTxtFrm::GetAdditionalFirstLineOffset()> returns a negative
339         //       value for the new list label postion and space mode LABEL_ALIGNMENT
340         //       and label alignment CENTER and RIGHT in L2R layout respectively
341         //       label alignment LEFT and CENTER in R2L layout
342         nFirst += pFrm->GetAdditionalFirstLineOffset();
343         // <--
344 
345 		if( nFirst >= nRight )
346 			nFirst = nRight - 1;
347 	}
348     const SvxAdjustItem& rAdjust = pFrm->GetTxtNode()->GetSwAttrSet().GetAdjust();
349 	nAdjust = static_cast<sal_uInt16>(rAdjust.GetAdjust());
350 
351     // left is left and right is right
352     if ( pFrm->IsRightToLeft() )
353     {
354         if ( SVX_ADJUST_LEFT == nAdjust )
355             nAdjust = SVX_ADJUST_RIGHT;
356         else if ( SVX_ADJUST_RIGHT == nAdjust )
357             nAdjust = SVX_ADJUST_LEFT;
358     }
359 
360 	bOneBlock = rAdjust.GetOneWord() == SVX_ADJUST_BLOCK;
361 	bLastBlock = rAdjust.GetLastBlock() == SVX_ADJUST_BLOCK;
362 	bLastCenter = rAdjust.GetLastBlock() == SVX_ADJUST_CENTER;
363 
364     // --> OD 2008-07-01 #i91133#
365     mnTabLeft = pNode->GetLeftMarginForTabCalculation();
366     // <--
367 
368 #if OSL_DEBUG_LEVEL > 1
369 	static sal_Bool bOne = sal_False;
370 	static sal_Bool bLast = sal_False;
371 	static sal_Bool bCenter = sal_False;
372 	bOneBlock |= bOne;
373 	bLastBlock |= bLast;
374 	bLastCenter |= bCenter;
375 #endif
376 	DropInit();
377 }
378 
379 /*************************************************************************
380  *				  SwTxtMargin::DropInit()
381  *************************************************************************/
DropInit()382 void SwTxtMargin::DropInit()
383 {
384 	nDropLeft = nDropLines = nDropHeight = nDropDescent = 0;
385 	const SwParaPortion *pPara = GetInfo().GetParaPortion();
386 	if( pPara )
387 	{
388 		const SwDropPortion *pPorDrop = pPara->FindDropPortion();
389 		if ( pPorDrop )
390 		{
391 			nDropLeft = pPorDrop->GetDropLeft();
392 			nDropLines = pPorDrop->GetLines();
393 			nDropHeight = pPorDrop->GetDropHeight();
394 			nDropDescent = pPorDrop->GetDropDescent();
395 		}
396 	}
397 }
398 
399 /*************************************************************************
400  *				  SwTxtMargin::GetLineStart()
401  *************************************************************************/
402 
403 // Unter Beruecksichtigung des Erstzeileneinzuges und der angebenen Breite.
GetLineStart() const404 SwTwips SwTxtMargin::GetLineStart() const
405 {
406 	SwTwips nRet = GetLeftMargin();
407 	if( GetAdjust() != SVX_ADJUST_LEFT &&
408 		!pCurr->GetFirstPortion()->IsMarginPortion() )
409 	{
410 		// Wenn die erste Portion ein Margin ist, dann wird das
411 		// Adjustment durch die Portions ausgedrueckt.
412 		if( GetAdjust() == SVX_ADJUST_RIGHT )
413 			nRet = Right() - CurrWidth();
414 		else if( GetAdjust() == SVX_ADJUST_CENTER )
415 			nRet += (GetLineWidth() - CurrWidth()) / 2;
416 	}
417 	return nRet;
418 }
419 
420 /*************************************************************************
421  *						SwTxtCursor::CtorInitTxtCursor()
422  *************************************************************************/
CtorInitTxtCursor(SwTxtFrm * pNewFrm,SwTxtSizeInfo * pNewInf)423 void SwTxtCursor::CtorInitTxtCursor( SwTxtFrm *pNewFrm, SwTxtSizeInfo *pNewInf )
424 {
425 	CtorInitTxtMargin( pNewFrm, pNewInf );
426 	// 6096: Vorsicht, die Iteratoren sind abgeleitet!
427 	// GetInfo().SetOut( GetInfo().GetWin() );
428 }
429 
430 /*************************************************************************
431  *						SwTxtCursor::GetEndCharRect()
432  *************************************************************************/
433 
434 // 1170: Antikbug: Shift-Ende vergisst das letzte Zeichen ...
435 
GetEndCharRect(SwRect * pOrig,const xub_StrLen nOfst,SwCrsrMoveState * pCMS,const long nMax)436 sal_Bool SwTxtCursor::GetEndCharRect( SwRect* pOrig, const xub_StrLen nOfst,
437 								  SwCrsrMoveState* pCMS, const long nMax )
438 {
439 	// 1170: Mehrdeutigkeit von Dokumentpositionen
440 	bRightMargin = sal_True;
441 	CharCrsrToLine(nOfst);
442 
443 	// Etwas verdreht: nOfst bezeichnet die Position hinter dem letzten
444 	// Zeichen der letzten Zeile == Position vor dem ersten Zeichen der
445 	// Zeile in der wir gerade stehen:
446 	if( nOfst != GetStart() || !pCurr->GetLen() )
447 	{
448 		// 8810: Masterzeile RightMargin, danach LeftMargin
449 		const sal_Bool bRet = GetCharRect( pOrig, nOfst, pCMS, nMax );
450 		bRightMargin = nOfst >= GetEnd() && nOfst < GetInfo().GetTxt().Len();
451 		return bRet;
452 	}
453 
454 	if( !GetPrev() || !GetPrev()->GetLen() || !PrevLine() )
455 		return GetCharRect( pOrig, nOfst, pCMS, nMax );
456 
457 	// Adjustierung ggf. nachholen
458 	GetAdjusted();
459 
460 	KSHORT nX = 0;
461 	KSHORT nLast = 0;
462 	SwLinePortion *pPor = pCurr->GetFirstPortion();
463 
464 	KSHORT nTmpHeight, nTmpAscent;
465 	CalcAscentAndHeight( nTmpAscent, nTmpHeight );
466 	KSHORT nPorHeight = nTmpHeight;
467 	KSHORT nPorAscent = nTmpAscent;
468 
469 	// Die letzte Text/EndPortion der Zeile suchen
470 	while( pPor )
471 	{
472 		nX = nX + pPor->Width();
473 		if( pPor->InTxtGrp() || ( pPor->GetLen() && !pPor->IsFlyPortion()
474 			&& !pPor->IsHolePortion() ) || pPor->IsBreakPortion() )
475 		{
476 			nLast = nX;
477 			nPorHeight = pPor->Height();
478 			nPorAscent = pPor->GetAscent();
479 		}
480 		pPor = pPor->GetPortion();
481 	}
482 
483 	const Size aCharSize( 1, nTmpHeight );
484 	pOrig->Pos( GetTopLeft() );
485 	pOrig->SSize( aCharSize );
486 	pOrig->Pos().X() += nLast;
487 	const SwTwips nTmpRight = Right() - 1;
488 	if( pOrig->Left() > nTmpRight )
489 		pOrig->Pos().X() = nTmpRight;
490 
491 	if ( pCMS && pCMS->bRealHeight )
492 	{
493 		if ( nTmpAscent > nPorAscent )
494 			pCMS->aRealHeight.X() = nTmpAscent - nPorAscent;
495 		else
496 			pCMS->aRealHeight.X() = 0;
497 		ASSERT( nPorHeight, "GetCharRect: Missing Portion-Height" );
498 		pCMS->aRealHeight.Y() = nPorHeight;
499 	}
500 
501 	return sal_True;
502 }
503 
504 /*************************************************************************
505  * void	SwTxtCursor::_GetCharRect(..)
506  * internal function, called by SwTxtCursor::GetCharRect() to calculate
507  * the relative character position in the current line.
508  * pOrig referes to x and y coordinates, width and height of the cursor
509  * pCMS is used for restricting the cursor, if there are different font
510  * heights in one line ( first value = offset to y of pOrig, second
511  * value = real height of (shortened) cursor
512  *************************************************************************/
513 
_GetCharRect(SwRect * pOrig,const xub_StrLen nOfst,SwCrsrMoveState * pCMS)514 void SwTxtCursor::_GetCharRect( SwRect* pOrig, const xub_StrLen nOfst,
515     SwCrsrMoveState* pCMS )
516 {
517 	const XubString &rText = GetInfo().GetTxt();
518 	SwTxtSizeInfo aInf( GetInfo(), rText, nStart );
519 	if( GetPropFont() )
520 		aInf.GetFont()->SetProportion( GetPropFont() );
521 	KSHORT nTmpAscent, nTmpHeight;	// Zeilenhoehe
522 	CalcAscentAndHeight( nTmpAscent, nTmpHeight );
523 	const Size	aCharSize( 1, nTmpHeight );
524 	const Point aCharPos;
525 	pOrig->Pos( aCharPos );
526 	pOrig->SSize( aCharSize );
527 
528     // If we are looking for a position inside a field which covers
529     // more than one line we may not skip any "empty portions" at the
530     // beginning of a line
531     const sal_Bool bInsideFirstField = pCMS && pCMS->pSpecialPos &&
532                                        ( pCMS->pSpecialPos->nLineOfst ||
533                                          SP_EXTEND_RANGE_BEFORE ==
534                                          pCMS->pSpecialPos->nExtendRange );
535 
536 	sal_Bool bWidth = pCMS && pCMS->bRealWidth;
537 	if( !pCurr->GetLen() && !pCurr->Width() )
538 	{
539 		if ( pCMS && pCMS->bRealHeight )
540 		{
541 			pCMS->aRealHeight.X() = 0;
542 			pCMS->aRealHeight.Y() = nTmpHeight;
543 		}
544 	}
545 	else
546 	{
547 		KSHORT nPorHeight = nTmpHeight;
548 		KSHORT nPorAscent = nTmpAscent;
549 		SwTwips nX = 0;
550         SwTwips nTmpFirst = 0;
551 		SwLinePortion *pPor = pCurr->GetFirstPortion();
552         SwBidiPortion* pLastBidiPor = 0;
553 		SwTwips nLastBidiPorWidth = 0;
554         SvUShorts* pKanaComp = pCurr->GetpKanaComp();
555         MSHORT nSpaceIdx = 0;
556         MSHORT nKanaIdx = 0;
557         long nSpaceAdd = pCurr->IsSpaceAdd() ? pCurr->GetLLSpaceAdd( 0 ) : 0;
558 
559         sal_Bool bNoTxt = sal_True;
560 
561 		// Zuerst werden alle Portions ohne Len am Zeilenanfang uebersprungen.
562 		// Ausnahme bilden die fiesen Spezialportions aus WhichFirstPortion:
563 		// Num, ErgoSum, FtnNum, FeldReste
564 		// 8477: aber auch die einzige Textportion einer leeren Zeile mit
565 		// Right/Center-Adjustment! Also nicht nur pPor->GetExpandPortion() ...
566         while( pPor && !pPor->GetLen() && ! bInsideFirstField )
567 		{
568 			nX += pPor->Width();
569             if ( pPor->InSpaceGrp() && nSpaceAdd )
570 				nX += pPor->CalcSpacing( nSpaceAdd, aInf );
571 			if( bNoTxt )
572                 nTmpFirst = nX;
573 			// 8670: EndPortions zaehlen hier einmal als TxtPortions.
574             // --> OD 2008-01-28 #newlistlevelattrs#
575 //            if( pPor->InTxtGrp() || pPor->IsBreakPortion() )
576             if( pPor->InTxtGrp() || pPor->IsBreakPortion() || pPor->InTabGrp() )
577             // <--
578 			{
579 				bNoTxt = sal_False;
580 				nTmpFirst = nX;
581 			}
582             if( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->HasTabulator() )
583 			{
584                 if ( pCurr->IsSpaceAdd() )
585                 {
586                     if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
587                         nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
588                     else
589                         nSpaceAdd = 0;
590                 }
591 
592                 if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() )
593                     ++nKanaIdx;
594 			}
595 			if( pPor->InFixMargGrp() )
596 			{
597 				if( pPor->IsMarginPortion() )
598 					bNoTxt = sal_False;
599                 else
600                 {
601                     // fix margin portion => next SpaceAdd, KanaComp value
602                     if ( pCurr->IsSpaceAdd() )
603                     {
604                         if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
605                             nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
606                         else
607                             nSpaceAdd = 0;
608                     }
609 
610                     if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() )
611                         ++nKanaIdx;
612                 }
613 			}
614 			pPor = pPor->GetPortion();
615 		}
616 
617 		if( !pPor )
618 		{
619             // Es sind nur Spezialportions unterwegs.
620             nX = nTmpFirst;
621 		}
622 		else
623 		{
624             if( !pPor->IsMarginPortion() && !pPor->IsPostItsPortion() &&
625 				(!pPor->InFldGrp() || pPor->GetAscent() ) )
626 			{
627 				nPorHeight = pPor->Height();
628 				nPorAscent = pPor->GetAscent();
629 			}
630 			while( pPor && !pPor->IsBreakPortion() && ( aInf.GetIdx() < nOfst ||
631                    ( bWidth && ( pPor->IsKernPortion() || pPor->IsMultiPortion() ) ) ) )
632 			{
633 				if( !pPor->IsMarginPortion() && !pPor->IsPostItsPortion() &&
634 					(!pPor->InFldGrp() || pPor->GetAscent() ) )
635 				{
636 					nPorHeight = pPor->Height();
637 					nPorAscent = pPor->GetAscent();
638 				}
639 
640                 // If we are behind the portion, we add the portion width to
641                 // nX. Special case: nOfst = aInf.GetIdx() + pPor->GetLen().
642                 // For common portions (including BidiPortions) we want to add
643                 // the portion width to nX. For MultiPortions, nExtra = 0,
644                 // therefore we go to the 'else' branch and start a recursion.
645                 const sal_uInt8 nExtra = pPor->IsMultiPortion() &&
646                                     ! ((SwMultiPortion*)pPor)->IsBidi() &&
647                                     ! bWidth ? 0 : 1;
648                 if ( aInf.GetIdx() + pPor->GetLen() < nOfst + nExtra )
649 				{
650                     if ( pPor->InSpaceGrp() && nSpaceAdd )
651                         nX += pPor->PrtWidth() +
652                               pPor->CalcSpacing( nSpaceAdd, aInf );
653                     else
654 					{
655                         if( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() )
656 						{
657                             // update to current SpaceAdd, KanaComp values
658                             if ( pCurr->IsSpaceAdd() )
659                             {
660                                 if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
661                                     nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
662                                 else
663                                     nSpaceAdd = 0;
664                             }
665 
666                             if ( pKanaComp &&
667                                 ( nKanaIdx + 1 ) < pKanaComp->Count()
668                                 )
669                                 ++nKanaIdx;
670                         }
671 						if ( !pPor->IsFlyPortion() || ( pPor->GetPortion() &&
672 								!pPor->GetPortion()->IsMarginPortion() ) )
673 							nX += pPor->PrtWidth();
674 					}
675                     if( pPor->IsMultiPortion() )
676                     {
677                         if ( ((SwMultiPortion*)pPor)->HasTabulator() )
678                         {
679                             if ( pCurr->IsSpaceAdd() )
680                             {
681                                 if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
682                                     nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
683                                 else
684                                     nSpaceAdd = 0;
685                             }
686 
687                             if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() )
688                                 ++nKanaIdx;
689                         }
690 
691                         // if we are right behind a BidiPortion, we have to
692                         // hold a pointer to the BidiPortion in order to
693                         // find the correct cursor position, depending on the
694                         // cursor level
695                         if ( ((SwMultiPortion*)pPor)->IsBidi() &&
696                              aInf.GetIdx() + pPor->GetLen() == nOfst )
697 						{
698                              pLastBidiPor = (SwBidiPortion*)pPor;
699                              nLastBidiPorWidth = pLastBidiPor->Width() +
700                                                  pLastBidiPor->CalcSpacing( nSpaceAdd, aInf );;
701                         }
702                     }
703 
704 					aInf.SetIdx( aInf.GetIdx() + pPor->GetLen() );
705                     pPor = pPor->GetPortion();
706 				}
707 				else
708 				{
709 					if( pPor->IsMultiPortion() )
710 					{
711                         nTmpAscent = AdjustBaseLine( *pCurr, pPor );
712                         GetInfo().SetMulti( sal_True );
713                         pOrig->Pos().Y() += nTmpAscent - nPorAscent;
714 
715                         if( pCMS && pCMS->b2Lines )
716 						{
717                             sal_Bool bRecursion = sal_True;
718                             if ( ! pCMS->p2Lines )
719                             {
720                                 pCMS->p2Lines = new Sw2LinesPos;
721                                 pCMS->p2Lines->aLine = SwRect(aCharPos, aCharSize);
722                                 bRecursion = sal_False;
723                             }
724 
725 							if( ((SwMultiPortion*)pPor)->HasRotation() )
726 							{
727 								if( ((SwMultiPortion*)pPor)->IsRevers() )
728                                     pCMS->p2Lines->nMultiType = MT_ROT_270;
729 								else
730                                     pCMS->p2Lines->nMultiType = MT_ROT_90;
731 							}
732 							else if( ((SwMultiPortion*)pPor)->IsDouble() )
733                                 pCMS->p2Lines->nMultiType = MT_TWOLINE;
734                             else if( ((SwMultiPortion*)pPor)->IsBidi() )
735                                 pCMS->p2Lines->nMultiType = MT_BIDI;
736 							else
737                                 pCMS->p2Lines->nMultiType = MT_RUBY;
738 
739                             SwTwips nTmpWidth = pPor->Width();
740 							if( nSpaceAdd )
741 								nTmpWidth += pPor->CalcSpacing(nSpaceAdd, aInf);
742 
743                             SwRect aRect( Point(aCharPos.X() + nX, pOrig->Top() ),
744                                           Size( nTmpWidth, pPor->Height() ) );
745 
746                             if ( ! bRecursion )
747                                 pCMS->p2Lines->aPortion = aRect;
748                             else
749                                 pCMS->p2Lines->aPortion2 = aRect;
750 						}
751 
752 						// In a multi-portion we use GetCharRect()-function
753                         // recursively and must add the x-position
754 						// of the multi-portion.
755 						xub_StrLen nOldStart = nStart;
756                         SwTwips nOldY = nY;
757 						sal_uInt8 nOldProp = GetPropFont();
758 						nStart = aInf.GetIdx();
759 						SwLineLayout* pOldCurr = pCurr;
760 						pCurr = &((SwMultiPortion*)pPor)->GetRoot();
761 						if( ((SwMultiPortion*)pPor)->IsDouble() )
762 							SetPropFont( 50 );
763 
764                         GETGRID( GetTxtFrm()->FindPageFrm() )
765                         const sal_Bool bHasGrid = pGrid && GetInfo().SnapToGrid();
766                         const sal_uInt16 nRubyHeight = bHasGrid ?
767                                                    pGrid->GetRubyHeight() : 0;
768 
769                         if( nStart + pCurr->GetLen() <= nOfst && GetNext() &&
770                             ( ! ((SwMultiPortion*)pPor)->IsRuby() ||
771                                 ((SwMultiPortion*)pPor)->OnTop() ) )
772 						{
773                             sal_uInt16 nOffset;
774                             // in grid mode we may only add the height of the
775                             // ruby line if ruby line is on top
776                             if ( bHasGrid &&
777                                 ((SwMultiPortion*)pPor)->IsRuby() &&
778                                 ((SwMultiPortion*)pPor)->OnTop() )
779                                 nOffset = nRubyHeight;
780                             else
781                                 nOffset = GetLineHeight();
782 
783                             pOrig->Pos().Y() += nOffset;
784 							Next();
785 						}
786 
787 						sal_Bool bSpaceChg = ((SwMultiPortion*)pPor)->
788 												ChgSpaceAdd( pCurr, nSpaceAdd );
789 						Point aOldPos = pOrig->Pos();
790 
791                         // Ok, for ruby portions in grid mode we have to
792                         // temporarily set the inner line height to the
793                         // outer line height because that value is needed
794                         // for the adjustment inside the recursion
795                         const sal_uInt16 nOldRubyHeight = pCurr->Height();
796                         const sal_uInt16 nOldRubyRealHeight = pCurr->GetRealHeight();
797                         const sal_Bool bChgHeight =
798                                 ((SwMultiPortion*)pPor)->IsRuby() && bHasGrid;
799 
800                         if ( bChgHeight )
801                         {
802                             pCurr->Height( pOldCurr->Height() - nRubyHeight );
803                             pCurr->SetRealHeight( pOldCurr->GetRealHeight() -
804                                                   nRubyHeight );
805                         }
806 
807                         SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
808                         if ( ((SwMultiPortion*)pPor)->IsBidi() )
809                         {
810                             aLayoutModeModifier.Modify(
811                                 ((SwBidiPortion*)pPor)->GetLevel() % 2 );
812                         }
813 
814                         _GetCharRect( pOrig, nOfst, pCMS );
815 
816                         if ( bChgHeight )
817                         {
818                             pCurr->Height( nOldRubyHeight );
819                             pCurr->SetRealHeight( nOldRubyRealHeight );
820                         }
821 
822                         // if we are still in the first row of
823                         // our 2 line multiportion, we use the FirstMulti flag
824                         // to indicate this
825                         if ( ((SwMultiPortion*)pPor)->IsDouble() )
826                         {
827                             // the recursion may have damaged our font size
828                             SetPropFont( nOldProp );
829                             if ( !nOldProp )
830                                 nOldProp = 100;
831                             GetInfo().GetFont()->SetProportion( 100 );
832 
833                             if ( pCurr == &((SwMultiPortion*)pPor)->GetRoot() )
834                             {
835                                 GetInfo().SetFirstMulti( sal_True );
836 
837                                 // we want to treat a double line portion like a
838                                 // single line portion, if there is no text in
839                                 // the second line
840                                 if ( !pCurr->GetNext() ||
841                                      !pCurr->GetNext()->GetLen() )
842                                     GetInfo().SetMulti( sal_False );
843                             }
844                         }
845                         // ruby portions are treated like single line portions
846                         else if( ((SwMultiPortion*)pPor)->IsRuby() ||
847                                  ((SwMultiPortion*)pPor)->IsBidi() )
848                             GetInfo().SetMulti( sal_False );
849 
850                         // calculate cursor values
851                         if( ((SwMultiPortion*)pPor)->HasRotation() )
852 						{
853                             GetInfo().SetMulti( sal_False );
854                             long nTmp = pOrig->Width();
855 							pOrig->Width( pOrig->Height() );
856 							pOrig->Height( nTmp );
857 							nTmp = pOrig->Left() - aOldPos.X();
858 
859                             // if we travel into our rotated portion from
860                             // a line below, we have to take care, that the
861                             // y coord in pOrig is less than line height:
862                             if ( nTmp )
863                                 nTmp--;
864 
865                             pOrig->Pos().X() = nX + aOldPos.X();
866 							if( ((SwMultiPortion*)pPor)->IsRevers() )
867 								pOrig->Pos().Y() = aOldPos.Y() + nTmp;
868 							else
869 								pOrig->Pos().Y() = aOldPos.Y()
870 									+ pPor->Height() - nTmp - pOrig->Height();
871 							if ( pCMS && pCMS->bRealHeight )
872 							{
873 								pCMS->aRealHeight.Y() = -pCMS->aRealHeight.Y();
874                                 // result for rotated multi portion is not
875                                 // correct for reverse (270 degree) portions
876                                 if( ((SwMultiPortion*)pPor)->IsRevers() )
877                                 {
878                                     if ( SvxParaVertAlignItem::AUTOMATIC ==
879                                          GetLineInfo().GetVertAlign() )
880                                         // if vertical alignment is set to auto,
881                                         // we switch from base line alignment
882                                         // to centered alignment
883                                         pCMS->aRealHeight.X() =
884                                             ( pOrig->Width() +
885                                               pCMS->aRealHeight.Y() ) / 2;
886                                     else
887                                         pCMS->aRealHeight.X() =
888                                             ( pOrig->Width() -
889                                               pCMS->aRealHeight.X() +
890                                               pCMS->aRealHeight.Y() );
891                                 }
892                             }
893 						}
894 						else
895 						{
896 							pOrig->Pos().Y() += aOldPos.Y();
897                             if ( ((SwMultiPortion*)pPor)->IsBidi() )
898                             {
899                                 const SwTwips nPorWidth = pPor->Width() +
900                                                          pPor->CalcSpacing( nSpaceAdd, aInf );
901                                 const SwTwips nInsideOfst = pOrig->Pos().X();
902                                 pOrig->Pos().X() = nX + nPorWidth -
903                                                    nInsideOfst - pOrig->Width();
904                             }
905                             else
906                                 pOrig->Pos().X() += nX;
907 
908                             if( ((SwMultiPortion*)pPor)->HasBrackets() )
909 								pOrig->Pos().X() +=
910 									((SwDoubleLinePortion*)pPor)->PreWidth();
911 						}
912 
913                         if( bSpaceChg )
914 							SwDoubleLinePortion::ResetSpaceAdd( pCurr );
915 
916                         pCurr = pOldCurr;
917 						nStart = nOldStart;
918                         nY = nOldY;
919                         bPrev = sal_False;
920 
921                         return;
922 					}
923 					if ( pPor->PrtWidth() )
924 					{
925 						xub_StrLen nOldLen = pPor->GetLen();
926 						pPor->SetLen( nOfst - aInf.GetIdx() );
927 						aInf.SetLen( pPor->GetLen() );
928 						if( nX || !pPor->InNumberGrp() )
929 						{
930 							SeekAndChg( aInf );
931 							const sal_Bool bOldOnWin = aInf.OnWin();
932 							aInf.SetOnWin( sal_False ); // keine BULLETs!
933 							SwTwips nTmp = nX;
934                             aInf.SetKanaComp( pKanaComp );
935                             aInf.SetKanaIdx( nKanaIdx );
936                             nX += pPor->GetTxtSize( aInf ).Width();
937 							aInf.SetOnWin( bOldOnWin );
938 							if ( pPor->InSpaceGrp() && nSpaceAdd )
939 								nX += pPor->CalcSpacing( nSpaceAdd, aInf );
940 							if( bWidth )
941 							{
942 								pPor->SetLen( pPor->GetLen() + 1 );
943 								aInf.SetLen( pPor->GetLen() );
944 								aInf.SetOnWin( sal_False ); // keine BULLETs!
945 								nTmp += pPor->GetTxtSize( aInf ).Width();
946 								aInf.SetOnWin( bOldOnWin );
947 								if ( pPor->InSpaceGrp() && nSpaceAdd )
948 									nTmp += pPor->CalcSpacing(nSpaceAdd, aInf);
949 								pOrig->Width( nTmp - nX );
950 							}
951 						}
952 						pPor->SetLen( nOldLen );
953 					}
954 					bWidth = sal_False;
955 					break;
956 				}
957 			}
958 		}
959 
960 		if( pPor )
961 		{
962             ASSERT( !pPor->InNumberGrp() || bInsideFirstField, "Number surprise" );
963 			sal_Bool bEmptyFld = sal_False;
964 			if( pPor->InFldGrp() && pPor->GetLen() )
965 			{
966 				SwFldPortion *pTmp = (SwFldPortion*)pPor;
967 				while( pTmp->HasFollow() && !pTmp->GetExp().Len() )
968 				{
969 					KSHORT nAddX = pTmp->Width();
970 					SwLinePortion *pNext = pTmp->GetPortion();
971 					while( pNext && !pNext->InFldGrp() )
972 					{
973 						ASSERT( !pNext->GetLen(), "Where's my field follow?" );
974 						nAddX = nAddX + pNext->Width();
975 						pNext = pNext->GetPortion();
976 					}
977 					if( !pNext )
978 						break;
979 					pTmp = (SwFldPortion*)pNext;
980 					nPorHeight = pTmp->Height();
981 					nPorAscent = pTmp->GetAscent();
982 					nX += nAddX;
983 					bEmptyFld = sal_True;
984 				}
985 			}
986 			// 8513: Felder im Blocksatz, ueberspringen
987             while( pPor && !pPor->GetLen() && ! bInsideFirstField &&
988                    ( pPor->IsFlyPortion() || pPor->IsKernPortion() ||
989                      pPor->IsBlankPortion() || pPor->InTabGrp() ||
990                      ( !bEmptyFld && pPor->InFldGrp() ) ) )
991 			{
992 				if ( pPor->InSpaceGrp() && nSpaceAdd )
993 					nX += pPor->PrtWidth() +
994 						  pPor->CalcSpacing( nSpaceAdd, aInf );
995 				else
996 				{
997                     if( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() )
998 					{
999                         if ( pCurr->IsSpaceAdd() )
1000                         {
1001                             if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
1002                                 nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
1003                             else
1004                                 nSpaceAdd = 0;
1005                         }
1006 
1007                         if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() )
1008                             ++nKanaIdx;
1009 					}
1010 					if ( !pPor->IsFlyPortion() || ( pPor->GetPortion() &&
1011 							!pPor->GetPortion()->IsMarginPortion() ) )
1012 						nX += pPor->PrtWidth();
1013 				}
1014                 if( pPor->IsMultiPortion() &&
1015                     ((SwMultiPortion*)pPor)->HasTabulator() )
1016 				{
1017                     if ( pCurr->IsSpaceAdd() )
1018                     {
1019                         if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
1020                             nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
1021                         else
1022                             nSpaceAdd = 0;
1023                     }
1024 
1025                     if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->Count() )
1026                         ++nKanaIdx;
1027 				}
1028 				if( !pPor->IsFlyPortion() )
1029 				{
1030 					nPorHeight = pPor->Height();
1031 					nPorAscent = pPor->GetAscent();
1032 				}
1033 				pPor = pPor->GetPortion();
1034 			}
1035 
1036 			if( aInf.GetIdx() == nOfst && pPor && pPor->InHyphGrp() &&
1037 				pPor->GetPortion() && pPor->GetPortion()->InFixGrp() )
1038 			{
1039 				// Alle Sonderportions muessen uebersprungen werden
1040 				// Beispiel: zu-[FLY]sammen, 'u' == 19, 's' == 20; Right()
1041 				// Ohne den Ausgleich landen wir vor '-' mit dem
1042 				// Ausgleich vor 's'.
1043 				while( pPor && !pPor->GetLen() )
1044 				{
1045 					DBG_LOOP;
1046 					nX += pPor->Width();
1047 					if( !pPor->IsMarginPortion() )
1048 					{
1049 						nPorHeight = pPor->Height();
1050 						nPorAscent = pPor->GetAscent();
1051 					}
1052 					pPor = pPor->GetPortion();
1053 				}
1054 			}
1055 			if( pPor && pCMS )
1056 			{
1057 				if( pCMS->bFieldInfo &&	pPor->InFldGrp() && pPor->Width() )
1058 					pOrig->Width( pPor->Width() );
1059 				if( pPor->IsDropPortion() )
1060                 {
1061 					nPorAscent = ((SwDropPortion*)pPor)->GetDropHeight();
1062                     // The drop height is only calculated, if we have more than
1063                     // one line. Otherwise it is 0.
1064                     if ( ! nPorAscent)
1065                         nPorAscent = pPor->Height();
1066 					nPorHeight = nPorAscent;
1067 					pOrig->Height( nPorHeight +
1068 						((SwDropPortion*)pPor)->GetDropDescent() );
1069 					if( nTmpHeight < pOrig->Height() )
1070 					{
1071 						nTmpAscent = nPorAscent;
1072 						nTmpHeight = sal_uInt16( pOrig->Height() );
1073 					}
1074 				}
1075 				if( bWidth && pPor->PrtWidth() && pPor->GetLen() &&
1076 					aInf.GetIdx() == nOfst )
1077 				{
1078 					if( !pPor->IsFlyPortion() && pPor->Height() &&
1079 						pPor->GetAscent() )
1080 					{
1081 						nPorHeight = pPor->Height();
1082 						nPorAscent = pPor->GetAscent();
1083 					}
1084 					SwTwips nTmp;
1085 					if( 2 > pPor->GetLen() )
1086 					{
1087 						nTmp = pPor->Width();
1088 						if ( pPor->InSpaceGrp() && nSpaceAdd )
1089 							nTmp += pPor->CalcSpacing( nSpaceAdd, aInf );
1090 					}
1091 					else
1092 					{
1093 						const sal_Bool bOldOnWin = aInf.OnWin();
1094 						xub_StrLen nOldLen = pPor->GetLen();
1095 						pPor->SetLen( 1 );
1096 						aInf.SetLen( pPor->GetLen() );
1097 						SeekAndChg( aInf );
1098 						aInf.SetOnWin( sal_False ); // keine BULLETs!
1099                         aInf.SetKanaComp( pKanaComp );
1100                         aInf.SetKanaIdx( nKanaIdx );
1101 						nTmp = pPor->GetTxtSize( aInf ).Width();
1102 						aInf.SetOnWin( bOldOnWin );
1103 						if ( pPor->InSpaceGrp() && nSpaceAdd )
1104 							nTmp += pPor->CalcSpacing( nSpaceAdd, aInf );
1105 						pPor->SetLen( nOldLen );
1106 					}
1107 					pOrig->Width( nTmp );
1108 				}
1109 
1110                 // travel inside field portion?
1111                 if ( pCMS->pSpecialPos )
1112                 {
1113                     // apply attributes to font
1114                     Seek( nOfst );
1115                     lcl_GetCharRectInsideField( aInf, *pOrig, *pCMS, *pPor );
1116                 }
1117             }
1118         }
1119 
1120         // special case: We are at the beginning of a BidiPortion or
1121         // directly behind a BidiPortion
1122         if ( pCMS &&
1123                 ( pLastBidiPor ||
1124                 ( pPor &&
1125                   pPor->IsMultiPortion() &&
1126                   ((SwMultiPortion*)pPor)->IsBidi() ) ) )
1127         {
1128             // we determine if the cursor has to blink before or behind
1129             // the bidi portion
1130             if ( pLastBidiPor )
1131             {
1132                 const sal_uInt8 nPortionLevel = pLastBidiPor->GetLevel();
1133 
1134                 if ( pCMS->nCursorBidiLevel >= nPortionLevel )
1135                 {
1136                     // we came from inside the bidi portion, we want to blink
1137                     // behind the portion
1138                     pOrig->Pos().X() -= nLastBidiPorWidth;
1139 
1140                     // Again, there is a special case: logically behind
1141                     // the portion can actually mean that the cursor is inside
1142                     // the portion. This can happen is the last portion
1143                     // inside the bidi portion is a nested bidi portion
1144                     SwLineLayout& rLineLayout =
1145                             ((SwMultiPortion*)pLastBidiPor)->GetRoot();
1146 
1147                     const SwLinePortion *pLast = rLineLayout.FindLastPortion();
1148                     if ( pLast->IsMultiPortion() )
1149                     {
1150                         ASSERT( ((SwMultiPortion*)pLast)->IsBidi(),
1151                                  "Non-BidiPortion inside BidiPortion" )
1152                         pOrig->Pos().X() += pLast->Width() +
1153                                             pLast->CalcSpacing( nSpaceAdd, aInf );
1154                     }
1155                 }
1156             }
1157             else
1158             {
1159                 const sal_uInt8 nPortionLevel = ((SwBidiPortion*)pPor)->GetLevel();
1160 
1161                 if ( pCMS->nCursorBidiLevel >= nPortionLevel )
1162                 {
1163                     // we came from inside the bidi portion, we want to blink
1164                     // behind the portion
1165                     pOrig->Pos().X() += pPor->Width() +
1166                                         pPor->CalcSpacing( nSpaceAdd, aInf );
1167                 }
1168             }
1169         }
1170 
1171 		pOrig->Pos().X() += nX;
1172 
1173 		if ( pCMS && pCMS->bRealHeight )
1174 		{
1175             nTmpAscent = AdjustBaseLine( *pCurr, 0, nPorHeight, nPorAscent );
1176             if ( nTmpAscent > nPorAscent )
1177 				pCMS->aRealHeight.X() = nTmpAscent - nPorAscent;
1178 			else
1179 				pCMS->aRealHeight.X() = 0;
1180 			ASSERT( nPorHeight, "GetCharRect: Missing Portion-Height" );
1181 			if ( nTmpHeight > nPorHeight )
1182 				pCMS->aRealHeight.Y() = nPorHeight;
1183 			else
1184 				pCMS->aRealHeight.Y() = nTmpHeight;
1185 		}
1186 	}
1187 }
1188 
1189 /*************************************************************************
1190  *						SwTxtCursor::GetCharRect()
1191  *************************************************************************/
1192 
GetCharRect(SwRect * pOrig,const xub_StrLen nOfst,SwCrsrMoveState * pCMS,const long nMax)1193 sal_Bool SwTxtCursor::GetCharRect( SwRect* pOrig, const xub_StrLen nOfst,
1194 							   SwCrsrMoveState* pCMS, const long nMax )
1195 {
1196 	CharCrsrToLine(nOfst);
1197 
1198     // Indicates that a position inside a special portion (field, number portion)
1199     // is requested.
1200     const sal_Bool bSpecialPos = pCMS && pCMS->pSpecialPos;
1201     xub_StrLen nFindOfst = nOfst;
1202 
1203     if ( bSpecialPos )
1204     {
1205         const sal_uInt8 nExtendRange = pCMS->pSpecialPos->nExtendRange;
1206 
1207         ASSERT( ! pCMS->pSpecialPos->nLineOfst || SP_EXTEND_RANGE_BEFORE != nExtendRange,
1208                 "LineOffset AND Number Portion?" )
1209 
1210         // portions which are behind the string
1211         if ( SP_EXTEND_RANGE_BEHIND == nExtendRange )
1212             ++nFindOfst;
1213 
1214         // skip lines for fields which cover more than one line
1215         for ( sal_uInt16 i = 0; i < pCMS->pSpecialPos->nLineOfst; i++ )
1216             Next();
1217     }
1218 
1219 	// Adjustierung ggf. nachholen
1220 	GetAdjusted();
1221 
1222 	const Point aCharPos( GetTopLeft() );
1223 	sal_Bool bRet = sal_True;
1224 
1225     _GetCharRect( pOrig, nFindOfst, pCMS );
1226 
1227     const SwTwips nTmpRight = Right() - 12;
1228 
1229     pOrig->Pos().X() += aCharPos.X();
1230 	pOrig->Pos().Y() += aCharPos.Y();
1231 
1232 	if( pCMS && pCMS->b2Lines && pCMS->p2Lines )
1233 	{
1234 		pCMS->p2Lines->aLine.Pos().X() += aCharPos.X();
1235 		pCMS->p2Lines->aLine.Pos().Y() += aCharPos.Y();
1236 		pCMS->p2Lines->aPortion.Pos().X() += aCharPos.X();
1237 		pCMS->p2Lines->aPortion.Pos().Y() += aCharPos.Y();
1238 	}
1239 
1240     if( pOrig->Left() > nTmpRight )
1241         pOrig->Pos().X() = nTmpRight;
1242 
1243 	if( nMax )
1244 	{
1245         if( pOrig->Top() + pOrig->Height() > nMax )
1246 		{
1247 			if( pOrig->Top() > nMax )
1248 				pOrig->Top( nMax );
1249             pOrig->Height( nMax - pOrig->Top() );
1250 		}
1251 		if ( pCMS && pCMS->bRealHeight && pCMS->aRealHeight.Y() >= 0 )
1252 		{
1253 			long nTmp = pCMS->aRealHeight.X() + pOrig->Top();
1254 			if(	nTmp >= nMax )
1255 			{
1256 				pCMS->aRealHeight.X() = nMax - pOrig->Top();
1257 				pCMS->aRealHeight.Y() = 0;
1258 			}
1259 			else if( nTmp + pCMS->aRealHeight.Y() > nMax )
1260 				pCMS->aRealHeight.Y() = nMax - nTmp;
1261 		}
1262 	}
1263 	long nOut = pOrig->Right() - GetTxtFrm()->Frm().Right();
1264 	if( nOut > 0 )
1265 	{
1266 		if( GetTxtFrm()->Frm().Width() < GetTxtFrm()->Prt().Left()
1267 								   + GetTxtFrm()->Prt().Width() )
1268 			nOut += GetTxtFrm()->Frm().Width() - GetTxtFrm()->Prt().Left()
1269 					- GetTxtFrm()->Prt().Width();
1270 		if( nOut > 0 )
1271 			pOrig->Pos().X() -= nOut + 10;
1272 	}
1273 	return bRet;
1274 }
1275 
1276 /*************************************************************************
1277  *						SwTxtCursor::GetCrsrOfst()
1278  *
1279  * Return: Offset im String
1280  *************************************************************************/
GetCrsrOfst(SwPosition * pPos,const Point & rPoint,const MSHORT nChgNode,SwCrsrMoveState * pCMS) const1281 xub_StrLen SwTxtCursor::GetCrsrOfst( SwPosition *pPos, const Point &rPoint,
1282 					 const MSHORT nChgNode, SwCrsrMoveState* pCMS ) const
1283 {
1284 	// Adjustierung ggf. nachholen
1285 	GetAdjusted();
1286 
1287 	const XubString &rText = GetInfo().GetTxt();
1288 	xub_StrLen nOffset = 0;
1289 
1290 	// x ist der horizontale Offset innerhalb der Zeile.
1291 	SwTwips x = rPoint.X();
1292 	CONST SwTwips nLeftMargin  = GetLineStart();
1293 	SwTwips nRightMargin = GetLineEnd();
1294 	if( nRightMargin == nLeftMargin )
1295 		nRightMargin += 30;
1296 
1297 	const sal_Bool bLeftOver = x < nLeftMargin;
1298 	if( bLeftOver )
1299 		x = nLeftMargin;
1300 	const sal_Bool bRightOver = x > nRightMargin;
1301 	if( bRightOver )
1302 		x = nRightMargin;
1303 
1304 	sal_Bool bRightAllowed = pCMS && ( pCMS->eState == MV_NONE );
1305 
1306 	// Bis hierher in Dokumentkoordinaten.
1307 	x -= nLeftMargin;
1308 
1309 	KSHORT nX = KSHORT( x );
1310 
1311 	// Wenn es in der Zeile Attributwechsel gibt, den Abschnitt
1312 	// suchen, in dem nX liegt.
1313 	SwLinePortion *pPor = pCurr->GetFirstPortion();
1314 	xub_StrLen nCurrStart  = nStart;
1315 	sal_Bool bHolePortion = sal_False;
1316 	sal_Bool bLastHyph = sal_False;
1317 
1318     SvUShorts *pKanaComp = pCurr->GetpKanaComp();
1319 	xub_StrLen nOldIdx = GetInfo().GetIdx();
1320 	MSHORT nSpaceIdx = 0;
1321     MSHORT nKanaIdx = 0;
1322     long nSpaceAdd = pCurr->IsSpaceAdd() ? pCurr->GetLLSpaceAdd( 0 ) : 0;
1323     short nKanaComp = pKanaComp ? (*pKanaComp)[0] : 0;
1324 
1325 	// nWidth ist die Breite der Zeile, oder die Breite des
1326 	// Abschnitts mit dem Fontwechsel, in dem nX liegt.
1327 
1328 	KSHORT nWidth = pPor->Width();
1329     if ( pCurr->IsSpaceAdd() || pKanaComp )
1330 	{
1331 		if ( pPor->InSpaceGrp() && nSpaceAdd )
1332 		{
1333 			((SwTxtSizeInfo&)GetInfo()).SetIdx( nCurrStart );
1334 			nWidth = nWidth + sal_uInt16( pPor->CalcSpacing( nSpaceAdd, GetInfo() ) );
1335 		}
1336         if( ( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() ) ||
1337             ( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->HasTabulator() )
1338           )
1339 		{
1340             if ( pCurr->IsSpaceAdd() )
1341             {
1342                 if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
1343                     nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
1344                 else
1345                     nSpaceAdd = 0;
1346             }
1347 
1348             if( pKanaComp )
1349             {
1350                 if ( nKanaIdx + 1 < pKanaComp->Count() )
1351                     nKanaComp = (*pKanaComp)[++nKanaIdx];
1352                 else
1353                     nKanaComp = 0;
1354             }
1355 		}
1356 	}
1357 
1358     KSHORT nWidth30;
1359     if ( pPor->IsPostItsPortion() )
1360         nWidth30 = 30 + pPor->GetViewWidth( GetInfo() ) / 2;
1361     else
1362         nWidth30 = ! nWidth && pPor->GetLen() && pPor->InToxRefOrFldGrp() ?
1363                      30 :
1364                      nWidth;
1365 
1366 	while( pPor->GetPortion() && nWidth30 < nX && !pPor->IsBreakPortion() )
1367 	{
1368 		nX = nX - nWidth;
1369 		nCurrStart = nCurrStart + pPor->GetLen();
1370 		bHolePortion = pPor->IsHolePortion();
1371 		pPor = pPor->GetPortion();
1372 		nWidth = pPor->Width();
1373         if ( pCurr->IsSpaceAdd() || pKanaComp )
1374 		{
1375 			if ( pPor->InSpaceGrp() && nSpaceAdd )
1376 			{
1377 				((SwTxtSizeInfo&)GetInfo()).SetIdx( nCurrStart );
1378 				nWidth = nWidth + sal_uInt16( pPor->CalcSpacing( nSpaceAdd, GetInfo() ) );
1379 			}
1380 
1381             if( ( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() ) ||
1382                 ( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->HasTabulator() )
1383               )
1384 			{
1385                 if ( pCurr->IsSpaceAdd() )
1386                 {
1387                     if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
1388                         nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
1389                     else
1390                         nSpaceAdd = 0;
1391                 }
1392 
1393                 if ( pKanaComp )
1394                 {
1395                     if( nKanaIdx + 1 < pKanaComp->Count() )
1396                         nKanaComp = (*pKanaComp)[++nKanaIdx];
1397                     else
1398                         nKanaComp = 0;
1399                 }
1400 			}
1401 		}
1402 
1403         if ( pPor->IsPostItsPortion() )
1404             nWidth30 = 30 +  pPor->GetViewWidth( GetInfo() ) / 2;
1405         else
1406             nWidth30 = ! nWidth && pPor->GetLen() && pPor->InToxRefOrFldGrp() ?
1407                          30 :
1408                          nWidth;
1409 		if( !pPor->IsFlyPortion() && !pPor->IsMarginPortion() )
1410 			bLastHyph = pPor->InHyphGrp();
1411 	}
1412 
1413     const sal_Bool bLastPortion = (0 == pPor->GetPortion());
1414 
1415 	if( nX==nWidth )
1416 	{
1417 		SwLinePortion *pNextPor = pPor->GetPortion();
1418 		while( pNextPor && pNextPor->InFldGrp() && !pNextPor->Width() )
1419 		{
1420 			nCurrStart = nCurrStart + pPor->GetLen();
1421 			pPor = pNextPor;
1422 			if( !pPor->IsFlyPortion() && !pPor->IsMarginPortion() )
1423 				bLastHyph = pPor->InHyphGrp();
1424 			pNextPor = pPor->GetPortion();
1425 		}
1426 	}
1427 
1428 	((SwTxtSizeInfo&)GetInfo()).SetIdx( nOldIdx );
1429 
1430 	xub_StrLen nLength = pPor->GetLen();
1431 
1432 	sal_Bool bFieldInfo = pCMS && pCMS->bFieldInfo;
1433 
1434 	if( bFieldInfo && ( nWidth30 < nX || bRightOver || bLeftOver ||
1435 		( pPor->InNumberGrp() && !pPor->IsFtnNumPortion() ) ||
1436 		( pPor->IsMarginPortion() && nWidth > nX + 30 ) ) )
1437 		((SwCrsrMoveState*)pCMS)->bPosCorr = sal_True;
1438 
1439 
1440     // #i27615#
1441     if (pCMS)
1442     {
1443         if( pCMS->bInFrontOfLabel)
1444         {
1445             if (! (2 * nX < nWidth && pPor->InNumberGrp() &&
1446                    !pPor->IsFtnNumPortion()))
1447                 pCMS->bInFrontOfLabel = sal_False;
1448         }
1449     }
1450 
1451 	// 7684: Wir sind genau auf der HyphPortion angelangt und muessen dafuer
1452 	// sorgen, dass wir in dem String landen.
1453 	// 7993: Wenn die Laenge 0 ist muessen wir raus...
1454 	if( !nLength )
1455 	{
1456 		if( pCMS )
1457 		{
1458 			if( pPor->IsFlyPortion() && bFieldInfo )
1459 				((SwCrsrMoveState*)pCMS)->bPosCorr = sal_True;
1460 
1461             if (!bRightOver && nX)
1462             {
1463                 if( pPor->IsFtnNumPortion())
1464                     ((SwCrsrMoveState*)pCMS)->bFtnNoInfo = sal_True;
1465                 else if (pPor->InNumberGrp() ) // #i23726#
1466                 {
1467                     ((SwCrsrMoveState*)pCMS)->nInNumPostionOffset = nX;
1468                     ((SwCrsrMoveState*)pCMS)->bInNumPortion = sal_True;
1469                 }
1470             }
1471 		}
1472 		if( !nCurrStart )
1473 			return 0;
1474 
1475 		 // 7849, 7816: auf pPor->GetHyphPortion kann nicht verzichtet werden!
1476 		if( bHolePortion || ( !bRightAllowed && bLastHyph ) ||
1477 			( pPor->IsMarginPortion() && !pPor->GetPortion() &&
1478 			// 46598: In der letzten Zeile eines zentrierten Absatzes wollen
1479 			// wir auch mal hinter dem letzten Zeichen landen.
1480               nCurrStart < rText.Len() ) )
1481 			--nCurrStart;
1482 		else if( pPor->InFldGrp() && ((SwFldPortion*)pPor)->IsFollow()
1483 				 && nWidth > nX )
1484         {
1485 			if( bFieldInfo )
1486 				--nCurrStart;
1487 			else
1488 			{
1489 				KSHORT nHeight = pPor->Height();
1490 				if ( !nHeight || nHeight > nWidth )
1491 					nHeight = nWidth;
1492 				if( nChgNode && nWidth - nHeight/2 > nX )
1493 					--nCurrStart;
1494 			}
1495 		}
1496 		return nCurrStart;
1497 	}
1498 	if ( 1 == nLength )
1499 	{
1500 		if ( nWidth )
1501 		{
1502 			// Sonst kommen wir nicht mehr in zeichengeb. Rahmen hinein...
1503 			if( !( nChgNode && pPos && pPor->IsFlyCntPortion() ) )
1504 			{
1505 				if ( pPor->InFldGrp() ||
1506                      ( pPor->IsMultiPortion() &&
1507                        ((SwMultiPortion*)pPor)->IsBidi()  ) )
1508 				{
1509 					KSHORT nHeight = 0;
1510 					if( !bFieldInfo )
1511 					{
1512 						nHeight = pPor->Height();
1513 						if ( !nHeight || nHeight > nWidth )
1514 							nHeight = nWidth;
1515 					}
1516 
1517 					if( nWidth - nHeight/2 <= nX &&
1518                         ( ! pPor->InFldGrp() ||
1519                           !((SwFldPortion*)pPor)->HasFollow() ) )
1520                         ++nCurrStart;
1521 				}
1522                 else if ( ( !pPor->IsFlyPortion() || ( pPor->GetPortion() &&
1523 					!pPor->GetPortion()->IsMarginPortion() &&
1524                     !pPor->GetPortion()->IsHolePortion() ) )
1525                          && ( nWidth/2 < nX ) &&
1526                          ( !bFieldInfo ||
1527                             ( pPor->GetPortion() &&
1528                               pPor->GetPortion()->IsPostItsPortion() ) )
1529 						 && ( bRightAllowed || !bLastHyph ))
1530 					++nCurrStart;
1531 
1532                 // if we want to get the position inside the field, we should not return
1533                 if ( !pCMS || !pCMS->pSpecialPos )
1534 				    return nCurrStart;
1535 			}
1536 		}
1537 		else
1538 		{
1539 			if ( pPor->IsPostItsPortion() || pPor->IsBreakPortion() ||
1540 				 pPor->InToxRefGrp() )
1541 				return nCurrStart;
1542 			if ( pPor->InFldGrp() )
1543 			{
1544 				if( bRightOver && !((SwFldPortion*)pPor)->HasFollow() )
1545 					++nCurrStart;
1546 				return nCurrStart;
1547 			}
1548 		}
1549 	}
1550 
1551 	if( bLastPortion && (pCurr->GetNext() || pFrm->GetFollow() ) )
1552 		--nLength;
1553 
1554     if( nWidth > nX ||
1555       ( nWidth == nX && pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsDouble() ) )
1556 	{
1557 		if( pPor->IsMultiPortion() )
1558 		{
1559             // In a multi-portion we use GetCrsrOfst()-function recursively
1560 			SwTwips nTmpY = rPoint.Y() - pCurr->GetAscent() + pPor->GetAscent();
1561             // if we are in the first line of a double line portion, we have
1562             // to add a value to nTmpY for not staying in this line
1563             // we also want to skip the first line, if we are inside ruby
1564             if ( ( ((SwTxtSizeInfo*)pInf)->IsMulti() &&
1565                    ((SwTxtSizeInfo*)pInf)->IsFirstMulti() ) ||
1566                  ( ((SwMultiPortion*)pPor)->IsRuby() &&
1567                    ((SwMultiPortion*)pPor)->OnTop() ) )
1568                 nTmpY += ((SwMultiPortion*)pPor)->Height();
1569 
1570             // Important for cursor traveling in ruby portions:
1571             // We have to set nTmpY to 0 in order to stay in the first row
1572             // if the phonetic line is the second row
1573             if (   ((SwMultiPortion*)pPor)->IsRuby() &&
1574                  ! ((SwMultiPortion*)pPor)->OnTop() )
1575                 nTmpY = 0;
1576 
1577             SwTxtCursorSave aSave( (SwTxtCursor*)this, (SwMultiPortion*)pPor,
1578                  nTmpY, nX, nCurrStart, nSpaceAdd );
1579 
1580             SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
1581             if ( ((SwMultiPortion*)pPor)->IsBidi() )
1582             {
1583                 const sal_uInt8 nBidiLevel = ((SwBidiPortion*)pPor)->GetLevel();
1584                 aLayoutModeModifier.Modify( nBidiLevel % 2 );
1585             }
1586 
1587 			if( ((SwMultiPortion*)pPor)->HasRotation() )
1588 			{
1589 				nTmpY -= nY;
1590 				if( !((SwMultiPortion*)pPor)->IsRevers() )
1591 					nTmpY = pPor->Height() - nTmpY;
1592 				if( nTmpY < 0 )
1593 					nTmpY = 0;
1594                 nX = (KSHORT)nTmpY;
1595 			}
1596 
1597 			if( ((SwMultiPortion*)pPor)->HasBrackets() )
1598             {
1599                 sal_uInt16 nPreWidth = ((SwDoubleLinePortion*)pPor)->PreWidth();
1600                 if ( nX > nPreWidth )
1601                     nX = nX - nPreWidth;
1602                 else
1603                     nX = 0;
1604             }
1605 
1606             return GetCrsrOfst( pPos, Point( GetLineStart() + nX, rPoint.Y() ),
1607 								nChgNode, pCMS );
1608 		}
1609 		if( pPor->InTxtGrp() )
1610 		{
1611 			sal_uInt8 nOldProp;
1612 			if( GetPropFont() )
1613 			{
1614 				((SwFont*)GetFnt())->SetProportion( GetPropFont() );
1615 				nOldProp = GetFnt()->GetPropr();
1616 			}
1617 			else
1618 				nOldProp = 0;
1619 			{
1620 				SwTxtSizeInfo aSizeInf( GetInfo(), rText, nCurrStart );
1621 				((SwTxtCursor*)this)->SeekAndChg( aSizeInf );
1622                 SwTxtSlot aDiffTxt( &aSizeInf, ((SwTxtPortion*)pPor), false, false );
1623 				SwFontSave aSave( aSizeInf, pPor->IsDropPortion() ?
1624 						((SwDropPortion*)pPor)->GetFnt() : NULL );
1625 
1626                 SwParaPortion* pPara = (SwParaPortion*)GetInfo().GetParaPortion();
1627                 ASSERT( pPara, "No paragraph!" );
1628 
1629                 SwDrawTextInfo aDrawInf( aSizeInf.GetVsh(),
1630                                          *aSizeInf.GetOut(),
1631                                          &pPara->GetScriptInfo(),
1632                                          aSizeInf.GetTxt(),
1633                                          aSizeInf.GetIdx(),
1634                                          pPor->GetLen() );
1635                 aDrawInf.SetOfst( nX );
1636 
1637                 if ( nSpaceAdd )
1638                 {
1639                     xub_StrLen nCharCnt;
1640                     // --> FME 2005-04-04 #i41860# Thai justified alignemt needs some
1641                     // additional information:
1642                     aDrawInf.SetNumberOfBlanks( pPor->InTxtGrp() ?
1643                                                 static_cast<const SwTxtPortion*>(pPor)->GetSpaceCnt( aSizeInf, nCharCnt ) :
1644                                                 0 );
1645                     // <--
1646                 }
1647 
1648                 if ( pPor->InFldGrp() && pCMS && pCMS->pSpecialPos )
1649                     aDrawInf.SetLen( STRING_LEN ); // SMARTTAGS
1650 
1651                 aDrawInf.SetSpace( nSpaceAdd );
1652                 aDrawInf.SetFont( aSizeInf.GetFont() );
1653                 aDrawInf.SetFrm( pFrm );
1654                 aDrawInf.SetSnapToGrid( aSizeInf.SnapToGrid() );
1655                 aDrawInf.SetPosMatchesBounds( pCMS && pCMS->bPosMatchesBounds );
1656 
1657                 if ( SW_CJK == aSizeInf.GetFont()->GetActual() &&
1658                      pPara->GetScriptInfo().CountCompChg() &&
1659                     ! pPor->InFldGrp() )
1660                     aDrawInf.SetKanaComp( nKanaComp );
1661 
1662                 nLength = aSizeInf.GetFont()->_GetCrsrOfst( aDrawInf );
1663 
1664                 // get position inside field portion?
1665                 if ( pPor->InFldGrp() && pCMS && pCMS->pSpecialPos )
1666                 {
1667                     pCMS->pSpecialPos->nCharOfst = nLength;
1668                     nLength = 0; // SMARTTAGS
1669                 }
1670 
1671                 // set cursor bidi level
1672                 if ( pCMS )
1673                     ((SwCrsrMoveState*)pCMS)->nCursorBidiLevel =
1674                         aDrawInf.GetCursorBidiLevel();
1675 
1676                 if( bFieldInfo && nLength == pPor->GetLen() &&
1677                     ( ! pPor->GetPortion() ||
1678                       ! pPor->GetPortion()->IsPostItsPortion() ) )
1679 					--nLength;
1680 			}
1681 			if( nOldProp )
1682 				((SwFont*)GetFnt())->SetProportion( nOldProp );
1683 		}
1684 		else
1685 		{
1686 			if( nChgNode && pPos && pPor->IsFlyCntPortion()
1687 				&& !( (SwFlyCntPortion*)pPor )->IsDraw() )
1688 			{
1689 				// JP 24.11.94: liegt die Pos nicht im Fly, dann
1690 				// 				darf nicht mit STRING_LEN returnt werden!
1691 				//				(BugId: 9692 + Aenderung in feshview)
1692 				SwFlyInCntFrm *pTmp = ( (SwFlyCntPortion*)pPor )->GetFlyFrm();
1693 				sal_Bool bChgNode = 1 < nChgNode;
1694 				if( !bChgNode )
1695 				{
1696 					SwFrm* pLower = pTmp->GetLower();
1697 					if( pLower && (pLower->IsTxtFrm() || pLower->IsLayoutFrm()) )
1698 						bChgNode = sal_True;
1699 				}
1700                 Point aTmpPoint( rPoint );
1701 
1702                 if ( pFrm->IsRightToLeft() )
1703                     pFrm->SwitchLTRtoRTL( aTmpPoint );
1704 
1705                 if ( pFrm->IsVertical() )
1706                     pFrm->SwitchHorizontalToVertical( aTmpPoint );
1707 
1708                 if( bChgNode && pTmp->Frm().IsInside( aTmpPoint ) &&
1709 					!( pTmp->IsProtected() ) )
1710 				{
1711 					nLength = ((SwFlyCntPortion*)pPor)->
1712                               GetFlyCrsrOfst( nX, aTmpPoint, pPos, pCMS );
1713 					// Sobald der Frame gewechselt wird, muessen wir aufpassen, dass
1714 					// unser Font wieder im OutputDevice steht.
1715 					// vgl. Paint und new SwFlyCntPortion !
1716 					((SwTxtSizeInfo*)pInf)->SelectFont();
1717 
1718 					// 6776: Das pIter->GetCrsrOfst returnt
1719 					// aus einer Verschachtelung mit STRING_LEN.
1720 					return STRING_LEN;
1721 				}
1722 			}
1723 			else
1724 				nLength = pPor->GetCrsrOfst( nX );
1725 		}
1726 	}
1727 	nOffset = nCurrStart + nLength;
1728 
1729 	// 7684: Wir sind vor der HyphPortion angelangt und muessen dafuer
1730 	// sorgen, dass wir in dem String landen.
1731 	// Bei Zeilenenden vor FlyFrms muessen ebenso behandelt werden.
1732 
1733 	if( nOffset && pPor->GetLen() == nLength && pPor->GetPortion() &&
1734 		!pPor->GetPortion()->GetLen() && pPor->GetPortion()->InHyphGrp() )
1735 		--nOffset;
1736 
1737 	return nOffset;
1738 }
1739 
1740 /** Looks for text portions which are inside the given rectangle
1741 
1742     For a rectangular text selection every text portions which is inside the given
1743     rectangle has to be put into the SwSelectionList as SwPaM
1744     From these SwPaM the SwCursors will be created.
1745 
1746     @param rSelList
1747     The container for the overlapped text portions
1748 
1749     @param rRect
1750     A rectangle in document coordinates, text inside this rectangle has to be
1751     selected.
1752 
1753     @return [ true, false ]
1754     true if any overlapping text portion has been found and put into list
1755     false if no portion overlaps, the list has been unchanged
1756 */
FillSelection(SwSelectionList & rSelList,const SwRect & rRect) const1757 bool SwTxtFrm::FillSelection( SwSelectionList& rSelList, const SwRect& rRect ) const
1758 {
1759     bool bRet = false;
1760     // PaintArea() instead Frm() for negative indents
1761     SwRect aTmpFrm( PaintArea() );
1762     if( !rRect.IsOver( aTmpFrm ) )
1763         return false;
1764     if( rSelList.checkContext( this ) )
1765     {
1766         SwRect aRect( aTmpFrm );
1767         aRect.Intersection( rRect );
1768         // rNode without const to create SwPaMs
1769         SwCntntNode &rNode = const_cast<SwCntntNode&>( *GetNode() );
1770         SwNodeIndex aIdx( rNode );
1771         SwPosition aPosL( aIdx, SwIndex( &rNode, 0 ) );
1772         if( IsEmpty() )
1773         {
1774             SwPaM *pPam = new SwPaM( aPosL, aPosL );
1775             rSelList.insertPaM( pPam );
1776         }
1777         else if( aRect.HasArea() )
1778         {
1779             xub_StrLen nOld = STRING_LEN;
1780             SwPosition aPosR( aPosL );
1781             Point aPoint;
1782             SwTxtInfo aInf( const_cast<SwTxtFrm*>(this) );
1783             SwTxtIter aLine( const_cast<SwTxtFrm*>(this), &aInf );
1784             // We have to care for top-to-bottom layout, where right becomes top etc.
1785             SWRECTFN( this )
1786             SwTwips nTop = (aRect.*fnRect->fnGetTop)();
1787             SwTwips nBottom = (aRect.*fnRect->fnGetBottom)();
1788             SwTwips nLeft = (aRect.*fnRect->fnGetLeft)();
1789             SwTwips nRight = (aRect.*fnRect->fnGetRight)();
1790             SwTwips nY = aLine.Y(); // Top position of the first line
1791             SwTwips nLastY = nY;
1792             while( nY < nTop && aLine.Next() ) // line above rectangle
1793             {
1794                 nLastY = nY;
1795                 nY = aLine.Y();
1796             }
1797             bool bLastLine = false;
1798             if( nY < nTop && !aLine.GetNext() )
1799             {
1800                 bLastLine = true;
1801                 nY += aLine.GetLineHeight();
1802             }
1803             do // check the lines for overlapping
1804             {
1805                 if( nLastY < nTop ) // if the last line was above rectangle
1806                     nLastY = nTop;
1807                 if( nY > nBottom ) // if the current line leaves the rectangle
1808                     nY = nBottom;
1809                 if( nY >= nLastY ) // gotcha: overlapping
1810                 {
1811                     nLastY += nY;
1812                     nLastY /= 2;
1813                     if( bVert )
1814                     {
1815                         aPoint.X() = nLastY;
1816                         aPoint.Y() = nLeft;
1817                     }
1818                     else
1819                     {
1820                         aPoint.X() = nLeft;
1821                         aPoint.Y() = nLastY;
1822                     }
1823                     // Looking for the position of the left border of the rectangle
1824                     // in this text line
1825                     SwCrsrMoveState aState( MV_UPDOWN );
1826                     if( GetCrsrOfst( &aPosL, aPoint, &aState ) )
1827                     {
1828                         if( bVert )
1829                         {
1830                             aPoint.X() = nLastY;
1831                             aPoint.Y() = nRight;
1832                         }
1833                         else
1834                         {
1835                             aPoint.X() = nRight;
1836                             aPoint.Y() = nLastY;
1837                         }
1838                         // If we get a right position and if the left position
1839                         // is not the same like the left position of the line before
1840                         // which cound happen e.g. for field portions or fly frames
1841                         // a SwPaM will be inserted with these positions
1842                         if( GetCrsrOfst( &aPosR, aPoint, &aState ) &&
1843                             nOld != aPosL.nContent.GetIndex() )
1844                         {
1845                             SwPaM *pPam = new SwPaM( aPosL, aPosR );
1846                             rSelList.insertPaM( pPam );
1847                             nOld = aPosL.nContent.GetIndex();
1848                         }
1849                     }
1850                 }
1851                 if( aLine.Next() )
1852                 {
1853                     nLastY = nY;
1854                     nY = aLine.Y();
1855                 }
1856                 else if( !bLastLine )
1857                 {
1858                     bLastLine = true;
1859                     nLastY = nY;
1860                     nY += aLine.GetLineHeight();
1861                 }
1862                 else
1863                     break;
1864             }while( nLastY < nBottom );
1865         }
1866     }
1867     if( GetDrawObjs() )
1868     {
1869         const SwSortedObjs &rObjs = *GetDrawObjs();
1870         for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
1871         {
1872             const SwAnchoredObject* pAnchoredObj = rObjs[i];
1873             if( !pAnchoredObj->ISA(SwFlyFrm) )
1874                 continue;
1875             const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pAnchoredObj);
1876             if( pFly->IsFlyInCntFrm() && pFly->FillSelection( rSelList, rRect ) )
1877                 bRet = true;
1878         }
1879     }
1880     return bRet;
1881 }
1882 
1883