LCOV - code coverage report
Current view: top level - sw/source/core/text - frmcrsr.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 239 836 28.6 %
Date: 2014-11-03 Functions: 16 34 47.1 %
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 "ndtxt.hxx"
      21             : #include "pam.hxx"
      22             : #include "frmtool.hxx"
      23             : #include "viewopt.hxx"
      24             : #include "paratr.hxx"
      25             : #include "rootfrm.hxx"
      26             : #include "pagefrm.hxx"
      27             : #include "colfrm.hxx"
      28             : #include "swtypes.hxx"
      29             : #include <sfx2/printer.hxx>
      30             : #include <editeng/lrspitem.hxx>
      31             : #include <editeng/tstpitem.hxx>
      32             : #include <editeng/ulspitem.hxx>
      33             : #include <editeng/lspcitem.hxx>
      34             : #include <pormulti.hxx>
      35             : #include <doc.hxx>
      36             : #include <IDocumentDeviceAccess.hxx>
      37             : #include <sortedobjs.hxx>
      38             : 
      39             : #include <unicode/ubidi.h>
      40             : 
      41             : #include "txtfrm.hxx"
      42             : #include "inftxt.hxx"
      43             : #include "itrtxt.hxx"
      44             : #include "crstate.hxx"
      45             : #include "viewsh.hxx"
      46             : #include "swfntcch.hxx"
      47             : #include "flyfrm.hxx"
      48             : 
      49             : #define MIN_OFFSET_STEP 10
      50             : 
      51             : using namespace ::com::sun::star;
      52             : 
      53             : /*
      54             :  * - SurvivalKit: For how long do we get past the last char of the line.
      55             :  * - RightMargin abstains from adjusting position with -1
      56             :  * - GetCharRect returns a GetEndCharRect for MV_RIGHTMARGIN
      57             :  * - GetEndCharRect sets bRightMargin to true
      58             :  * - SwTxtCursor::bRightMargin is set to false by CharCrsrToLine
      59             :  */
      60             : 
      61             : namespace
      62             : {
      63             : 
      64      148214 : SwTxtFrm *GetAdjFrmAtPos( SwTxtFrm *pFrm, const SwPosition &rPos,
      65             :                           const bool bRightMargin, const bool bNoScroll = true )
      66             : {
      67             :     // RightMargin in the last master line
      68      148214 :     const sal_Int32 nOffset = rPos.nContent.GetIndex();
      69      148214 :     SwTxtFrm *pFrmAtPos = pFrm;
      70      148214 :     if( !bNoScroll || pFrm->GetFollow() )
      71             :     {
      72      145214 :         pFrmAtPos = pFrm->GetFrmAtPos( rPos );
      73      145214 :         if( nOffset < pFrmAtPos->GetOfst() &&
      74           0 :             !pFrmAtPos->IsFollow() )
      75             :         {
      76           0 :             sal_Int32 nNew = nOffset;
      77           0 :             if( nNew < MIN_OFFSET_STEP )
      78           0 :                 nNew = 0;
      79             :             else
      80           0 :                 nNew -= MIN_OFFSET_STEP;
      81           0 :             sw_ChangeOffset( pFrmAtPos, nNew );
      82             :         }
      83             :     }
      84      296428 :     while( pFrm != pFrmAtPos )
      85             :     {
      86           0 :         pFrm = pFrmAtPos;
      87           0 :         pFrm->GetFormatted();
      88           0 :         pFrmAtPos = (SwTxtFrm*)pFrm->GetFrmAtPos( rPos );
      89             :     }
      90             : 
      91      148214 :     if( nOffset && bRightMargin )
      92             :     {
      93           0 :         while( pFrmAtPos && pFrmAtPos->GetOfst() == nOffset &&
      94           0 :                pFrmAtPos->IsFollow() )
      95             :         {
      96           0 :             pFrmAtPos->GetFormatted();
      97           0 :             pFrmAtPos = pFrmAtPos->FindMaster();
      98             :         }
      99             :         OSL_ENSURE( pFrmAtPos, "+GetCharRect: no frame with my rightmargin" );
     100             :     }
     101      148214 :     return pFrmAtPos ? pFrmAtPos : pFrm;
     102             : }
     103             : 
     104             : }
     105             : 
     106           0 : bool sw_ChangeOffset( SwTxtFrm* pFrm, sal_Int32 nNew )
     107             : {
     108             :     // Do not scroll in areas and outside of flies
     109             :     OSL_ENSURE( !pFrm->IsFollow(), "Illegal Scrolling by Follow!" );
     110           0 :     if( pFrm->GetOfst() != nNew && !pFrm->IsInSct() )
     111             :     {
     112           0 :         SwFlyFrm *pFly = pFrm->FindFlyFrm();
     113             :         // Attention: if e.g. in a column frame the size is still invalid
     114             :         // we must not scroll around just like that
     115           0 :         if ( ( pFly && pFly->IsValid() &&
     116           0 :              !pFly->GetNextLink() && !pFly->GetPrevLink() ) ||
     117           0 :              ( !pFly && pFrm->IsInTab() ) )
     118             :         {
     119           0 :             SwViewShell* pVsh = pFrm->getRootFrm()->GetCurrShell();
     120           0 :             if( pVsh )
     121             :             {
     122           0 :                 if( pVsh->GetNext() != pVsh ||
     123           0 :                     ( pFrm->GetDrawObjs() && pFrm->GetDrawObjs()->size() ) )
     124             :                 {
     125           0 :                     if( !pFrm->GetOfst() )
     126           0 :                         return false;
     127           0 :                     nNew = 0;
     128             :                 }
     129           0 :                 pFrm->SetOfst( nNew );
     130           0 :                 pFrm->SetPara( 0 );
     131           0 :                 pFrm->GetFormatted();
     132           0 :                 if( pFrm->Frm().HasArea() )
     133           0 :                     pFrm->getRootFrm()->GetCurrShell()->InvalidateWindows( pFrm->Frm() );
     134           0 :                 return true;
     135             :             }
     136             :         }
     137             :     }
     138           0 :     return false;
     139             : }
     140             : 
     141      109132 : SwTxtFrm& SwTxtFrm::GetFrmAtOfst( const sal_Int32 nWhere )
     142             : {
     143      109132 :     SwTxtFrm* pRet = this;
     144      218416 :     while( pRet->HasFollow() && nWhere >= pRet->GetFollow()->GetOfst() )
     145         152 :         pRet = pRet->GetFollow();
     146      109132 :     return *pRet;
     147             : }
     148             : 
     149      508585 : SwTxtFrm *SwTxtFrm::GetFrmAtPos( const SwPosition &rPos )
     150             : {
     151      508585 :     SwTxtFrm *pFoll = (SwTxtFrm*)this;
     152     1075170 :     while( pFoll->GetFollow() )
     153             :     {
     154       58608 :         if( rPos.nContent.GetIndex() > pFoll->GetFollow()->GetOfst() )
     155       57790 :             pFoll = pFoll->GetFollow();
     156             :         else
     157             :         {
     158        1636 :             if( rPos.nContent.GetIndex() == pFoll->GetFollow()->GetOfst()
     159         818 :                  && !SwTxtCursor::IsRightMargin() )
     160         210 :                  pFoll = pFoll->GetFollow();
     161             :             else
     162         608 :                 break;
     163             :         }
     164             :     }
     165      508585 :     return pFoll;
     166             : }
     167             : 
     168             : /*
     169             :  * GetCharRect() returns the char's char line described by aPos.
     170             :  * GetCrsrOfst() does the reverse: It goes from a document coordinate to
     171             :  * a Pam.
     172             :  * Both are virtual in the frame base class and thus are redefined here.
     173             :  */
     174             : 
     175      148576 : bool SwTxtFrm::GetCharRect( SwRect& rOrig, const SwPosition &rPos,
     176             :                             SwCrsrMoveState *pCMS ) const
     177             : {
     178             :     OSL_ENSURE( ! IsVertical() || ! IsSwapped(),"SwTxtFrm::GetCharRect with swapped frame" );
     179             : 
     180      148576 :     if( IsLocked() || IsHiddenNow() )
     181         368 :         return false;
     182             : 
     183             :     // Find the right frame first. We need to keep in mind that:
     184             :     // - the cached information could be invalid  (GetPara() == 0)
     185             :     // - we could have a Follow
     186             :     // - the Follow chain grows dynamically; the one we end up in
     187             :     //   needs to be formatted
     188             : 
     189             :     // Optimisation: reading ahead saves us a GetAdjFrmAtPos
     190      148208 :     const bool bRightMargin = pCMS && ( MV_RIGHTMARGIN == pCMS->eState );
     191      148208 :     const bool bNoScroll = pCMS && pCMS->bNoScroll;
     192             :     SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, rPos, bRightMargin,
     193      148208 :                                      bNoScroll );
     194      148208 :     pFrm->GetFormatted();
     195      148208 :     const SwFrm* pTmpFrm = (SwFrm*)pFrm->GetUpper();
     196             : 
     197      148208 :     SWRECTFN ( pFrm )
     198      148208 :     const SwTwips nUpperMaxY = (pTmpFrm->*fnRect->fnGetPrtBottom)();
     199      148208 :     const SwTwips nFrmMaxY = (pFrm->*fnRect->fnGetPrtBottom)();
     200             : 
     201             :     // nMaxY is an absolute value
     202             :     SwTwips nMaxY = bVert ?
     203           0 :                     ( bVertL2R ? std::min( nFrmMaxY, nUpperMaxY ) : std::max( nFrmMaxY, nUpperMaxY ) ) :
     204      148208 :                     std::min( nFrmMaxY, nUpperMaxY );
     205             : 
     206      148208 :     bool bRet = false;
     207             : 
     208      148208 :     if ( pFrm->IsEmpty() || ! (pFrm->Prt().*fnRect->fnGetHeight)() )
     209             :     {
     210       35330 :         Point aPnt1 = pFrm->Frm().Pos() + pFrm->Prt().Pos();
     211       35330 :         SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
     212             :         short nFirstOffset;
     213       35330 :         pTxtNd->GetFirstLineOfsWithNum( nFirstOffset );
     214             : 
     215       35330 :         Point aPnt2;
     216       35330 :         if ( bVert )
     217             :         {
     218           0 :             if( nFirstOffset > 0 )
     219           0 :                 aPnt1.Y() += nFirstOffset;
     220           0 :             if ( aPnt1.X() < nMaxY && !bVertL2R )
     221           0 :                 aPnt1.X() = nMaxY;
     222           0 :             aPnt2.X() = aPnt1.X() + pFrm->Prt().Width();
     223           0 :             aPnt2.Y() = aPnt1.Y();
     224           0 :             if( aPnt2.X() < nMaxY )
     225           0 :                 aPnt2.X() = nMaxY;
     226             :         }
     227             :         else
     228             :         {
     229       35330 :             if( nFirstOffset > 0 )
     230           0 :                 aPnt1.X() += nFirstOffset;
     231             : 
     232       35330 :             if( aPnt1.Y() > nMaxY )
     233           0 :                 aPnt1.Y() = nMaxY;
     234       35330 :             aPnt2.X() = aPnt1.X();
     235       35330 :             aPnt2.Y() = aPnt1.Y() + pFrm->Prt().Height();
     236       35330 :             if( aPnt2.Y() > nMaxY )
     237           0 :                 aPnt2.Y() = nMaxY;
     238             :         }
     239             : 
     240       35330 :         rOrig = SwRect( aPnt1, aPnt2 );
     241             : 
     242       35330 :         if ( pCMS )
     243             :         {
     244       35322 :             pCMS->aRealHeight.X() = 0;
     245       35322 :             pCMS->aRealHeight.Y() = bVert ? -rOrig.Width() : rOrig.Height();
     246             :         }
     247             : 
     248       35330 :         if ( pFrm->IsRightToLeft() )
     249         128 :             pFrm->SwitchLTRtoRTL( rOrig );
     250             : 
     251       35330 :         bRet = true;
     252             :     }
     253             :     else
     254             :     {
     255      112878 :         if( !pFrm->HasPara() )
     256           0 :             return false;
     257             : 
     258      112878 :         SwFrmSwapper aSwapper( pFrm, true );
     259      112878 :         if ( bVert )
     260           0 :             nMaxY = pFrm->SwitchVerticalToHorizontal( nMaxY );
     261             : 
     262      112878 :         bool bGoOn = true;
     263      112878 :         const sal_Int32 nOffset = rPos.nContent.GetIndex();
     264             :         sal_Int32 nNextOfst;
     265             : 
     266      112878 :         do
     267             :         {
     268             :             {
     269      112878 :                 SwTxtSizeInfo aInf( pFrm );
     270      225756 :                 SwTxtCursor  aLine( pFrm, &aInf );
     271      112878 :                 nNextOfst = aLine.GetEnd();
     272             :                 // See comment in AdjustFrm
     273             :                 // Include the line's last char?
     274             :                 bRet = bRightMargin ? aLine.GetEndCharRect( &rOrig, nOffset, pCMS, nMaxY )
     275      225756 :                                 : aLine.GetCharRect( &rOrig, nOffset, pCMS, nMaxY );
     276             :             }
     277             : 
     278      112878 :             if ( pFrm->IsRightToLeft() )
     279         198 :                 pFrm->SwitchLTRtoRTL( rOrig );
     280             : 
     281      112878 :             if ( bVert )
     282           0 :                 pFrm->SwitchHorizontalToVertical( rOrig );
     283             : 
     284      226216 :             if( pFrm->IsUndersized() && pCMS && !pFrm->GetNext() &&
     285         386 :                 (rOrig.*fnRect->fnGetBottom)() == nUpperMaxY &&
     286         164 :                 pFrm->GetOfst() < nOffset &&
     287      112902 :                 !pFrm->IsFollow() && !bNoScroll &&
     288           8 :                 pFrm->GetTxtNode()->GetTxt().getLength() != nNextOfst)
     289             :             {
     290           0 :                 bGoOn = sw_ChangeOffset( pFrm, nNextOfst );
     291             :             }
     292             :             else
     293      112878 :                 bGoOn = false;
     294             :         } while ( bGoOn );
     295             : 
     296      112878 :         if ( pCMS )
     297             :         {
     298      111714 :             if ( pFrm->IsRightToLeft() )
     299             :             {
     300         198 :                 if( pCMS->b2Lines && pCMS->p2Lines)
     301             :                 {
     302           0 :                     pFrm->SwitchLTRtoRTL( pCMS->p2Lines->aLine );
     303           0 :                     pFrm->SwitchLTRtoRTL( pCMS->p2Lines->aPortion );
     304             :                 }
     305             :             }
     306             : 
     307      111714 :             if ( bVert )
     308             :             {
     309           0 :                 if ( pCMS->bRealHeight )
     310             :                 {
     311           0 :                     pCMS->aRealHeight.Y() = -pCMS->aRealHeight.Y();
     312           0 :                     if ( pCMS->aRealHeight.Y() < 0 )
     313             :                     {
     314             :                         // writing direction is from top to bottom
     315           0 :                         pCMS->aRealHeight.X() =  ( rOrig.Width() -
     316           0 :                                                     pCMS->aRealHeight.X() +
     317           0 :                                                     pCMS->aRealHeight.Y() );
     318             :                     }
     319             :                 }
     320           0 :                 if( pCMS->b2Lines && pCMS->p2Lines)
     321             :                 {
     322           0 :                     pFrm->SwitchHorizontalToVertical( pCMS->p2Lines->aLine );
     323           0 :                     pFrm->SwitchHorizontalToVertical( pCMS->p2Lines->aPortion );
     324             :                 }
     325             :             }
     326             : 
     327      112878 :         }
     328             :     }
     329      148208 :     if( bRet )
     330             :     {
     331      148208 :         SwPageFrm *pPage = pFrm->FindPageFrm();
     332             :         OSL_ENSURE( pPage, "Text escaped from page?" );
     333      148208 :         const SwTwips nOrigTop = (rOrig.*fnRect->fnGetTop)();
     334      148208 :         const SwTwips nPageTop = (pPage->Frm().*fnRect->fnGetTop)();
     335      148208 :         const SwTwips nPageBott = (pPage->Frm().*fnRect->fnGetBottom)();
     336             : 
     337             :         // We have the following situation: if the frame is in an invalid
     338             :         // sectionframe, it's possible that the frame is outside the page.
     339             :         // If we restrict the cursor position to the page area, we enforce
     340             :         // the formatting of the page, of the section frame and the frame itself.
     341      148208 :         if( (*fnRect->fnYDiff)( nPageTop, nOrigTop ) > 0 )
     342           0 :             (rOrig.*fnRect->fnSetTop)( nPageTop );
     343             : 
     344      148208 :         if ( (*fnRect->fnYDiff)( nOrigTop, nPageBott ) > 0 )
     345           0 :             (rOrig.*fnRect->fnSetTop)( nPageBott );
     346             :     }
     347             : 
     348      148208 :     return bRet;
     349             : }
     350             : 
     351             : /*
     352             :  * GetAutoPos() looks up the char's char line which is described by rPos
     353             :  * and is used by the auto-positioned frame.
     354             :  */
     355             : 
     356        3834 : bool SwTxtFrm::GetAutoPos( SwRect& rOrig, const SwPosition &rPos ) const
     357             : {
     358        3834 :     if( IsHiddenNow() )
     359           0 :         return false;
     360             : 
     361        3834 :     const sal_Int32 nOffset = rPos.nContent.GetIndex();
     362        3834 :     SwTxtFrm* pFrm = &(const_cast<SwTxtFrm*>(this)->GetFrmAtOfst( nOffset ));
     363             : 
     364        3834 :     pFrm->GetFormatted();
     365        3834 :     const SwFrm* pTmpFrm = (SwFrm*)pFrm->GetUpper();
     366             : 
     367        3834 :     SWRECTFN( pTmpFrm )
     368        3834 :     SwTwips nUpperMaxY = (pTmpFrm->*fnRect->fnGetPrtBottom)();
     369             : 
     370             :     // nMaxY is in absolute value
     371             :     SwTwips nMaxY = bVert ?
     372        3834 :                     ( bVertL2R ? std::min( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY ) : std::max( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY ) ) :
     373        7668 :                     std::min( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY );
     374             : 
     375        3834 :     if ( pFrm->IsEmpty() || ! (pFrm->Prt().*fnRect->fnGetHeight)() )
     376             :     {
     377        1238 :         Point aPnt1 = pFrm->Frm().Pos() + pFrm->Prt().Pos();
     378        1238 :         Point aPnt2;
     379        1238 :         if ( bVert )
     380             :         {
     381           0 :             if ( aPnt1.X() < nMaxY && !bVertL2R )
     382           0 :                 aPnt1.X() = nMaxY;
     383             : 
     384           0 :             aPnt2.X() = aPnt1.X() + pFrm->Prt().Width();
     385           0 :             aPnt2.Y() = aPnt1.Y();
     386           0 :             if( aPnt2.X() < nMaxY )
     387           0 :                 aPnt2.X() = nMaxY;
     388             :         }
     389             :         else
     390             :         {
     391        1238 :             if( aPnt1.Y() > nMaxY )
     392           0 :                 aPnt1.Y() = nMaxY;
     393        1238 :             aPnt2.X() = aPnt1.X();
     394        1238 :             aPnt2.Y() = aPnt1.Y() + pFrm->Prt().Height();
     395        1238 :             if( aPnt2.Y() > nMaxY )
     396           0 :                 aPnt2.Y() = nMaxY;
     397             :         }
     398        1238 :         rOrig = SwRect( aPnt1, aPnt2 );
     399        1238 :         return true;
     400             :     }
     401             :     else
     402             :     {
     403        2596 :         if( !pFrm->HasPara() )
     404           0 :             return false;
     405             : 
     406        2596 :         SwFrmSwapper aSwapper( pFrm, true );
     407        2596 :         if ( bVert )
     408           0 :             nMaxY = pFrm->SwitchVerticalToHorizontal( nMaxY );
     409             : 
     410        5192 :         SwTxtSizeInfo aInf( pFrm );
     411        5192 :         SwTxtCursor aLine( pFrm, &aInf );
     412        2596 :         SwCrsrMoveState aTmpState( MV_SETONLYTEXT );
     413        2596 :         aTmpState.bRealHeight = true;
     414        2596 :         if( aLine.GetCharRect( &rOrig, nOffset, &aTmpState, nMaxY ) )
     415             :         {
     416        2596 :             if( aTmpState.aRealHeight.X() >= 0 )
     417             :             {
     418        2596 :                 rOrig.Pos().Y() += aTmpState.aRealHeight.X();
     419        2596 :                 rOrig.Height( aTmpState.aRealHeight.Y() );
     420             :             }
     421             : 
     422        2596 :             if ( pFrm->IsRightToLeft() )
     423           0 :                 pFrm->SwitchLTRtoRTL( rOrig );
     424             : 
     425        2596 :             if ( bVert )
     426           0 :                 pFrm->SwitchHorizontalToVertical( rOrig );
     427             : 
     428        2596 :             return true;
     429             :         }
     430        2596 :         return false;
     431             :     }
     432             : }
     433             : 
     434             : /** determine top of line for given position in the text frame
     435             : 
     436             :     - Top of first paragraph line is the top of the printing area of the text frame
     437             :     - If a proportional line spacing is applied use top of anchor character as
     438             :       top of the line.
     439             : */
     440        3554 : bool SwTxtFrm::GetTopOfLine( SwTwips& _onTopOfLine,
     441             :                              const SwPosition& _rPos ) const
     442             : {
     443        3554 :     bool bRet = true;
     444             : 
     445             :     // get position offset
     446        3554 :     const sal_Int32 nOffset = _rPos.nContent.GetIndex();
     447             : 
     448        3554 :     if ( GetTxt().getLength() < nOffset )
     449             :     {
     450           0 :         bRet = false;
     451             :     }
     452             :     else
     453             :     {
     454        3554 :         SWRECTFN( this )
     455        3554 :         if ( IsEmpty() || !(Prt().*fnRect->fnGetHeight)() )
     456             :         {
     457             :             // consider upper space amount considered
     458             :             // for previous frame and the page grid.
     459        1238 :             _onTopOfLine = (this->*fnRect->fnGetPrtTop)();
     460             :         }
     461             :         else
     462             :         {
     463             :             // determine formatted text frame that contains the requested position
     464        2316 :             SwTxtFrm* pFrm = &(const_cast<SwTxtFrm*>(this)->GetFrmAtOfst( nOffset ));
     465        2316 :             pFrm->GetFormatted();
     466        2316 :             SWREFRESHFN( pFrm )
     467             :             // If proportional line spacing is applied
     468             :             // to the text frame, the top of the anchor character is also the
     469             :             // top of the line.
     470             :             // Otherwise the line layout determines the top of the line
     471        2316 :             const SvxLineSpacingItem& rSpace = GetAttrSet()->GetLineSpacing();
     472        2316 :             if ( rSpace.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP )
     473             :             {
     474         280 :                 SwRect aCharRect;
     475         280 :                 if ( GetAutoPos( aCharRect, _rPos ) )
     476             :                 {
     477         280 :                     _onTopOfLine = (aCharRect.*fnRect->fnGetTop)();
     478             :                 }
     479             :                 else
     480             :                 {
     481           0 :                     bRet = false;
     482             :                 }
     483             :             }
     484             :             else
     485             :             {
     486             :                 // assure that text frame is in a horizontal layout
     487        2036 :                 SwFrmSwapper aSwapper( pFrm, true );
     488             :                 // determine text line that contains the requested position
     489        4072 :                 SwTxtSizeInfo aInf( pFrm );
     490        4072 :                 SwTxtCursor aLine( pFrm, &aInf );
     491        2036 :                 aLine.CharCrsrToLine( nOffset );
     492             :                 // determine top of line
     493        2036 :                 _onTopOfLine = aLine.Y();
     494        2036 :                 if ( bVert )
     495             :                 {
     496           0 :                     _onTopOfLine = pFrm->SwitchHorizontalToVertical( _onTopOfLine );
     497        2036 :                 }
     498             :             }
     499             :         }
     500             :     }
     501             : 
     502        3554 :     return bRet;
     503             : }
     504             : 
     505             : // Minimum distance of non-empty lines is a little less than 2 cm
     506             : #define FILL_MIN_DIST 1100
     507             : 
     508             : struct SwFillData
     509             : {
     510             :     SwRect aFrm;
     511             :     const SwCrsrMoveState *pCMS;
     512             :     SwPosition* pPos;
     513             :     const Point& rPoint;
     514             :     SwTwips nLineWidth;
     515             :     bool bFirstLine : 1;
     516             :     bool bInner     : 1;
     517             :     bool bColumn    : 1;
     518             :     bool bEmpty     : 1;
     519           0 :     SwFillData( const SwCrsrMoveState *pC, SwPosition* pP, const SwRect& rR,
     520             :         const Point& rPt ) : aFrm( rR ), pCMS( pC ), pPos( pP ), rPoint( rPt ),
     521             :         nLineWidth( 0 ), bFirstLine( true ), bInner( false ), bColumn( false ),
     522           0 :         bEmpty( true ){}
     523           0 :     SwFillMode Mode() const { return pCMS->pFill->eMode; }
     524           0 :     long X() const { return rPoint.X(); }
     525           0 :     long Y() const { return rPoint.Y(); }
     526           0 :     long Left() const { return aFrm.Left(); }
     527           0 :     long Right() const { return aFrm.Right(); }
     528           0 :     long Bottom() const { return aFrm.Bottom(); }
     529           0 :     SwFillCrsrPos &Fill() const { return *pCMS->pFill; }
     530           0 :     void SetTab( sal_uInt16 nNew ) { pCMS->pFill->nTabCnt = nNew; }
     531           0 :     void SetSpace( sal_uInt16 nNew ) { pCMS->pFill->nSpaceCnt = nNew; }
     532           0 :     void SetOrient( const sal_Int16 eNew ){ pCMS->pFill->eOrient = eNew; }
     533             : };
     534             : 
     535         789 : bool SwTxtFrm::_GetCrsrOfst(SwPosition* pPos, const Point& rPoint,
     536             :                     const bool bChgFrm, SwCrsrMoveState* pCMS ) const
     537             : {
     538             :     // _GetCrsrOfst is called by GetCrsrOfst and GetKeyCrsrOfst.
     539             :     // Never just a return false.
     540             : 
     541         789 :     if( IsLocked() || IsHiddenNow() )
     542         315 :         return false;
     543             : 
     544         474 :     ((SwTxtFrm*)this)->GetFormatted();
     545             : 
     546         474 :     Point aOldPoint( rPoint );
     547             : 
     548         474 :     if ( IsVertical() )
     549             :     {
     550           0 :         SwitchVerticalToHorizontal( (Point&)rPoint );
     551           0 :         ((SwTxtFrm*)this)->SwapWidthAndHeight();
     552             :     }
     553             : 
     554         474 :     if ( IsRightToLeft() )
     555           0 :         SwitchRTLtoLTR( (Point&)rPoint );
     556             : 
     557         474 :     SwFillData *pFillData = ( pCMS && pCMS->pFill ) ?
     558         474 :                         new SwFillData( pCMS, pPos, Frm(), rPoint ) : NULL;
     559             : 
     560         474 :     if ( IsEmpty() )
     561             :     {
     562         240 :         SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
     563         240 :         pPos->nNode = *pTxtNd;
     564         240 :         pPos->nContent.Assign( pTxtNd, 0 );
     565         240 :         if( pCMS && pCMS->bFieldInfo )
     566             :         {
     567           0 :             SwTwips nDiff = rPoint.X() - Frm().Left() - Prt().Left();
     568           0 :             if( nDiff > 50 || nDiff < 0 )
     569           0 :                 ((SwCrsrMoveState*)pCMS)->bPosCorr = true;
     570             :         }
     571             :     }
     572             :     else
     573             :     {
     574         234 :         SwTxtSizeInfo aInf( (SwTxtFrm*)this );
     575         468 :         SwTxtCursor  aLine( ((SwTxtFrm*)this), &aInf );
     576             : 
     577             :         // See comment in AdjustFrm()
     578         234 :         SwTwips nMaxY = Frm().Top() + Prt().Top() + Prt().Height();
     579         234 :         aLine.TwipsToLine( rPoint.Y() );
     580         468 :         while( aLine.Y() + aLine.GetLineHeight() > nMaxY )
     581             :         {
     582           0 :             if( !aLine.Prev() )
     583           0 :                 break;
     584             :         }
     585             : 
     586         468 :         if( aLine.GetDropLines() >= aLine.GetLineNr() && 1 != aLine.GetLineNr()
     587         234 :             && rPoint.X() < aLine.FirstLeft() + aLine.GetDropLeft() )
     588           0 :             while( aLine.GetLineNr() > 1 )
     589           0 :                 aLine.Prev();
     590             : 
     591         234 :         sal_Int32 nOffset = aLine.GetCrsrOfst( pPos, rPoint, bChgFrm, pCMS );
     592             : 
     593         234 :         if( pCMS && pCMS->eState == MV_NONE && aLine.GetEnd() == nOffset )
     594           0 :             ((SwCrsrMoveState*)pCMS)->eState = MV_RIGHTMARGIN;
     595             : 
     596             :     // pPos is a pure IN parameter and must not be evaluated.
     597             :     // pIter->GetCrsrOfst returns from a nesting with COMPLETE_STRING.
     598             :     // If SwTxtIter::GetCrsrOfst calls GetCrsrOfst further by itself
     599             :     // nNode changes the position.
     600             :     // In such cases, pPos must not be calculated.
     601         234 :         if( COMPLETE_STRING != nOffset )
     602             :         {
     603         234 :             SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
     604         234 :             pPos->nNode = *pTxtNd;
     605         234 :             pPos->nContent.Assign( pTxtNd, nOffset );
     606         234 :             if( pFillData )
     607             :             {
     608           0 :                 if (pTxtNd->GetTxt().getLength() > nOffset ||
     609           0 :                     rPoint.Y() < Frm().Top() )
     610           0 :                     pFillData->bInner = true;
     611           0 :                 pFillData->bFirstLine = aLine.GetLineNr() < 2;
     612           0 :                 if (pTxtNd->GetTxt().getLength())
     613             :                 {
     614           0 :                     pFillData->bEmpty = false;
     615           0 :                     pFillData->nLineWidth = aLine.GetCurr()->Width();
     616             :                 }
     617             :             }
     618         234 :         }
     619             :     }
     620         474 :     bool bChgFillData = false;
     621         474 :     if( pFillData && FindPageFrm()->Frm().IsInside( aOldPoint ) )
     622             :     {
     623           0 :         FillCrsrPos( *pFillData );
     624           0 :         bChgFillData = true;
     625             :     }
     626             : 
     627         474 :     if ( IsVertical() )
     628             :     {
     629           0 :         if ( bChgFillData )
     630           0 :             SwitchHorizontalToVertical( pFillData->Fill().aCrsr.Pos() );
     631           0 :         ((SwTxtFrm*)this)->SwapWidthAndHeight();
     632             :     }
     633             : 
     634         474 :     if ( IsRightToLeft() && bChgFillData )
     635             :     {
     636           0 :             SwitchLTRtoRTL( pFillData->Fill().aCrsr.Pos() );
     637           0 :             const sal_Int16 eOrient = pFillData->pCMS->pFill->eOrient;
     638             : 
     639           0 :             if ( text::HoriOrientation::LEFT == eOrient )
     640           0 :                 pFillData->SetOrient( text::HoriOrientation::RIGHT );
     641           0 :             else if ( text::HoriOrientation::RIGHT == eOrient )
     642           0 :                 pFillData->SetOrient( text::HoriOrientation::LEFT );
     643             :     }
     644             : 
     645         474 :     (Point&)rPoint = aOldPoint;
     646         474 :     delete pFillData;
     647             : 
     648         474 :     return true;
     649             : }
     650             : 
     651         789 : bool SwTxtFrm::GetCrsrOfst(SwPosition* pPos, Point& rPoint,
     652             :                                SwCrsrMoveState* pCMS, bool ) const
     653             : {
     654         789 :     const bool bChgFrm = !(pCMS && MV_UPDOWN == pCMS->eState);
     655         789 :     return _GetCrsrOfst( pPos, rPoint, bChgFrm, pCMS );
     656             : }
     657             : 
     658             : /*
     659             :  * Layout-oriented cursor movement to the line start.
     660             :  */
     661             : 
     662           0 : bool SwTxtFrm::LeftMargin(SwPaM *pPam) const
     663             : {
     664           0 :     if( &pPam->GetNode() != GetNode() )
     665           0 :         pPam->GetPoint()->nNode = *((SwTxtFrm*)this)->GetTxtNode();
     666             : 
     667           0 :     SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *pPam->GetPoint(),
     668           0 :                                      SwTxtCursor::IsRightMargin() );
     669           0 :     pFrm->GetFormatted();
     670             :     sal_Int32 nIndx;
     671           0 :     if ( pFrm->IsEmpty() )
     672           0 :         nIndx = 0;
     673             :     else
     674             :     {
     675           0 :         SwTxtSizeInfo aInf( pFrm );
     676           0 :         SwTxtCursor  aLine( pFrm, &aInf );
     677             : 
     678           0 :         aLine.CharCrsrToLine(pPam->GetPoint()->nContent.GetIndex());
     679           0 :         nIndx = aLine.GetStart();
     680           0 :         if( pFrm->GetOfst() && !pFrm->IsFollow() && !aLine.GetPrev() )
     681             :         {
     682           0 :             sw_ChangeOffset( pFrm, 0 );
     683           0 :             nIndx = 0;
     684           0 :         }
     685             :     }
     686           0 :     pPam->GetPoint()->nContent = SwIndex( pFrm->GetTxtNode(), nIndx );
     687           0 :     SwTxtCursor::SetRightMargin( false );
     688           0 :     return true;
     689             : }
     690             : 
     691             : /*
     692             :  * To the line end: That's the position before the last char of the line.
     693             :  * Exception: In the last line, it should be able to place the cursor after
     694             :  * the last char in order to append text.
     695             :  */
     696             : 
     697           0 : bool SwTxtFrm::RightMargin(SwPaM *pPam, bool bAPI) const
     698             : {
     699           0 :     if( &pPam->GetNode() != GetNode() )
     700           0 :         pPam->GetPoint()->nNode = *((SwTxtFrm*)this)->GetTxtNode();
     701             : 
     702           0 :     SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *pPam->GetPoint(),
     703           0 :                                      SwTxtCursor::IsRightMargin() );
     704           0 :     pFrm->GetFormatted();
     705             :     sal_Int32 nRightMargin;
     706           0 :     if ( IsEmpty() )
     707           0 :         nRightMargin = 0;
     708             :     else
     709             :     {
     710           0 :         SwTxtSizeInfo aInf( pFrm );
     711           0 :         SwTxtCursor  aLine( pFrm, &aInf );
     712             : 
     713           0 :         aLine.CharCrsrToLine(pPam->GetPoint()->nContent.GetIndex());
     714           0 :         nRightMargin = aLine.GetStart() + aLine.GetCurr()->GetLen();
     715             : 
     716             :         // We skip hard line brakes
     717           0 :         if( aLine.GetCurr()->GetLen() &&
     718           0 :             CH_BREAK == aInf.GetTxt()[nRightMargin - 1])
     719           0 :             --nRightMargin;
     720           0 :         else if( !bAPI && (aLine.GetNext() || pFrm->GetFollow()) )
     721             :         {
     722           0 :             while( nRightMargin > aLine.GetStart() &&
     723           0 :                 ' ' == aInf.GetTxt()[nRightMargin - 1])
     724           0 :                 --nRightMargin;
     725           0 :         }
     726             :     }
     727           0 :     pPam->GetPoint()->nContent = SwIndex( pFrm->GetTxtNode(), nRightMargin );
     728           0 :     SwTxtCursor::SetRightMargin( !bAPI );
     729           0 :     return true;
     730             : }
     731             : 
     732             : // The following two methods try to put the Crsr into the next/succsessive
     733             : // line. If we do not have a preceding/successive line we forward the call
     734             : // to the base class.
     735             : // The Crsr's horizontal justification is done afterwards by the CrsrShell.
     736             : 
     737             : class SwSetToRightMargin
     738             : {
     739             :     bool bRight;
     740             : public:
     741           4 :     inline SwSetToRightMargin() : bRight( false ) { }
     742           4 :     inline ~SwSetToRightMargin() { SwTxtCursor::SetRightMargin( bRight ); }
     743           0 :     inline void SetRight( const bool bNew ) { bRight = bNew; }
     744             : };
     745             : 
     746           4 : bool SwTxtFrm::_UnitUp( SwPaM *pPam, const SwTwips nOffset,
     747             :                         bool bSetInReadOnly ) const
     748             : {
     749             :     // Set the RightMargin if needed
     750           4 :     SwSetToRightMargin aSet;
     751             : 
     752           8 :     if( IsInTab() &&
     753           4 :         pPam->GetNode( true ).StartOfSectionNode() !=
     754           4 :         pPam->GetNode( false ).StartOfSectionNode() )
     755             :     {
     756             :         // If the PaM is located within different boxes, we have a table selection,
     757             :         // which is handled by the base class.
     758           0 :         return SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
     759             :     }
     760             : 
     761           4 :     ((SwTxtFrm*)this)->GetFormatted();
     762           4 :     const sal_Int32 nPos = pPam->GetPoint()->nContent.GetIndex();
     763           4 :     SwRect aCharBox;
     764             : 
     765           4 :     if( !IsEmpty() && !IsHiddenNow() )
     766             :     {
     767           0 :         sal_Int32 nFormat = COMPLETE_STRING;
     768             :         do
     769             :         {
     770           0 :             if( nFormat != COMPLETE_STRING && !IsFollow() )
     771           0 :                 sw_ChangeOffset( ((SwTxtFrm*)this), nFormat );
     772             : 
     773           0 :             SwTxtSizeInfo aInf( (SwTxtFrm*)this );
     774           0 :             SwTxtCursor  aLine( ((SwTxtFrm*)this), &aInf );
     775             : 
     776             :             // Optimize away flys with no flow and IsDummy()
     777           0 :             if( nPos )
     778           0 :                 aLine.CharCrsrToLine( nPos );
     779             :             else
     780           0 :                 aLine.Top();
     781             : 
     782           0 :             const SwLineLayout *pPrevLine = aLine.GetPrevLine();
     783           0 :             const sal_Int32 nStart = aLine.GetStart();
     784           0 :             aLine.GetCharRect( &aCharBox, nPos );
     785             : 
     786           0 :             bool bSecondOfDouble = ( aInf.IsMulti() && ! aInf.IsFirstMulti() );
     787           0 :             bool bPrevLine = ( pPrevLine && pPrevLine != aLine.GetCurr() );
     788             : 
     789           0 :             if( !pPrevLine && !bSecondOfDouble && GetOfst() && !IsFollow() )
     790             :             {
     791           0 :                 nFormat = GetOfst();
     792           0 :                 sal_Int32 nDiff = aLine.GetLength();
     793           0 :                 if( !nDiff )
     794           0 :                     nDiff = MIN_OFFSET_STEP;
     795           0 :                 if( nFormat > nDiff )
     796           0 :                     nFormat = nFormat - nDiff;
     797             :                 else
     798           0 :                     nFormat = 0;
     799           0 :                 continue;
     800             :             }
     801             : 
     802             :             // We select the target line for the cursor, in case we are in a
     803             :             // double line portion, prev line = curr line
     804           0 :             if( bPrevLine && !bSecondOfDouble )
     805             :             {
     806           0 :                 aLine.PrevLine();
     807           0 :                 while ( aLine.GetStart() == nStart &&
     808           0 :                         0 != ( pPrevLine = aLine.GetPrevLine() ) &&
     809           0 :                         pPrevLine != aLine.GetCurr() )
     810           0 :                     aLine.PrevLine();
     811             :             }
     812             : 
     813           0 :             if ( bPrevLine || bSecondOfDouble )
     814             :             {
     815           0 :                 aCharBox.SSize().Width() /= 2;
     816           0 :                 aCharBox.Pos().X() = aCharBox.Pos().X() - 150;
     817             : 
     818             :                 // See comment in SwTxtFrm::GetCrsrOfst()
     819             : #if OSL_DEBUG_LEVEL > 0
     820             :                 const sal_uLong nOldNode = pPam->GetPoint()->nNode.GetIndex();
     821             : #endif
     822             :                 // The node should not be changed
     823             :                 sal_Int32 nTmpOfst = aLine.GetCrsrOfst( pPam->GetPoint(),
     824           0 :                                                          aCharBox.Pos(), false );
     825             : #if OSL_DEBUG_LEVEL > 0
     826             :                 OSL_ENSURE( nOldNode == pPam->GetPoint()->nNode.GetIndex(),
     827             :                         "SwTxtFrm::UnitUp: illegal node change" );
     828             : #endif
     829             : 
     830             :                 // We make sure that we move up.
     831           0 :                 if( nTmpOfst >= nStart && nStart && !bSecondOfDouble )
     832             :                 {
     833           0 :                     nTmpOfst = nStart;
     834           0 :                     aSet.SetRight( true );
     835             :                 }
     836           0 :                 pPam->GetPoint()->nContent =
     837           0 :                       SwIndex( ((SwTxtFrm*)this)->GetTxtNode(), nTmpOfst );
     838           0 :                 return true;
     839             :             }
     840             : 
     841           0 :             if ( IsFollow() )
     842             :             {
     843           0 :                 aLine.GetCharRect( &aCharBox, nPos );
     844           0 :                 aCharBox.SSize().Width() /= 2;
     845             :             }
     846           0 :             break;
     847           0 :         } while ( true );
     848             :     }
     849             :     /* If 'this' is a follow and a prev failed, we need to go to the
     850             :      * last line of the master, which is us.
     851             :      * Or: If we are a follow with follow, we need to get the master.
     852             :      */
     853           4 :     if ( IsFollow() )
     854             :     {
     855           0 :         const SwTxtFrm *pTmpPrev = FindMaster();
     856           0 :         sal_Int32 nOffs = GetOfst();
     857           0 :         if( pTmpPrev )
     858             :         {
     859           0 :             SwViewShell *pSh = getRootFrm()->GetCurrShell();
     860           0 :             const bool bProtectedAllowed = pSh && pSh->GetViewOptions()->IsCursorInProtectedArea();
     861           0 :             const SwTxtFrm *pPrevPrev = pTmpPrev;
     862             :             // We skip protected frames and frames without content here
     863           0 :             while( pPrevPrev && ( pPrevPrev->GetOfst() == nOffs ||
     864           0 :                    ( !bProtectedAllowed && pPrevPrev->IsProtected() ) ) )
     865             :             {
     866           0 :                 pTmpPrev = pPrevPrev;
     867           0 :                 nOffs = pTmpPrev->GetOfst();
     868           0 :                 if ( pPrevPrev->IsFollow() )
     869           0 :                     pPrevPrev = pTmpPrev->FindMaster();
     870             :                 else
     871           0 :                     pPrevPrev = NULL;
     872             :             }
     873           0 :             if ( !pPrevPrev )
     874           0 :                 return pTmpPrev->SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
     875           0 :             aCharBox.Pos().Y() = pPrevPrev->Frm().Bottom() - 1;
     876           0 :             return pPrevPrev->GetKeyCrsrOfst( pPam->GetPoint(), aCharBox.Pos() );
     877             :         }
     878             :     }
     879           4 :     return SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
     880             : }
     881             : 
     882             : // Used for Bidi. nPos is the logical position in the string, bLeft indicates
     883             : // if left arrow or right arrow was pressed. The return values are:
     884             : // nPos: the new visual position
     885             : // bLeft: whether the break iterator has to add or subtract from the
     886             : //        current position
     887           0 : static void lcl_VisualMoveRecursion( const SwLineLayout& rCurrLine, sal_Int32 nIdx,
     888             :                               sal_Int32& nPos, bool& bRight,
     889             :                               sal_uInt8& nCrsrLevel, sal_uInt8 nDefaultDir )
     890             : {
     891           0 :     const SwLinePortion* pPor = rCurrLine.GetFirstPortion();
     892           0 :     const SwLinePortion* pLast = 0;
     893             : 
     894             :     // What's the current portion?
     895           0 :     while ( pPor && nIdx + pPor->GetLen() <= nPos )
     896             :     {
     897           0 :         nIdx = nIdx + pPor->GetLen();
     898           0 :         pLast = pPor;
     899           0 :         pPor = pPor->GetPortion();
     900             :     }
     901             : 
     902           0 :     if ( bRight )
     903             :     {
     904           0 :         bool bRecurse = pPor && pPor->IsMultiPortion() &&
     905           0 :                            ((SwMultiPortion*)pPor)->IsBidi();
     906             : 
     907             :         // 1. special case: at beginning of bidi portion
     908           0 :         if ( bRecurse && nIdx == nPos )
     909             :         {
     910           0 :             nPos = nPos + pPor->GetLen();
     911             : 
     912             :             // leave bidi portion
     913           0 :             if ( nCrsrLevel != nDefaultDir )
     914             :             {
     915           0 :                 bRecurse = false;
     916             :             }
     917             :             else
     918             :                 // special case:
     919             :                 // buffer: abcXYZ123 in LTR paragraph
     920             :                 // view:   abc123ZYX
     921             :                 // cursor is between c and X in the buffer and cursor level = 0
     922           0 :                 nCrsrLevel++;
     923             :         }
     924             : 
     925             :         // 2. special case: at beginning of portion after bidi portion
     926           0 :         else if ( pLast && pLast->IsMultiPortion() &&
     927           0 :                  ((SwMultiPortion*)pLast)->IsBidi() && nIdx == nPos )
     928             :         {
     929             :             // enter bidi portion
     930           0 :             if ( nCrsrLevel != nDefaultDir )
     931             :             {
     932           0 :                 bRecurse = true;
     933           0 :                 nIdx = nIdx - pLast->GetLen();
     934           0 :                 pPor = pLast;
     935             :             }
     936             :         }
     937             : 
     938             :         // Recursion
     939           0 :         if ( bRecurse )
     940             :         {
     941           0 :             const SwLineLayout& rLine = ((SwMultiPortion*)pPor)->GetRoot();
     942           0 :             sal_Int32 nTmpPos = nPos - nIdx;
     943           0 :             bool bTmpForward = ! bRight;
     944           0 :             sal_uInt8 nTmpCrsrLevel = nCrsrLevel;
     945             :             lcl_VisualMoveRecursion( rLine, 0, nTmpPos, bTmpForward,
     946           0 :                                      nTmpCrsrLevel, nDefaultDir + 1 );
     947             : 
     948           0 :             nPos = nTmpPos + nIdx;
     949           0 :             bRight = bTmpForward;
     950           0 :             nCrsrLevel = nTmpCrsrLevel;
     951             :         }
     952             : 
     953             :         // go forward
     954             :         else
     955             :         {
     956           0 :             bRight = true;
     957           0 :             nCrsrLevel = nDefaultDir;
     958             :         }
     959             : 
     960             :     }
     961             :     else
     962             :     {
     963           0 :         bool bRecurse = pPor && pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi();
     964             : 
     965             :         // 1. special case: at beginning of bidi portion
     966           0 :         if ( bRecurse && nIdx == nPos )
     967             :         {
     968             :             // leave bidi portion
     969           0 :             if ( nCrsrLevel == nDefaultDir )
     970             :             {
     971           0 :                 bRecurse = false;
     972             :             }
     973             :         }
     974             : 
     975             :         // 2. special case: at beginning of portion after bidi portion
     976           0 :         else if ( pLast && pLast->IsMultiPortion() &&
     977           0 :                  ((SwMultiPortion*)pLast)->IsBidi() && nIdx == nPos )
     978             :         {
     979           0 :             nPos = nPos - pLast->GetLen();
     980             : 
     981             :             // enter bidi portion
     982           0 :             if ( nCrsrLevel % 2 == nDefaultDir % 2 )
     983             :             {
     984           0 :                 bRecurse = true;
     985           0 :                 nIdx = nIdx - pLast->GetLen();
     986           0 :                 pPor = pLast;
     987             : 
     988             :                 // special case:
     989             :                 // buffer: abcXYZ123 in LTR paragraph
     990             :                 // view:   abc123ZYX
     991             :                 // cursor is behind 3 in the buffer and cursor level = 2
     992           0 :                 if ( nDefaultDir + 2 == nCrsrLevel )
     993           0 :                     nPos = nPos + pLast->GetLen();
     994             :             }
     995             :         }
     996             : 
     997             :         // go forward
     998           0 :         if ( bRecurse )
     999             :         {
    1000           0 :             const SwLineLayout& rLine = ((SwMultiPortion*)pPor)->GetRoot();
    1001           0 :             sal_Int32 nTmpPos = nPos - nIdx;
    1002           0 :             bool bTmpForward = ! bRight;
    1003           0 :             sal_uInt8 nTmpCrsrLevel = nCrsrLevel;
    1004             :             lcl_VisualMoveRecursion( rLine, 0, nTmpPos, bTmpForward,
    1005           0 :                                      nTmpCrsrLevel, nDefaultDir + 1 );
    1006             : 
    1007             :             // special case:
    1008             :             // buffer: abcXYZ123 in LTR paragraph
    1009             :             // view:   abc123ZYX
    1010             :             // cursor is between Z and 1 in the buffer and cursor level = 2
    1011           0 :             if ( nTmpPos == pPor->GetLen() && nTmpCrsrLevel == nDefaultDir + 1 )
    1012             :             {
    1013           0 :                 nTmpPos = nTmpPos - pPor->GetLen();
    1014           0 :                 nTmpCrsrLevel = nDefaultDir;
    1015           0 :                 bTmpForward = ! bTmpForward;
    1016             :             }
    1017             : 
    1018           0 :             nPos = nTmpPos + nIdx;
    1019           0 :             bRight = bTmpForward;
    1020           0 :             nCrsrLevel = nTmpCrsrLevel;
    1021             :         }
    1022             : 
    1023             :         // go backward
    1024             :         else
    1025             :         {
    1026           0 :             bRight = false;
    1027           0 :             nCrsrLevel = nDefaultDir;
    1028             :         }
    1029             :     }
    1030           0 : }
    1031             : 
    1032           0 : void SwTxtFrm::PrepareVisualMove( sal_Int32& nPos, sal_uInt8& nCrsrLevel,
    1033             :                                   bool& bForward, bool bInsertCrsr )
    1034             : {
    1035           0 :     if( IsEmpty() || IsHiddenNow() )
    1036           0 :         return;
    1037             : 
    1038           0 :     ((SwTxtFrm*)this)->GetFormatted();
    1039             : 
    1040           0 :     SwTxtSizeInfo aInf( (SwTxtFrm*)this );
    1041           0 :     SwTxtCursor  aLine( ((SwTxtFrm*)this), &aInf );
    1042             : 
    1043           0 :     if( nPos )
    1044           0 :         aLine.CharCrsrToLine( nPos );
    1045             :     else
    1046           0 :         aLine.Top();
    1047             : 
    1048           0 :     const SwLineLayout* pLine = aLine.GetCurr();
    1049           0 :     const sal_Int32 nStt = aLine.GetStart();
    1050           0 :     const sal_Int32 nLen = pLine->GetLen();
    1051             : 
    1052             :     // We have to distinguish between an insert and overwrite cursor:
    1053             :     // The insert cursor position depends on the cursor level:
    1054             :     // buffer:  abcXYZdef in LTR paragraph
    1055             :     // display: abcZYXdef
    1056             :     // If cursor is between c and X in the buffer and cursor level is 0,
    1057             :     // the cursor blinks between c and Z and -> sets the cursor between Z and Y.
    1058             :     // If the cursor level is 1, the cursor blinks between X and d and
    1059             :     // -> sets the cursor between d and e.
    1060             :     // The overwrite cursor simply travels to the next visual character.
    1061           0 :     if ( bInsertCrsr )
    1062             :     {
    1063             :         lcl_VisualMoveRecursion( *pLine, nStt, nPos, bForward,
    1064           0 :                                  nCrsrLevel, IsRightToLeft() ? 1 : 0 );
    1065           0 :         return;
    1066             :     }
    1067             : 
    1068           0 :     const sal_uInt8 nDefaultDir = static_cast<sal_uInt8>(IsRightToLeft() ? UBIDI_RTL : UBIDI_LTR);
    1069           0 :     const bool bVisualRight = ( nDefaultDir == UBIDI_LTR && bForward ) ||
    1070           0 :                                   ( nDefaultDir == UBIDI_RTL && ! bForward );
    1071             : 
    1072             :     // Bidi functions from icu 2.0
    1073             : 
    1074           0 :     const sal_Unicode* pLineString = GetTxtNode()->GetTxt().getStr();
    1075             : 
    1076           0 :     UErrorCode nError = U_ZERO_ERROR;
    1077           0 :     UBiDi* pBidi = ubidi_openSized( nLen, 0, &nError );
    1078           0 :     ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(pLineString), nLen, nDefaultDir, NULL, &nError ); // UChar != sal_Unicode in MinGW
    1079             : 
    1080           0 :     sal_Int32 nTmpPos = 0;
    1081           0 :     bool bOutOfBounds = false;
    1082             : 
    1083           0 :     if ( nPos < nStt + nLen )
    1084             :     {
    1085           0 :         nTmpPos = ubidi_getVisualIndex( pBidi, nPos, &nError );
    1086             : 
    1087             :         // visual indices are always LTR aligned
    1088           0 :         if ( bVisualRight )
    1089             :         {
    1090           0 :             if ( nTmpPos + 1 < nStt + nLen )
    1091           0 :                 ++nTmpPos;
    1092             :             else
    1093             :             {
    1094           0 :                 nPos = nDefaultDir == UBIDI_RTL ? 0 : nStt + nLen;
    1095           0 :                 bOutOfBounds = true;
    1096             :             }
    1097             :         }
    1098             :         else
    1099             :         {
    1100           0 :             if ( nTmpPos )
    1101           0 :                 --nTmpPos;
    1102             :             else
    1103             :             {
    1104           0 :                 nPos = nDefaultDir == UBIDI_RTL ? nStt + nLen : 0;
    1105           0 :                 bOutOfBounds = true;
    1106             :             }
    1107             :         }
    1108             :     }
    1109             :     else
    1110             :     {
    1111           0 :         nTmpPos = nDefaultDir == UBIDI_LTR ? nPos - 1 : 0;
    1112             :     }
    1113             : 
    1114           0 :     if ( ! bOutOfBounds )
    1115             :     {
    1116           0 :         nPos = ubidi_getLogicalIndex( pBidi, nTmpPos, &nError );
    1117             : 
    1118           0 :         if ( bForward )
    1119             :         {
    1120           0 :             if ( nPos )
    1121           0 :                 --nPos;
    1122             :             else
    1123             :             {
    1124           0 :                 ++nPos;
    1125           0 :                 bForward = ! bForward;
    1126             :             }
    1127             :         }
    1128             :         else
    1129           0 :             ++nPos;
    1130             :     }
    1131             : 
    1132           0 :     ubidi_close( pBidi );
    1133             : }
    1134             : 
    1135           2 : bool SwTxtFrm::_UnitDown(SwPaM *pPam, const SwTwips nOffset,
    1136             :                          bool bSetInReadOnly ) const
    1137             : {
    1138             : 
    1139           4 :     if ( IsInTab() &&
    1140           2 :         pPam->GetNode( true ).StartOfSectionNode() !=
    1141           2 :         pPam->GetNode( false ).StartOfSectionNode() )
    1142             :     {
    1143             :         // If the PaM is located within different boxes, we have a table selection,
    1144             :         // which is handled by the base class.
    1145           0 :         return SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
    1146             :     }
    1147           2 :     ((SwTxtFrm*)this)->GetFormatted();
    1148           2 :     const sal_Int32 nPos = pPam->GetPoint()->nContent.GetIndex();
    1149           2 :     SwRect aCharBox;
    1150           2 :     const SwCntntFrm *pTmpFollow = 0;
    1151             : 
    1152           2 :     if ( IsVertical() )
    1153           0 :         ((SwTxtFrm*)this)->SwapWidthAndHeight();
    1154             : 
    1155           2 :     if ( !IsEmpty() && !IsHiddenNow() )
    1156             :     {
    1157           2 :         sal_Int32 nFormat = COMPLETE_STRING;
    1158             :         do
    1159             :         {
    1160           2 :             if( nFormat != COMPLETE_STRING && !IsFollow() &&
    1161           0 :                 !sw_ChangeOffset( ((SwTxtFrm*)this), nFormat ) )
    1162           2 :                 break;
    1163             : 
    1164           2 :             SwTxtSizeInfo aInf( (SwTxtFrm*)this );
    1165           2 :             SwTxtCursor  aLine( ((SwTxtFrm*)this), &aInf );
    1166           2 :             nFormat = aLine.GetEnd();
    1167             : 
    1168           2 :             aLine.CharCrsrToLine( nPos );
    1169             : 
    1170           2 :             const SwLineLayout* pNextLine = aLine.GetNextLine();
    1171           2 :             const sal_Int32 nStart = aLine.GetStart();
    1172           2 :             aLine.GetCharRect( &aCharBox, nPos );
    1173             : 
    1174           2 :             bool bFirstOfDouble = ( aInf.IsMulti() && aInf.IsFirstMulti() );
    1175             : 
    1176           2 :             if( pNextLine || bFirstOfDouble )
    1177             :             {
    1178           0 :                 aCharBox.SSize().Width() /= 2;
    1179             : #if OSL_DEBUG_LEVEL > 0
    1180             :                 // See comment in SwTxtFrm::GetCrsrOfst()
    1181             :                 const sal_uLong nOldNode = pPam->GetPoint()->nNode.GetIndex();
    1182             : #endif
    1183           0 :                 if ( pNextLine && ! bFirstOfDouble )
    1184           0 :                     aLine.NextLine();
    1185             : 
    1186             :                 sal_Int32 nTmpOfst = aLine.GetCrsrOfst( pPam->GetPoint(),
    1187           0 :                                  aCharBox.Pos(), false );
    1188             : #if OSL_DEBUG_LEVEL > 0
    1189             :                 OSL_ENSURE( nOldNode == pPam->GetPoint()->nNode.GetIndex(),
    1190             :                     "SwTxtFrm::UnitDown: illegal node change" );
    1191             : #endif
    1192             : 
    1193             :                 // We make sure that we move down.
    1194           0 :                 if( nTmpOfst <= nStart && ! bFirstOfDouble )
    1195           0 :                     nTmpOfst = nStart + 1;
    1196           0 :                 pPam->GetPoint()->nContent =
    1197           0 :                       SwIndex( ((SwTxtFrm*)this)->GetTxtNode(), nTmpOfst );
    1198             : 
    1199           0 :                 if ( IsVertical() )
    1200           0 :                     ((SwTxtFrm*)this)->SwapWidthAndHeight();
    1201             : 
    1202           0 :                 return true;
    1203             :             }
    1204           2 :             if( 0 != ( pTmpFollow = GetFollow() ) )
    1205             :             {   // Skip protected follows
    1206           0 :                 const SwCntntFrm* pTmp = pTmpFollow;
    1207           0 :                 SwViewShell *pSh = getRootFrm()->GetCurrShell();
    1208           0 :                 if( !pSh || !pSh->GetViewOptions()->IsCursorInProtectedArea() )
    1209             :                 {
    1210           0 :                     while( pTmpFollow && pTmpFollow->IsProtected() )
    1211             :                     {
    1212           0 :                         pTmp = pTmpFollow;
    1213           0 :                         pTmpFollow = pTmpFollow->GetFollow();
    1214             :                     }
    1215             :                 }
    1216           0 :                 if( !pTmpFollow ) // Only protected ones left
    1217             :                 {
    1218           0 :                     if ( IsVertical() )
    1219           0 :                         ((SwTxtFrm*)this)->SwapWidthAndHeight();
    1220           0 :                     return pTmp->SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
    1221             :                 }
    1222             : 
    1223           0 :                 aLine.GetCharRect( &aCharBox, nPos );
    1224           0 :                 aCharBox.SSize().Width() /= 2;
    1225             :             }
    1226           2 :             else if( !IsFollow() )
    1227             :             {
    1228           2 :                 sal_Int32 nTmpLen = aInf.GetTxt().getLength();
    1229           2 :                 if( aLine.GetEnd() < nTmpLen )
    1230             :                 {
    1231           0 :                     if( nFormat <= GetOfst() )
    1232             :                     {
    1233           0 :                         nFormat = std::min( sal_Int32( GetOfst() + MIN_OFFSET_STEP ),
    1234           0 :                                        static_cast<sal_Int32>(nTmpLen) );
    1235           0 :                         if( nFormat <= GetOfst() )
    1236           0 :                             break;
    1237             :                     }
    1238           0 :                     continue;
    1239             :                 }
    1240             :             }
    1241           2 :             break;
    1242           0 :         } while( true );
    1243             :     }
    1244             :     else
    1245           0 :         pTmpFollow = GetFollow();
    1246             : 
    1247           2 :     if ( IsVertical() )
    1248           0 :         ((SwTxtFrm*)this)->SwapWidthAndHeight();
    1249             : 
    1250             :     // We take a shortcut for follows
    1251           2 :     if( pTmpFollow )
    1252             :     {
    1253           0 :         aCharBox.Pos().Y() = pTmpFollow->Frm().Top() + 1;
    1254             :         return ((SwTxtFrm*)pTmpFollow)->GetKeyCrsrOfst( pPam->GetPoint(),
    1255           0 :                                                      aCharBox.Pos() );
    1256             :     }
    1257           2 :     return SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
    1258             : }
    1259             : 
    1260           4 : bool SwTxtFrm::UnitUp(SwPaM *pPam, const SwTwips nOffset,
    1261             :                       bool bSetInReadOnly ) const
    1262             : {
    1263             :     /* We call CntntNode::GertFrm() in CrsrSh::Up().
    1264             :      * This _always returns the master.
    1265             :      * In order to not mess with cursor travelling, we correct here
    1266             :      * in SwTxtFrm.
    1267             :      * We calculate UnitUp for pFrm. pFrm is either a master (= this) or a
    1268             :      * follow (!= this).
    1269             :      */
    1270           4 :     const SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *(pPam->GetPoint()),
    1271           8 :                                            SwTxtCursor::IsRightMargin() );
    1272           4 :     const bool bRet = pFrm->_UnitUp( pPam, nOffset, bSetInReadOnly );
    1273             : 
    1274             :     // No SwTxtCursor::SetRightMargin( false );
    1275             :     // Instead we have a SwSetToRightMargin in _UnitUp
    1276           4 :     return bRet;
    1277             : }
    1278             : 
    1279           2 : bool SwTxtFrm::UnitDown(SwPaM *pPam, const SwTwips nOffset,
    1280             :                         bool bSetInReadOnly ) const
    1281             : {
    1282           2 :     const SwTxtFrm *pFrm = GetAdjFrmAtPos((SwTxtFrm*)this, *(pPam->GetPoint()),
    1283           4 :                                            SwTxtCursor::IsRightMargin() );
    1284           2 :     const bool bRet = pFrm->_UnitDown( pPam, nOffset, bSetInReadOnly );
    1285           2 :     SwTxtCursor::SetRightMargin( false );
    1286           2 :     return bRet;
    1287             : }
    1288             : 
    1289           0 : void SwTxtFrm::FillCrsrPos( SwFillData& rFill ) const
    1290             : {
    1291           0 :     if( !rFill.bColumn && GetUpper()->IsColBodyFrm() ) // ColumnFrms now with BodyFrm
    1292             :     {
    1293             :         const SwColumnFrm* pTmp =
    1294           0 :             (SwColumnFrm*)GetUpper()->GetUpper()->GetUpper()->Lower(); // The 1st column
    1295             :         // The first SwFrm in BodyFrm of the first column
    1296           0 :         const SwFrm* pFrm = ((SwLayoutFrm*)pTmp->Lower())->Lower();
    1297           0 :         sal_uInt16 nNextCol = 0;
    1298             :         // In which column do we end up in?
    1299           0 :         while( rFill.X() > pTmp->Frm().Right() && pTmp->GetNext() )
    1300             :         {
    1301           0 :             pTmp = (SwColumnFrm*)pTmp->GetNext();
    1302           0 :             if( ((SwLayoutFrm*)pTmp->Lower())->Lower() ) // ColumnFrms now with BodyFrm
    1303             :             {
    1304           0 :                 pFrm = ((SwLayoutFrm*)pTmp->Lower())->Lower();
    1305           0 :                 nNextCol = 0;
    1306             :             }
    1307             :             else
    1308           0 :                 ++nNextCol; // Empty columns require column brakes
    1309             :         }
    1310           0 :         if( pTmp != GetUpper()->GetUpper() ) // Did we end up in another column?
    1311             :         {
    1312           0 :             if( !pFrm )
    1313           0 :                 return;
    1314           0 :             if( nNextCol )
    1315             :             {
    1316           0 :                 while( pFrm->GetNext() )
    1317           0 :                     pFrm = pFrm->GetNext();
    1318             :             }
    1319             :             else
    1320             :             {
    1321           0 :                 while( pFrm->GetNext() && pFrm->Frm().Bottom() < rFill.Y() )
    1322           0 :                     pFrm = pFrm->GetNext();
    1323             :             }
    1324             :             // No filling, if the last frame in the targeted column does
    1325             :             // not contain a paragraph, but e.g. a table
    1326           0 :             if( pFrm->IsTxtFrm() )
    1327             :             {
    1328           0 :                 rFill.Fill().nColumnCnt = nNextCol;
    1329           0 :                 rFill.bColumn = true;
    1330           0 :                 if( rFill.pPos )
    1331             :                 {
    1332           0 :                     SwTxtNode* pTxtNd = ((SwTxtFrm*)pFrm)->GetTxtNode();
    1333           0 :                     rFill.pPos->nNode = *pTxtNd;
    1334             :                     rFill.pPos->nContent.Assign(
    1335           0 :                             pTxtNd, pTxtNd->GetTxt().getLength());
    1336             :                 }
    1337           0 :                 if( nNextCol )
    1338             :                 {
    1339           0 :                     rFill.aFrm = pTmp->Prt();
    1340           0 :                     rFill.aFrm += pTmp->Frm().Pos();
    1341             :                 }
    1342             :                 else
    1343           0 :                     rFill.aFrm = pFrm->Frm();
    1344           0 :                 ((SwTxtFrm*)pFrm)->FillCrsrPos( rFill );
    1345             :             }
    1346           0 :             return;
    1347             :         }
    1348             :     }
    1349             :     SwFont *pFnt;
    1350           0 :     SwTxtFmtColl* pColl = GetTxtNode()->GetTxtColl();
    1351           0 :     SwTwips nFirst = GetTxtNode()->GetSwAttrSet().GetULSpace().GetLower();
    1352           0 :     SwTwips nDiff = rFill.Y() - Frm().Bottom();
    1353           0 :     if( nDiff < nFirst )
    1354           0 :         nDiff = -1;
    1355             :     else
    1356           0 :         pColl = &pColl->GetNextTxtFmtColl();
    1357           0 :     SwAttrSet aSet( ((SwDoc*)GetTxtNode()->GetDoc())->GetAttrPool(), aTxtFmtCollSetRange );
    1358           0 :     const SwAttrSet* pSet = &pColl->GetAttrSet();
    1359           0 :     SwViewShell *pSh = getRootFrm()->GetCurrShell();
    1360           0 :     if( GetTxtNode()->HasSwAttrSet() )
    1361             :     {
    1362           0 :         aSet.Put( *GetTxtNode()->GetpSwAttrSet() );
    1363           0 :         aSet.SetParent( pSet );
    1364           0 :         pSet = &aSet;
    1365           0 :         pFnt = new SwFont( pSet, GetNode()->getIDocumentSettingAccess() );
    1366             :     }
    1367             :     else
    1368             :     {
    1369           0 :         SwFontAccess aFontAccess( pColl, pSh );
    1370           0 :         pFnt = new SwFont( aFontAccess.Get()->GetFont() );
    1371           0 :         pFnt->ChkMagic( pSh, pFnt->GetActual() );
    1372             :     }
    1373           0 :     OutputDevice* pOut = pSh->GetOut();
    1374           0 :     if( !pSh->GetViewOptions()->getBrowseMode() || pSh->GetViewOptions()->IsPrtFormat() )
    1375           0 :         pOut = GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
    1376             : 
    1377           0 :     pFnt->SetFntChg( true );
    1378           0 :     pFnt->ChgPhysFnt( pSh, *pOut );
    1379             : 
    1380           0 :     SwTwips nLineHeight = pFnt->GetHeight( pSh, *pOut );
    1381             : 
    1382           0 :     bool bFill = false;
    1383           0 :     if( nLineHeight )
    1384             :     {
    1385           0 :         bFill = true;
    1386           0 :         const SvxULSpaceItem &rUL = pSet->GetULSpace();
    1387           0 :         SwTwips nDist = std::max( rUL.GetLower(), rUL.GetUpper() );
    1388           0 :         if( rFill.Fill().nColumnCnt )
    1389             :         {
    1390           0 :             rFill.aFrm.Height( nLineHeight );
    1391           0 :             nDiff = rFill.Y() - rFill.Bottom();
    1392           0 :             nFirst = 0;
    1393             :         }
    1394           0 :         else if( nDist < nFirst )
    1395           0 :             nFirst = nFirst - nDist;
    1396             :         else
    1397           0 :             nFirst = 0;
    1398           0 :         nDist = std::max( nDist, long( GetLineSpace() ) );
    1399           0 :         nDist += nLineHeight;
    1400           0 :         nDiff -= nFirst;
    1401             : 
    1402           0 :         if( nDiff > 0 )
    1403             :         {
    1404           0 :             nDiff /= nDist;
    1405           0 :             rFill.Fill().nParaCnt = static_cast<sal_uInt16>(nDiff + 1);
    1406           0 :             rFill.nLineWidth = 0;
    1407           0 :             rFill.bInner = false;
    1408           0 :             rFill.bEmpty = true;
    1409           0 :             rFill.SetOrient( text::HoriOrientation::LEFT );
    1410             :         }
    1411             :         else
    1412           0 :             nDiff = -1;
    1413           0 :         if( rFill.bInner )
    1414           0 :             bFill = false;
    1415             :         else
    1416             :         {
    1417           0 :             const SvxTabStopItem &rRuler = pSet->GetTabStops();
    1418           0 :             const SvxLRSpaceItem &rLRSpace = pSet->GetLRSpace();
    1419             : 
    1420           0 :             SwRect &rRect = rFill.Fill().aCrsr;
    1421           0 :             rRect.Top( rFill.Bottom() + (nDiff+1) * nDist - nLineHeight );
    1422           0 :             if( nFirst && nDiff > -1 )
    1423           0 :                 rRect.Top( rRect.Top() + nFirst );
    1424           0 :             rRect.Height( nLineHeight );
    1425           0 :             SwTwips nLeft = rFill.Left() + rLRSpace.GetLeft() +
    1426           0 :                             GetTxtNode()->GetLeftMarginWithNum();
    1427           0 :             SwTwips nRight = rFill.Right() - rLRSpace.GetRight();
    1428           0 :             SwTwips nCenter = ( nLeft + nRight ) / 2;
    1429           0 :             rRect.Left( nLeft );
    1430           0 :             if( FILL_MARGIN == rFill.Mode() )
    1431             :             {
    1432           0 :                 if( rFill.bEmpty )
    1433             :                 {
    1434           0 :                     rFill.SetOrient( text::HoriOrientation::LEFT );
    1435           0 :                     if( rFill.X() < nCenter )
    1436             :                     {
    1437           0 :                         if( rFill.X() > ( nLeft + 2 * nCenter ) / 3 )
    1438             :                         {
    1439           0 :                             rFill.SetOrient( text::HoriOrientation::CENTER );
    1440           0 :                             rRect.Left( nCenter );
    1441             :                         }
    1442             :                     }
    1443           0 :                     else if( rFill.X() > ( nRight + 2 * nCenter ) / 3 )
    1444             :                     {
    1445           0 :                         rFill.SetOrient( text::HoriOrientation::RIGHT );
    1446           0 :                         rRect.Left( nRight );
    1447             :                     }
    1448             :                     else
    1449             :                     {
    1450           0 :                         rFill.SetOrient( text::HoriOrientation::CENTER );
    1451           0 :                         rRect.Left( nCenter );
    1452             :                     }
    1453             :                 }
    1454             :                 else
    1455           0 :                     bFill = false;
    1456             :             }
    1457             :             else
    1458             :             {
    1459           0 :                 SwTwips nSpace = 0;
    1460           0 :                 if( FILL_TAB != rFill.Mode() )
    1461             :                 {
    1462           0 :                     const OUString aTmp("  ");
    1463           0 :                     SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTmp, 0, 2 );
    1464           0 :                     nSpace = pFnt->_GetTxtSize( aDrawInf ).Width()/2;
    1465             :                 }
    1466           0 :                 if( rFill.X() >= nRight )
    1467             :                 {
    1468           0 :                     if( FILL_INDENT != rFill.Mode() && ( rFill.bEmpty ||
    1469           0 :                         rFill.X() > rFill.nLineWidth + FILL_MIN_DIST ) )
    1470             :                     {
    1471           0 :                         rFill.SetOrient( text::HoriOrientation::RIGHT );
    1472           0 :                         rRect.Left( nRight );
    1473             :                     }
    1474             :                     else
    1475           0 :                         bFill = false;
    1476             :                 }
    1477           0 :                 else if( FILL_INDENT == rFill.Mode() )
    1478             :                 {
    1479           0 :                     SwTwips nIndent = rFill.X();
    1480           0 :                     if( !rFill.bEmpty || nIndent > nRight )
    1481           0 :                         bFill = false;
    1482             :                     else
    1483             :                     {
    1484           0 :                         nIndent -= rFill.Left();
    1485           0 :                         if( nIndent >= 0 && nSpace )
    1486             :                         {
    1487           0 :                             nIndent /= nSpace;
    1488           0 :                             nIndent *= nSpace;
    1489           0 :                             rFill.SetTab( sal_uInt16( nIndent ) );
    1490           0 :                             rRect.Left( nIndent + rFill.Left() );
    1491             :                         }
    1492             :                         else
    1493           0 :                             bFill = false;
    1494             :                     }
    1495             :                 }
    1496           0 :                 else if( rFill.X() > nLeft )
    1497             :                 {
    1498           0 :                     SwTwips nTxtLeft = rFill.Left() + rLRSpace.GetTxtLeft() +
    1499           0 :                                     GetTxtNode()->GetLeftMarginWithNum( true );
    1500           0 :                     rFill.nLineWidth += rFill.bFirstLine ? nLeft : nTxtLeft;
    1501           0 :                     SwTwips nLeftTab = nLeft;
    1502           0 :                     SwTwips nRightTab = nLeft;
    1503           0 :                     sal_uInt16 nSpaceCnt = 0;
    1504           0 :                     sal_uInt16 nTabCnt = 0;
    1505           0 :                     sal_uInt16 nIdx = 0;
    1506           0 :                     do
    1507             :                     {
    1508           0 :                         nLeftTab = nRightTab;
    1509           0 :                         if( nIdx < rRuler.Count() )
    1510             :                         {
    1511           0 :                             const SvxTabStop &rTabStop = rRuler.operator[](nIdx);
    1512           0 :                             nRightTab = nTxtLeft + rTabStop.GetTabPos();
    1513           0 :                             if( nLeftTab < nTxtLeft && nRightTab > nTxtLeft )
    1514           0 :                                 nRightTab = nTxtLeft;
    1515             :                             else
    1516           0 :                                 ++nIdx;
    1517           0 :                             if( nRightTab > rFill.nLineWidth )
    1518           0 :                                 ++nTabCnt;
    1519             :                         }
    1520             :                         else
    1521             :                         {
    1522             :                             const SvxTabStopItem& rTab =
    1523             :                                 (const SvxTabStopItem &)pSet->
    1524           0 :                                 GetPool()->GetDefaultItem( RES_PARATR_TABSTOP );
    1525           0 :                             const SwTwips nDefTabDist = rTab[0].GetTabPos();
    1526           0 :                             nRightTab = nLeftTab - nTxtLeft;
    1527           0 :                             nRightTab /= nDefTabDist;
    1528           0 :                             nRightTab = nRightTab * nDefTabDist + nTxtLeft;
    1529           0 :                             while ( nRightTab <= nLeftTab )
    1530           0 :                                 nRightTab += nDefTabDist;
    1531           0 :                             if( nRightTab > rFill.nLineWidth )
    1532           0 :                                 ++nTabCnt;
    1533           0 :                             while ( nRightTab < rFill.X() )
    1534             :                             {
    1535           0 :                                 nRightTab += nDefTabDist;
    1536           0 :                                 if( nRightTab > rFill.nLineWidth )
    1537           0 :                                     ++nTabCnt;
    1538             :                             }
    1539           0 :                             if( nLeftTab < nRightTab - nDefTabDist )
    1540           0 :                                 nLeftTab = nRightTab - nDefTabDist;
    1541             :                         }
    1542           0 :                         if( nRightTab > nRight )
    1543           0 :                             nRightTab = nRight;
    1544             :                     }
    1545           0 :                     while( rFill.X() > nRightTab );
    1546           0 :                     --nTabCnt;
    1547           0 :                     if( FILL_TAB != rFill.Mode() )
    1548             :                     {
    1549           0 :                         if( nSpace > 0 )
    1550             :                         {
    1551           0 :                             if( !nTabCnt )
    1552           0 :                                 nLeftTab = rFill.nLineWidth;
    1553           0 :                             while( nLeftTab < rFill.X() )
    1554             :                             {
    1555           0 :                                 nLeftTab += nSpace;
    1556           0 :                                 ++nSpaceCnt;
    1557             :                             }
    1558           0 :                             if( nSpaceCnt )
    1559             :                             {
    1560           0 :                                 nLeftTab -= nSpace;
    1561           0 :                                 --nSpaceCnt;
    1562             :                             }
    1563           0 :                             if( rFill.X() - nLeftTab > nRightTab - rFill.X() )
    1564             :                             {
    1565           0 :                                 nSpaceCnt = 0;
    1566           0 :                                 ++nTabCnt;
    1567           0 :                                 rRect.Left( nRightTab );
    1568             :                             }
    1569             :                             else
    1570             :                             {
    1571           0 :                                 if( rFill.X() - nLeftTab > nSpace/2 )
    1572             :                                 {
    1573           0 :                                     ++nSpaceCnt;
    1574           0 :                                     rRect.Left( nLeftTab + nSpace );
    1575             :                                 }
    1576             :                                 else
    1577           0 :                                     rRect.Left( nLeftTab );
    1578             :                             }
    1579             :                         }
    1580           0 :                         else if( rFill.X() - nLeftTab < nRightTab - rFill.X() )
    1581           0 :                             rRect.Left( nLeftTab );
    1582             :                         else
    1583             :                         {
    1584           0 :                             if( nRightTab >= nRight )
    1585             :                             {
    1586           0 :                                 rFill.SetOrient( text::HoriOrientation::RIGHT );
    1587           0 :                                 rRect.Left( nRight );
    1588           0 :                                 nTabCnt = 0;
    1589           0 :                                 nSpaceCnt = 0;
    1590             :                             }
    1591             :                             else
    1592             :                             {
    1593           0 :                                 rRect.Left( nRightTab );
    1594           0 :                                 ++nTabCnt;
    1595             :                             }
    1596             :                         }
    1597             :                     }
    1598             :                     else
    1599             :                     {
    1600           0 :                         if( rFill.X() - nLeftTab < nRightTab - rFill.X() )
    1601           0 :                             rRect.Left( nLeftTab );
    1602             :                         else
    1603             :                         {
    1604           0 :                             if( nRightTab >= nRight )
    1605             :                             {
    1606           0 :                                 rFill.SetOrient( text::HoriOrientation::RIGHT );
    1607           0 :                                 rRect.Left( nRight );
    1608           0 :                                 nTabCnt = 0;
    1609           0 :                                 nSpaceCnt = 0;
    1610             :                             }
    1611             :                             else
    1612             :                             {
    1613           0 :                                 rRect.Left( nRightTab );
    1614           0 :                                 ++nTabCnt;
    1615             :                             }
    1616             :                         }
    1617             :                     }
    1618           0 :                     rFill.SetTab( nTabCnt );
    1619           0 :                     rFill.SetSpace( nSpaceCnt );
    1620           0 :                     if( bFill )
    1621             :                     {
    1622           0 :                         if( std::abs( rFill.X() - nCenter ) <=
    1623           0 :                             std::abs( rFill.X() - rRect.Left() ) )
    1624             :                         {
    1625           0 :                             rFill.SetOrient( text::HoriOrientation::CENTER );
    1626           0 :                             rFill.SetTab( 0 );
    1627           0 :                             rFill.SetSpace( 0 );
    1628           0 :                             rRect.Left( nCenter );
    1629             :                         }
    1630           0 :                         if( !rFill.bEmpty )
    1631           0 :                             rFill.nLineWidth += FILL_MIN_DIST;
    1632           0 :                         if( rRect.Left() < rFill.nLineWidth )
    1633           0 :                             bFill = false;
    1634             :                     }
    1635             :                 }
    1636             :             }
    1637             :             // Do we extend over the page's/column's/etc. lower edge?
    1638           0 :             const SwFrm* pUp = GetUpper();
    1639           0 :             if( pUp->IsInSct() )
    1640             :             {
    1641           0 :                 if( pUp->IsSctFrm() )
    1642           0 :                     pUp = pUp->GetUpper();
    1643           0 :                 else if( pUp->IsColBodyFrm() &&
    1644           0 :                          pUp->GetUpper()->GetUpper()->IsSctFrm() )
    1645           0 :                     pUp = pUp->GetUpper()->GetUpper()->GetUpper();
    1646             :             }
    1647           0 :             SWRECTFN( this )
    1648           0 :             SwTwips nLimit = (pUp->*fnRect->fnGetPrtBottom)();
    1649           0 :             SwTwips nRectBottom = rRect.Bottom();
    1650           0 :             if ( bVert )
    1651           0 :                 nRectBottom = SwitchHorizontalToVertical( nRectBottom );
    1652             : 
    1653           0 :             if( (*fnRect->fnYDiff)( nLimit, nRectBottom ) < 0 )
    1654           0 :                 bFill = false;
    1655             :             else
    1656           0 :                 rRect.Width( 1 );
    1657             :         }
    1658             :     }
    1659           0 :     ((SwCrsrMoveState*)rFill.pCMS)->bFillRet = bFill;
    1660           0 :     delete pFnt;
    1661         270 : }
    1662             : 
    1663             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10