xref: /AOO41X/main/sw/source/core/text/itrcrsr.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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  *************************************************************************/
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 {
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  *************************************************************************/
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  *************************************************************************/
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.
404 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  *************************************************************************/
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 
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 
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 
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  *************************************************************************/
1281 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 */
1757 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