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