xref: /AOO41X/main/sw/source/core/text/itrcrsr.cxx (revision 376de1e92b9cf8f9af0f1e4b64def448bc422b96)
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 #include <com/sun/star/i18n/ScriptType.hpp>
60 
61 // Nicht reentrant !!!
62 // wird in GetCharRect gesetzt und im UnitUp/Down ausgewertet.
63 sal_Bool SwTxtCursor::bRightMargin = sal_False;
64 
65 
66 /*************************************************************************
67  *                    lcl_GetCharRectInsideField
68  *
69  * After calculating the position of a character during GetCharRect
70  * this function allows to find the coordinates of a position (defined
71  * in pCMS->pSpecialPos) inside a special portion (e.g., a field)
72  *************************************************************************/
lcl_GetCharRectInsideField(SwTxtSizeInfo & rInf,SwRect & rOrig,const SwCrsrMoveState & rCMS,const SwLinePortion & rPor)73 void lcl_GetCharRectInsideField( SwTxtSizeInfo& rInf, SwRect& rOrig,
74                                  const SwCrsrMoveState& rCMS,
75                                  const SwLinePortion& rPor )
76 {
77     ASSERT( rCMS.pSpecialPos, "Information about special pos missing" )
78 
79     if ( rPor.InFldGrp() && ((SwFldPortion&)rPor).GetExp().Len() )
80     {
81         const sal_uInt16 nCharOfst = rCMS.pSpecialPos->nCharOfst;
82         sal_uInt16 nFldIdx = 0;
83         sal_uInt16 nFldLen = 0;
84 
85         const XubString* pString = 0;
86         const SwLinePortion* pPor = &rPor;
87         do
88         {
89             if ( pPor->InFldGrp() )
90             {
91                 pString = &((SwFldPortion*)pPor)->GetExp();
92                 nFldLen = pString->Len();
93             }
94             else
95             {
96                 pString = 0;
97                 nFldLen = 0;
98             }
99 
100             if ( ! pPor->GetPortion() || nFldIdx + nFldLen > nCharOfst )
101                 break;
102 
103             nFldIdx = nFldIdx + nFldLen;
104             rOrig.Pos().X() += pPor->Width();
105             pPor = pPor->GetPortion();
106 
107         } while ( sal_True );
108 
109         ASSERT( nCharOfst >= nFldIdx, "Request of position inside field failed" )
110         sal_uInt16 nLen = nCharOfst - nFldIdx + 1;
111 
112         if ( pString )
113         {
114             // get script for field portion
115             rInf.GetFont()->SetActual( SwScriptInfo::WhichFont( 0, pString, 0 ) );
116 
117             xub_StrLen nOldLen = pPor->GetLen();
118             ((SwLinePortion*)pPor)->SetLen( nLen - 1 );
119             const SwTwips nX1 = pPor->GetLen() ?
120                                 pPor->GetTxtSize( rInf ).Width() :
121                                 0;
122 
123             SwTwips nX2 = 0;
124             if ( rCMS.bRealWidth )
125             {
126                 ((SwLinePortion*)pPor)->SetLen( nLen );
127                 nX2 = pPor->GetTxtSize( rInf ).Width();
128             }
129 
130             ((SwLinePortion*)pPor)->SetLen( nOldLen );
131 
132             rOrig.Pos().X() += nX1;
133             rOrig.Width( ( nX2 > nX1 ) ?
134                          ( nX2 - nX1 ) :
135                            1 );
136         }
137     }
138     else
139     {
140         // special cases: no common fields, e.g., graphic number portion,
141         // FlyInCntPortions, Notes
142         rOrig.Width( rCMS.bRealWidth && rPor.Width() ? rPor.Width() : 1 );
143     }
144 }
145 
146 // --> OD 2010-05-05 #i111284#
147 namespace {
AreListLevelIndentsApplicableAndLabelAlignmentActive(const SwTxtNode & rTxtNode)148     bool AreListLevelIndentsApplicableAndLabelAlignmentActive( const SwTxtNode& rTxtNode )
149     {
150         bool bRet( false );
151 
152         if ( rTxtNode.AreListLevelIndentsApplicable() )
153         {
154             const SwNumFmt& rNumFmt =
155                     rTxtNode.GetNumRule()->Get( static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()) );
156             if ( rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
157             {
158                 bRet = true;
159             }
160         }
161 
162         return bRet;
163     }
164 } // end of anonymous namespace
165 // <--
166 
167 /*************************************************************************
168  *                SwTxtMargin::CtorInitTxtMargin()
169  *************************************************************************/
CtorInitTxtMargin(SwTxtFrm * pNewFrm,SwTxtSizeInfo * pNewInf)170 void SwTxtMargin::CtorInitTxtMargin( SwTxtFrm *pNewFrm, SwTxtSizeInfo *pNewInf )
171 {
172     CtorInitTxtIter( pNewFrm, pNewInf );
173 
174     pInf = pNewInf;
175     GetInfo().SetFont( GetFnt() );
176     const SwTxtNode *pNode = pFrm->GetTxtNode();
177 
178     const SvxLRSpaceItem &rSpace = pFrm->GetTxtNode()->GetSwAttrSet().GetLRSpace();
179     // --> OD 2009-09-08 #i95907#, #b6879723#
180     // --> OD 2010-05-05 #i111284#
181     const bool bListLevelIndentsApplicableAndLabelAlignmentActive(
182         AreListLevelIndentsApplicableAndLabelAlignmentActive( *(pFrm->GetTxtNode()) ) );
183     // <--
184 
185     //
186     // Carefully adjust the text formatting ranges.
187     //
188     // This whole area desperately needs some rework. There are
189     // quite a couple of values that need to be considered:
190     // 1. paragraph indent
191     // 2. paragraph first line indent
192     // 3. numbering indent
193     // 4. numbering spacing to text
194     // 5. paragraph border
195     // Note: These values have already been used during calculation
196     // of the printing area of the paragraph.
197     const int nLMWithNum = pNode->GetLeftMarginWithNum( sal_True );
198     if ( pFrm->IsRightToLeft() )
199     {
200         // --> OD 2008-01-23 #newlistlevelattrs#
201         // this calculation is identical this the calculation for L2R layout - see below
202         nLeft = pFrm->Frm().Left() +
203                 pFrm->Prt().Left() +
204                 nLMWithNum -
205                 pNode->GetLeftMarginWithNum( sal_False ) -
206                 // --> OD 2009-09-08 #i95907#, #b6879723#
207                 // --> OD 2010-05-05 #i111284#
208 //                rSpace.GetLeft() +
209 //                rSpace.GetTxtLeft();
210                 ( bListLevelIndentsApplicableAndLabelAlignmentActive
211                   ? 0
212                   : ( rSpace.GetLeft() - rSpace.GetTxtLeft() ) );
213                 // <--
214     }
215     else
216     {
217         // --> OD 2009-09-08 #i95907#, #b6879723#
218         // --> OD 2010-05-05 #i111284#
219 //        if ( !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
220         if ( bListLevelIndentsApplicableAndLabelAlignmentActive ||
221              !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
222         // <--
223         {
224             // this calculation is identical this the calculation for R2L layout - see above
225             nLeft = pFrm->Frm().Left() +
226                     pFrm->Prt().Left() +
227                     nLMWithNum -
228                     pNode->GetLeftMarginWithNum( sal_False ) -
229                     // --> OD 2009-09-08 #i95907#, #b6879723#
230                     // --> OD 2010-05-05 #i111284#
231 //                    rSpace.GetLeft() +
232 //                    rSpace.GetTxtLeft();
233                     ( bListLevelIndentsApplicableAndLabelAlignmentActive
234                       ? 0
235                       : ( rSpace.GetLeft() - rSpace.GetTxtLeft() ) );
236                     // <--
237         }
238         else
239         {
240             nLeft = pFrm->Frm().Left() +
241                     Max( long( rSpace.GetTxtLeft() + nLMWithNum ),
242                          pFrm->Prt().Left() );
243         }
244     }
245 
246     nRight = pFrm->Frm().Left() + pFrm->Prt().Left() + pFrm->Prt().Width();
247 
248     if( nLeft >= nRight &&
249          // --> FME 2005-08-10 #i53066# Omit adjustment of nLeft for numbered
250          // paras inside cells inside new documents:
251         ( pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) ||
252           !pFrm->IsInTab() ||
253           !nLMWithNum ) )
254          // <--
255     {
256         nLeft = pFrm->Prt().Left() + pFrm->Frm().Left();
257         if( nLeft >= nRight )   // z.B. bei grossen Absatzeinzuegen in schmalen Tabellenspalten
258             nRight = nLeft + 1; // einen goennen wir uns immer
259     }
260 
261     if( pFrm->IsFollow() && pFrm->GetOfst() )
262         nFirst = nLeft;
263     else
264     {
265         short nFLOfst = 0;
266         long nFirstLineOfs = 0;
267         if( !pNode->GetFirstLineOfsWithNum( nFLOfst ) &&
268             rSpace.IsAutoFirst() )
269         {
270             nFirstLineOfs = GetFnt()->GetSize( GetFnt()->GetActual() ).Height();
271                         LanguageType aLang = pNode->GetLang( 0, 1, i18n::ScriptType::ASIAN);
272                         if (aLang != LANGUAGE_KOREAN && aLang != LANGUAGE_JAPANESE)
273                             nFirstLineOfs<<=1;
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  *************************************************************************/
DropInit()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.
GetLineStart() const408 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  *************************************************************************/
CtorInitTxtCursor(SwTxtFrm * pNewFrm,SwTxtSizeInfo * pNewInf)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 
GetEndCharRect(SwRect * pOrig,const xub_StrLen nOfst,SwCrsrMoveState * pCMS,const long nMax)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 
_GetCharRect(SwRect * pOrig,const xub_StrLen nOfst,SwCrsrMoveState * pCMS)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 
GetCharRect(SwRect * pOrig,const xub_StrLen nOfst,SwCrsrMoveState * pCMS,const long nMax)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  *************************************************************************/
GetCrsrOfst(SwPosition * pPos,const Point & rPoint,const MSHORT nChgNode,SwCrsrMoveState * pCMS) const1285 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 */
FillSelection(SwSelectionList & rSelList,const SwRect & rRect) const1761 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