LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/sw/source/core/text - itrcrsr.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 401 939 42.7 %
Date: 2013-07-09 Functions: 10 13 76.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10