summaryrefslogtreecommitdiff
path: root/sw/source/core/text/frmcrsr.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/text/frmcrsr.cxx')
-rw-r--r--sw/source/core/text/frmcrsr.cxx1752
1 files changed, 1752 insertions, 0 deletions
diff --git a/sw/source/core/text/frmcrsr.cxx b/sw/source/core/text/frmcrsr.cxx
new file mode 100644
index 000000000000..2f35e82649b5
--- /dev/null
+++ b/sw/source/core/text/frmcrsr.cxx
@@ -0,0 +1,1752 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+#include "ndtxt.hxx" // GetNode()
+#include "pam.hxx" // SwPosition
+#include "frmtool.hxx"
+#include "viewopt.hxx"
+#include "paratr.hxx"
+#include "rootfrm.hxx"
+#include "pagefrm.hxx"
+#include "colfrm.hxx"
+#include "txttypes.hxx"
+#include <sfx2/printer.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/tstpitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <pormulti.hxx> // SwMultiPortion
+#include <doc.hxx>
+#include <sortedobjs.hxx>
+
+#include <unicode/ubidi.h>
+
+#include "txtfrm.hxx" // SwTxtFrm
+#include "inftxt.hxx" // SwTxtSizeInfo
+#include "itrtxt.hxx" // SwTxtCursor
+#include "crstate.hxx" // SwTxtCursor
+#include "viewsh.hxx" // InvalidateWindows
+#include "swfntcch.hxx" // SwFontAccess
+#include "flyfrm.hxx"
+
+#if OSL_DEBUG_LEVEL > 1
+#include "txtpaint.hxx"
+#endif
+
+#define MIN_OFFSET_STEP 10
+
+using namespace ::com::sun::star;
+
+
+/*
+ * 1170-SurvivalKit: Wie gelangt man hinter das letzte Zeichen der Zeile.
+ * - RightMargin verzichtet auf den Positionsausgleich mit -1
+ * - GetCharRect liefert bei MV_RIGHTMARGIN ein GetEndCharRect
+ * - GetEndCharRect setzt bRightMargin auf sal_True
+ * - SwTxtCursor::bRightMargin wird per CharCrsrToLine auf sal_False gesetzt
+ */
+
+/*************************************************************************
+ * GetAdjFrmAtPos()
+ *************************************************************************/
+
+SwTxtFrm *GetAdjFrmAtPos( SwTxtFrm *pFrm, const SwPosition &rPos,
+ const sal_Bool bRightMargin, const sal_Bool bNoScroll = sal_True )
+{
+ // 8810: vgl. 1170, RightMargin in der letzten Masterzeile...
+ const xub_StrLen nOffset = rPos.nContent.GetIndex();
+ SwTxtFrm *pFrmAtPos = pFrm;
+ if( !bNoScroll || pFrm->GetFollow() )
+ {
+ pFrmAtPos = pFrm->GetFrmAtPos( rPos );
+ if( nOffset < pFrmAtPos->GetOfst() &&
+ !pFrmAtPos->IsFollow() )
+ {
+ xub_StrLen nNew = nOffset;
+ if( nNew < MIN_OFFSET_STEP )
+ nNew = 0;
+ else
+ nNew -= MIN_OFFSET_STEP;
+ lcl_ChangeOffset( pFrmAtPos, nNew );
+ }
+ }
+ while( pFrm != pFrmAtPos )
+ {
+ pFrm = pFrmAtPos;
+ pFrm->GetFormatted();
+ pFrmAtPos = (SwTxtFrm*)pFrm->GetFrmAtPos( rPos );
+ }
+
+ if( nOffset && bRightMargin )
+ {
+ while( pFrmAtPos && pFrmAtPos->GetOfst() == nOffset &&
+ pFrmAtPos->IsFollow() )
+ {
+ pFrmAtPos->GetFormatted();
+ pFrmAtPos = pFrmAtPos->FindMaster();
+ }
+ OSL_ENSURE( pFrmAtPos, "+GetCharRect: no frame with my rightmargin" );
+ }
+ return pFrmAtPos ? pFrmAtPos : pFrm;
+}
+
+sal_Bool lcl_ChangeOffset( SwTxtFrm* pFrm, xub_StrLen nNew )
+{
+ // In Bereichen und ausserhalb von Flies wird nicht mehr gescrollt.
+ OSL_ENSURE( !pFrm->IsFollow(), "Illegal Scrolling by Follow!" );
+ if( pFrm->GetOfst() != nNew && !pFrm->IsInSct() )
+ {
+ SwFlyFrm *pFly = pFrm->FindFlyFrm();
+ // Vorsicht, wenn z.B. bei einem spaltigen Rahmen die Groesse noch invalide ist,
+ // duerfen wir nicht mal eben herumscrollen
+ if ( ( pFly && pFly->IsValid() &&
+ !pFly->GetNextLink() && !pFly->GetPrevLink() ) ||
+ ( !pFly && pFrm->IsInTab() ) )
+ {
+ ViewShell* pVsh = pFrm->getRootFrm()->GetCurrShell();
+ if( pVsh )
+ {
+ if( pVsh->GetNext() != pVsh ||
+ ( pFrm->GetDrawObjs() && pFrm->GetDrawObjs()->Count() ) )
+ {
+ if( !pFrm->GetOfst() )
+ return sal_False;
+ nNew = 0;
+ }
+ pFrm->SetOfst( nNew );
+ pFrm->SetPara( 0 );
+ pFrm->GetFormatted();
+ if( pFrm->Frm().HasArea() )
+ pFrm->getRootFrm()->GetCurrShell()->InvalidateWindows( pFrm->Frm() );
+ return sal_True;
+ }
+ }
+ }
+ return sal_False;
+}
+
+/*************************************************************************
+ * GetFrmAtOfst(), GetFrmAtPos()
+ *************************************************************************/
+
+// OD 07.10.2003 #110978#
+SwTxtFrm& SwTxtFrm::GetFrmAtOfst( const xub_StrLen nWhere )
+{
+ SwTxtFrm* pRet = this;
+ while( pRet->HasFollow() && nWhere >= pRet->GetFollow()->GetOfst() )
+ pRet = pRet->GetFollow();
+ return *pRet;
+}
+
+SwTxtFrm *SwTxtFrm::GetFrmAtPos( const SwPosition &rPos )
+{
+ SwTxtFrm *pFoll = (SwTxtFrm*)this;
+ while( pFoll->GetFollow() )
+ {
+ if( rPos.nContent.GetIndex() > pFoll->GetFollow()->GetOfst() )
+ pFoll = pFoll->GetFollow();
+ else
+ {
+ if( rPos.nContent.GetIndex() == pFoll->GetFollow()->GetOfst()
+ && !SwTxtCursor::IsRightMargin() )
+ pFoll = pFoll->GetFollow();
+ else
+ break;
+ }
+ }
+ return pFoll;
+}
+
+/*************************************************************************
+ * SwTxtFrm::GetCharRect()
+ *************************************************************************/
+
+/*
+ * GetCharRect() findet die Characterzelle des Characters, dass
+ * durch aPos beschrieben wird. GetCrsrOfst() findet den
+ * umgekehrten Weg: Von einer Dokumentkoordinate zu einem Pam.
+ * Beide sind virtuell in der Framebasisklasse und werden deshalb
+ * immer angezogen.
+ */
+
+sal_Bool SwTxtFrm::GetCharRect( SwRect& rOrig, const SwPosition &rPos,
+ SwCrsrMoveState *pCMS ) const
+{
+ OSL_ENSURE( ! IsVertical() || ! IsSwapped(),"SwTxtFrm::GetCharRect with swapped frame" );
+
+ if( IsLocked() || IsHiddenNow() )
+ return sal_False;
+
+ //Erstmal den richtigen Frm finden, dabei muss beachtet werden, dass:
+ //- die gecachten Informationen verworfen sein koennen (GetPara() == 0)
+ //- das ein Follow gemeint sein kann
+ //- das die Kette der Follows dynamisch waechst; der in den wir
+ // schliesslich gelangen muss aber Formatiert sein.
+
+ // opt: reading ahead erspart uns ein GetAdjFrmAtPos
+ const sal_Bool bRightMargin = pCMS && ( MV_RIGHTMARGIN == pCMS->eState );
+ const sal_Bool bNoScroll = pCMS && pCMS->bNoScroll;
+ SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, rPos, bRightMargin,
+ bNoScroll );
+ pFrm->GetFormatted();
+ const SwFrm* pTmpFrm = (SwFrm*)pFrm->GetUpper();
+
+ SWRECTFN ( pFrm )
+ const SwTwips nUpperMaxY = (pTmpFrm->*fnRect->fnGetPrtBottom)();
+ const SwTwips nFrmMaxY = (pFrm->*fnRect->fnGetPrtBottom)();
+
+ // nMaxY is an absolute value
+ //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
+ SwTwips nMaxY = bVert ?
+ ( bVertL2R ? Min( nFrmMaxY, nUpperMaxY ) : Max( nFrmMaxY, nUpperMaxY ) ) :
+ Min( nFrmMaxY, nUpperMaxY );
+
+ sal_Bool bRet = sal_False;
+
+ if ( pFrm->IsEmpty() || ! (pFrm->Prt().*fnRect->fnGetHeight)() )
+ {
+ Point aPnt1 = pFrm->Frm().Pos() + pFrm->Prt().Pos();
+ SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
+ short nFirstOffset;
+ pTxtNd->GetFirstLineOfsWithNum( nFirstOffset );
+
+ Point aPnt2;
+ if ( bVert )
+ {
+ if( nFirstOffset > 0 )
+ aPnt1.Y() += nFirstOffset;
+ //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
+ if ( aPnt1.X() < nMaxY && !bVertL2R )
+ aPnt1.X() = nMaxY;
+ aPnt2.X() = aPnt1.X() + pFrm->Prt().Width();
+ aPnt2.Y() = aPnt1.Y();
+ if( aPnt2.X() < nMaxY )
+ aPnt2.X() = nMaxY;
+ }
+ else
+ {
+ if( nFirstOffset > 0 )
+ aPnt1.X() += nFirstOffset;
+
+ if( aPnt1.Y() > nMaxY )
+ aPnt1.Y() = nMaxY;
+ aPnt2.X() = aPnt1.X();
+ aPnt2.Y() = aPnt1.Y() + pFrm->Prt().Height();
+ if( aPnt2.Y() > nMaxY )
+ aPnt2.Y() = nMaxY;
+ }
+
+ rOrig = SwRect( aPnt1, aPnt2 );
+
+ if ( pCMS )
+ {
+ pCMS->aRealHeight.X() = 0;
+ pCMS->aRealHeight.Y() = bVert ? -rOrig.Width() : rOrig.Height();
+ }
+
+ if ( pFrm->IsRightToLeft() )
+ pFrm->SwitchLTRtoRTL( rOrig );
+
+ bRet = sal_True;
+ }
+ else
+ {
+ if( !pFrm->HasPara() )
+ return sal_False;
+
+ SwFrmSwapper aSwapper( pFrm, sal_True );
+ if ( bVert )
+ nMaxY = pFrm->SwitchVerticalToHorizontal( nMaxY );
+
+ sal_Bool bGoOn = sal_True;
+ xub_StrLen nOffset = rPos.nContent.GetIndex();
+ xub_StrLen nNextOfst;
+
+ do
+ {
+ {
+ SwTxtSizeInfo aInf( pFrm );
+ SwTxtCursor aLine( pFrm, &aInf );
+ nNextOfst = aLine.GetEnd();
+ // Siehe Kommentar in AdjustFrm
+ // 1170: das letzte Zeichen der Zeile mitnehmen?
+ bRet = bRightMargin ? aLine.GetEndCharRect( &rOrig, nOffset, pCMS, nMaxY )
+ : aLine.GetCharRect( &rOrig, nOffset, pCMS, nMaxY );
+ }
+
+ if ( pFrm->IsRightToLeft() )
+ pFrm->SwitchLTRtoRTL( rOrig );
+
+ if ( bVert )
+ pFrm->SwitchHorizontalToVertical( rOrig );
+
+ if( pFrm->IsUndersized() && pCMS && !pFrm->GetNext() &&
+ (rOrig.*fnRect->fnGetBottom)() == nUpperMaxY &&
+ pFrm->GetOfst() < nOffset &&
+ !pFrm->IsFollow() && !bNoScroll &&
+ pFrm->GetTxtNode()->GetTxt().Len() != nNextOfst )
+ bGoOn = lcl_ChangeOffset( pFrm, nNextOfst );
+ else
+ bGoOn = sal_False;
+ } while ( bGoOn );
+
+ if ( pCMS )
+ {
+ if ( pFrm->IsRightToLeft() )
+ {
+ if( pCMS->b2Lines && pCMS->p2Lines)
+ {
+ pFrm->SwitchLTRtoRTL( pCMS->p2Lines->aLine );
+ pFrm->SwitchLTRtoRTL( pCMS->p2Lines->aPortion );
+ }
+ }
+
+ if ( bVert )
+ {
+ if ( pCMS->bRealHeight )
+ {
+ pCMS->aRealHeight.Y() = -pCMS->aRealHeight.Y();
+ if ( pCMS->aRealHeight.Y() < 0 )
+ {
+ // writing direction is from top to bottom
+ pCMS->aRealHeight.X() = ( rOrig.Width() -
+ pCMS->aRealHeight.X() +
+ pCMS->aRealHeight.Y() );
+ }
+ }
+ if( pCMS->b2Lines && pCMS->p2Lines)
+ {
+ pFrm->SwitchHorizontalToVertical( pCMS->p2Lines->aLine );
+ pFrm->SwitchHorizontalToVertical( pCMS->p2Lines->aPortion );
+ }
+ }
+
+ }
+ }
+ if( bRet )
+ {
+ SwPageFrm *pPage = pFrm->FindPageFrm();
+ OSL_ENSURE( pPage, "Text esaped from page?" );
+ const SwTwips nOrigTop = (rOrig.*fnRect->fnGetTop)();
+ const SwTwips nPageTop = (pPage->Frm().*fnRect->fnGetTop)();
+ const SwTwips nPageBott = (pPage->Frm().*fnRect->fnGetBottom)();
+
+ // Following situation: if the frame is in an invalid sectionframe,
+ // it's possible that the frame is outside the page. If we restrict
+ // the cursor position to the page area, we enforce the formatting
+ // of the page, of the section frame and the frame himself.
+ if( (*fnRect->fnYDiff)( nPageTop, nOrigTop ) > 0 )
+ (rOrig.*fnRect->fnSetTop)( nPageTop );
+
+ if ( (*fnRect->fnYDiff)( nOrigTop, nPageBott ) > 0 )
+ (rOrig.*fnRect->fnSetTop)( nPageBott );
+ }
+
+ return bRet;
+}
+
+/*************************************************************************
+ * SwTxtFrm::GetAutoPos()
+ *************************************************************************/
+
+/*
+ * GetAutoPos() findet die Characterzelle des Characters, dass
+ * durch aPos beschrieben wird und wird von autopositionierten Rahmen genutzt.
+ */
+
+sal_Bool SwTxtFrm::GetAutoPos( SwRect& rOrig, const SwPosition &rPos ) const
+{
+ if( IsHiddenNow() )
+ return sal_False;
+
+ xub_StrLen nOffset = rPos.nContent.GetIndex();
+ SwTxtFrm* pFrm = &(const_cast<SwTxtFrm*>(this)->GetFrmAtOfst( nOffset ));
+
+ pFrm->GetFormatted();
+ const SwFrm* pTmpFrm = (SwFrm*)pFrm->GetUpper();
+
+ SWRECTFN( pTmpFrm )
+ SwTwips nUpperMaxY = (pTmpFrm->*fnRect->fnGetPrtBottom)();
+
+ // nMaxY is in absolute value
+ //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
+ SwTwips nMaxY = bVert ?
+ ( bVertL2R ? Min( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY ) : Max( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY ) ) :
+ Min( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY );
+
+ if ( pFrm->IsEmpty() || ! (pFrm->Prt().*fnRect->fnGetHeight)() )
+ {
+ Point aPnt1 = pFrm->Frm().Pos() + pFrm->Prt().Pos();
+ Point aPnt2;
+ if ( bVert )
+ {
+ if ( aPnt1.X() < nMaxY && !bVertL2R )
+ aPnt1.X() = nMaxY;
+
+ aPnt2.X() = aPnt1.X() + pFrm->Prt().Width();
+ aPnt2.Y() = aPnt1.Y();
+ if( aPnt2.X() < nMaxY )
+ aPnt2.X() = nMaxY;
+ }
+ else
+ {
+ if( aPnt1.Y() > nMaxY )
+ aPnt1.Y() = nMaxY;
+ aPnt2.X() = aPnt1.X();
+ aPnt2.Y() = aPnt1.Y() + pFrm->Prt().Height();
+ if( aPnt2.Y() > nMaxY )
+ aPnt2.Y() = nMaxY;
+ }
+ rOrig = SwRect( aPnt1, aPnt2 );
+ return sal_True;
+ }
+ else
+ {
+ if( !pFrm->HasPara() )
+ return sal_False;
+
+ SwFrmSwapper aSwapper( pFrm, sal_True );
+ if ( bVert )
+ nMaxY = pFrm->SwitchVerticalToHorizontal( nMaxY );
+
+ SwTxtSizeInfo aInf( pFrm );
+ SwTxtCursor aLine( pFrm, &aInf );
+ SwCrsrMoveState aTmpState( MV_SETONLYTEXT );
+ aTmpState.bRealHeight = sal_True;
+ if( aLine.GetCharRect( &rOrig, nOffset, &aTmpState, nMaxY ) )
+ {
+ if( aTmpState.aRealHeight.X() >= 0 )
+ {
+ rOrig.Pos().Y() += aTmpState.aRealHeight.X();
+ rOrig.Height( aTmpState.aRealHeight.Y() );
+ }
+
+ if ( pFrm->IsRightToLeft() )
+ pFrm->SwitchLTRtoRTL( rOrig );
+
+ if ( bVert )
+ pFrm->SwitchHorizontalToVertical( rOrig );
+
+ return sal_True;
+ }
+ return sal_False;
+ }
+}
+
+/** determine top of line for given position in the text frame
+
+ OD 11.11.2003 #i22341#
+ OD 2004-03-18 #114789# - corrections:
+ - Top of first paragraph line is the top of the printing area of the text frame
+ - If a proportional line spacing is applied use top of anchor character as
+ top of the line.
+
+ @author OD
+*/
+bool SwTxtFrm::GetTopOfLine( SwTwips& _onTopOfLine,
+ const SwPosition& _rPos ) const
+{
+ bool bRet = true;
+
+ // get position offset
+ xub_StrLen nOffset = _rPos.nContent.GetIndex();
+
+ if ( GetTxt().Len() < nOffset )
+ {
+ bRet = false;
+ }
+ else
+ {
+ SWRECTFN( this )
+ if ( IsEmpty() || !(Prt().*fnRect->fnGetHeight)() )
+ {
+ // OD 2004-03-18 #i11860# - consider upper space amount considered
+ // for previous frame and the page grid.
+ _onTopOfLine = (this->*fnRect->fnGetPrtTop)();
+ }
+ else
+ {
+ // determine formatted text frame that contains the requested position
+ SwTxtFrm* pFrm = &(const_cast<SwTxtFrm*>(this)->GetFrmAtOfst( nOffset ));
+ pFrm->GetFormatted();
+ SWREFRESHFN( pFrm )
+ // OD 2004-03-18 #114789# - If proportional line spacing is applied
+ // to the text frame, the top of the anchor character is also the
+ // top of the line.
+ // Otherwise the line layout determines the top of the line
+ const SvxLineSpacingItem& rSpace = GetAttrSet()->GetLineSpacing();
+ if ( rSpace.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP )
+ {
+ SwRect aCharRect;
+ if ( GetAutoPos( aCharRect, _rPos ) )
+ {
+ _onTopOfLine = (aCharRect.*fnRect->fnGetTop)();
+ }
+ else
+ {
+ bRet = false;
+ }
+ }
+ else
+ {
+ // assure that text frame is in a horizontal layout
+ SwFrmSwapper aSwapper( pFrm, sal_True );
+ // determine text line that contains the requested position
+ SwTxtSizeInfo aInf( pFrm );
+ SwTxtCursor aLine( pFrm, &aInf );
+ aLine.CharCrsrToLine( nOffset );
+ // determine top of line
+ _onTopOfLine = aLine.Y();
+ if ( bVert )
+ {
+ _onTopOfLine = pFrm->SwitchHorizontalToVertical( _onTopOfLine );
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+/*************************************************************************
+ * SwTxtFrm::_GetCrsrOfst()
+ *************************************************************************/
+
+// Minimaler Abstand von nichtleeren Zeilen etwas weniger als 2 cm
+#define FILL_MIN_DIST 1100
+
+struct SwFillData
+{
+ SwRect aFrm;
+ const SwCrsrMoveState *pCMS;
+ SwPosition* pPos;
+ const Point& rPoint;
+ SwTwips nLineWidth;
+ sal_Bool bFirstLine : 1;
+ sal_Bool bInner : 1;
+ sal_Bool bColumn : 1;
+ sal_Bool bEmpty : 1;
+ SwFillData( const SwCrsrMoveState *pC, SwPosition* pP, const SwRect& rR,
+ const Point& rPt ) : aFrm( rR ), pCMS( pC ), pPos( pP ), rPoint( rPt ),
+ nLineWidth( 0 ), bFirstLine( sal_True ), bInner( sal_False ), bColumn( sal_False ),
+ bEmpty( sal_True ){}
+ SwFillMode Mode() const { return pCMS->pFill->eMode; }
+ long X() const { return rPoint.X(); }
+ long Y() const { return rPoint.Y(); }
+ long Left() const { return aFrm.Left(); }
+ long Right() const { return aFrm.Right(); }
+ long Bottom() const { return aFrm.Bottom(); }
+ SwRect& Frm() { return aFrm; }
+ SwFillCrsrPos &Fill() const { return *pCMS->pFill; }
+ void SetTab( MSHORT nNew ) { pCMS->pFill->nTabCnt = nNew; }
+ void SetSpace( MSHORT nNew ) { pCMS->pFill->nSpaceCnt = nNew; }
+ void SetOrient( const sal_Int16 eNew ){ pCMS->pFill->eOrient = eNew; }
+};
+
+sal_Bool SwTxtFrm::_GetCrsrOfst(SwPosition* pPos, const Point& rPoint,
+ const sal_Bool bChgFrm, SwCrsrMoveState* pCMS ) const
+{
+ // 8804: _GetCrsrOfst wird vom GetCrsrOfst und GetKeyCrsrOfst gerufen.
+ // In keinem Fall nur ein return sal_False.
+
+ if( IsLocked() || IsHiddenNow() )
+ return sal_False;
+
+ ((SwTxtFrm*)this)->GetFormatted();
+
+ Point aOldPoint( rPoint );
+
+ if ( IsVertical() )
+ {
+ SwitchVerticalToHorizontal( (Point&)rPoint );
+ ((SwTxtFrm*)this)->SwapWidthAndHeight();
+ }
+
+ if ( IsRightToLeft() )
+ SwitchRTLtoLTR( (Point&)rPoint );
+
+ SwFillData *pFillData = ( pCMS && pCMS->pFill ) ?
+ new SwFillData( pCMS, pPos, Frm(), rPoint ) : NULL;
+
+ if ( IsEmpty() )
+ {
+ SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
+ pPos->nNode = *pTxtNd;
+ pPos->nContent.Assign( pTxtNd, 0 );
+ if( pCMS && pCMS->bFieldInfo )
+ {
+ SwTwips nDiff = rPoint.X() - Frm().Left() - Prt().Left();
+ if( nDiff > 50 || nDiff < 0 )
+ ((SwCrsrMoveState*)pCMS)->bPosCorr = sal_True;
+ }
+ }
+ else
+ {
+ SwTxtSizeInfo aInf( (SwTxtFrm*)this );
+ SwTxtCursor aLine( ((SwTxtFrm*)this), &aInf );
+
+ // Siehe Kommentar in AdjustFrm()
+ SwTwips nMaxY = Frm().Top() + Prt().Top() + Prt().Height();
+ aLine.TwipsToLine( rPoint.Y() );
+ while( aLine.Y() + aLine.GetLineHeight() > nMaxY )
+ {
+ if( !aLine.Prev() )
+ break;
+ }
+
+ if( aLine.GetDropLines() >= aLine.GetLineNr() && 1 != aLine.GetLineNr()
+ && rPoint.X() < aLine.FirstLeft() + aLine.GetDropLeft() )
+ while( aLine.GetLineNr() > 1 )
+ aLine.Prev();
+
+ xub_StrLen nOffset = aLine.GetCrsrOfst( pPos, rPoint, bChgFrm, pCMS );
+
+ if( pCMS && pCMS->eState == MV_NONE && aLine.GetEnd() == nOffset )
+ ((SwCrsrMoveState*)pCMS)->eState = MV_RIGHTMARGIN;
+
+ // 6776: pPos ist ein reiner IN-Parameter, der nicht ausgewertet werden darf.
+ // Das pIter->GetCrsrOfst returnt aus einer Verschachtelung mit STRING_LEN.
+ // Wenn SwTxtIter::GetCrsrOfst von sich aus weitere GetCrsrOfst
+ // ruft, so aendert sich nNode der Position. In solchen Faellen
+ // darf pPos nicht berechnet werden.
+ if( STRING_LEN != nOffset )
+ {
+ SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
+ pPos->nNode = *pTxtNd;
+ pPos->nContent.Assign( pTxtNd, nOffset );
+ if( pFillData )
+ {
+ if( pTxtNd->GetTxt().Len() > nOffset ||
+ rPoint.Y() < Frm().Top() )
+ pFillData->bInner = sal_True;
+ pFillData->bFirstLine = aLine.GetLineNr() < 2;
+ if( pTxtNd->GetTxt().Len() )
+ {
+ pFillData->bEmpty = sal_False;
+ pFillData->nLineWidth = aLine.GetCurr()->Width();
+ }
+ }
+ }
+ }
+ sal_Bool bChgFillData = sal_False;
+ if( pFillData && FindPageFrm()->Frm().IsInside( aOldPoint ) )
+ {
+ FillCrsrPos( *pFillData );
+ bChgFillData = sal_True;
+ }
+
+ if ( IsVertical() )
+ {
+ if ( bChgFillData )
+ SwitchHorizontalToVertical( pFillData->Fill().aCrsr.Pos() );
+ ((SwTxtFrm*)this)->SwapWidthAndHeight();
+ }
+
+ if ( IsRightToLeft() && bChgFillData )
+ {
+ SwitchLTRtoRTL( pFillData->Fill().aCrsr.Pos() );
+ const sal_Int16 eOrient = pFillData->pCMS->pFill->eOrient;
+
+ if ( text::HoriOrientation::LEFT == eOrient )
+ pFillData->SetOrient( text::HoriOrientation::RIGHT );
+ else if ( text::HoriOrientation::RIGHT == eOrient )
+ pFillData->SetOrient( text::HoriOrientation::LEFT );
+ }
+
+ (Point&)rPoint = aOldPoint;
+ delete pFillData;
+
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwTxtFrm::GetCrsrOfst()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::GetCrsrOfst(SwPosition* pPos, Point& rPoint,
+ SwCrsrMoveState* pCMS ) const
+{
+ MSHORT nChgFrm = 2;
+ if( pCMS )
+ {
+ if( MV_UPDOWN == pCMS->eState )
+ nChgFrm = 0;
+ else if( MV_SETONLYTEXT == pCMS->eState ||
+ MV_TBLSEL == pCMS->eState )
+ nChgFrm = 1;
+ }
+ return _GetCrsrOfst( pPos, rPoint, nChgFrm != 0, pCMS );
+}
+
+/*************************************************************************
+ * SwTxtFrm::LeftMargin()
+ *************************************************************************/
+
+/*
+ * Layout-orientierte Cursorbewegungen
+ */
+
+/*
+ * an den Zeilenanfang
+ */
+
+sal_Bool SwTxtFrm::LeftMargin(SwPaM *pPam) const
+{
+ if( ((const SwNode*)pPam->GetNode()) != GetNode() )
+ pPam->GetPoint()->nNode = *((SwTxtFrm*)this)->GetTxtNode();
+
+ SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *pPam->GetPoint(),
+ SwTxtCursor::IsRightMargin() );
+ pFrm->GetFormatted();
+ xub_StrLen nIndx;
+ if ( pFrm->IsEmpty() )
+ nIndx = 0;
+ else
+ {
+ SwTxtSizeInfo aInf( pFrm );
+ SwTxtCursor aLine( pFrm, &aInf );
+
+ aLine.CharCrsrToLine(pPam->GetPoint()->nContent.GetIndex());
+ nIndx = aLine.GetStart();
+ if( pFrm->GetOfst() && !pFrm->IsFollow() && !aLine.GetPrev() )
+ {
+ lcl_ChangeOffset( pFrm, 0 );
+ nIndx = 0;
+ }
+ }
+ pPam->GetPoint()->nContent = SwIndex( pFrm->GetTxtNode(), nIndx );
+ SwTxtCursor::SetRightMargin( sal_False );
+ return sal_True;
+}
+
+/*************************************************************************
+ * SwTxtFrm::RightMargin()
+ *************************************************************************/
+
+/*
+ * An das Zeilenende:Das ist die Position vor dem letzten
+ * Character in der Zeile. Ausnahme: In der letzten Zeile soll
+ * der Cursor auch hinter dem letzten Character stehen koennen,
+ * um Text anhaengen zu koennen.
+ *
+ */
+
+sal_Bool SwTxtFrm::RightMargin(SwPaM *pPam, sal_Bool bAPI) const
+{
+ if( ((const SwNode*)pPam->GetNode()) != GetNode() )
+ pPam->GetPoint()->nNode = *((SwTxtFrm*)this)->GetTxtNode();
+
+ SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *pPam->GetPoint(),
+ SwTxtCursor::IsRightMargin() );
+ pFrm->GetFormatted();
+ xub_StrLen nRightMargin;
+ if ( IsEmpty() )
+ nRightMargin = 0;
+ else
+ {
+ SwTxtSizeInfo aInf( pFrm );
+ SwTxtCursor aLine( pFrm, &aInf );
+
+ aLine.CharCrsrToLine(pPam->GetPoint()->nContent.GetIndex());
+ nRightMargin = aLine.GetStart() + aLine.GetCurr()->GetLen();
+
+ // Harte Zeilenumbrueche lassen wir hinter uns.
+ if( aLine.GetCurr()->GetLen() &&
+ CH_BREAK == aInf.GetTxt().GetChar( nRightMargin - 1 ) )
+ --nRightMargin;
+ else if( !bAPI && (aLine.GetNext() || pFrm->GetFollow()) )
+ {
+ while( nRightMargin > aLine.GetStart() &&
+ ' ' == aInf.GetTxt().GetChar( nRightMargin - 1 ) )
+ --nRightMargin;
+ }
+ }
+ pPam->GetPoint()->nContent = SwIndex( pFrm->GetTxtNode(), nRightMargin );
+ SwTxtCursor::SetRightMargin( !bAPI );
+ return sal_True;
+}
+
+/*************************************************************************
+ * SwTxtFrm::_UnitUp()
+ *************************************************************************/
+
+//Die beiden folgenden Methoden versuchen zunaechst den Crsr in die
+//nachste/folgende Zeile zu setzen. Gibt es im Frame keine vorhergehende/
+//folgende Zeile, so wird der Aufruf an die Basisklasse weitergeleitet.
+//Die Horizontale Ausrichtung des Crsr wird hinterher von der CrsrShell
+//vorgenommen.
+
+class SwSetToRightMargin
+{
+ sal_Bool bRight;
+public:
+ inline SwSetToRightMargin() : bRight( sal_False ) { }
+ inline ~SwSetToRightMargin() { SwTxtCursor::SetRightMargin( bRight ); }
+ inline void SetRight( const sal_Bool bNew ) { bRight = bNew; }
+};
+
+sal_Bool SwTxtFrm::_UnitUp( SwPaM *pPam, const SwTwips nOffset,
+ sal_Bool bSetInReadOnly ) const
+{
+ // 8626: Im Notfall den RightMargin setzen.
+ SwSetToRightMargin aSet;
+
+ if( IsInTab() &&
+ pPam->GetNode( sal_True )->StartOfSectionNode() !=
+ pPam->GetNode( sal_False )->StartOfSectionNode() )
+ {
+ //Wenn der PaM in unterschiedlichen Boxen sitzt, so handelt es sich um
+ //eine Tabellenselektion; diese wird von der Basisklasse abgearbeitet.
+ return SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
+ }
+
+ ((SwTxtFrm*)this)->GetFormatted();
+ const xub_StrLen nPos = pPam->GetPoint()->nContent.GetIndex();
+ SwRect aCharBox;
+
+ if( !IsEmpty() && !IsHiddenNow() )
+ {
+ xub_StrLen nFormat = STRING_LEN;
+ do
+ {
+ if( nFormat != STRING_LEN && !IsFollow() )
+ lcl_ChangeOffset( ((SwTxtFrm*)this), nFormat );
+
+ SwTxtSizeInfo aInf( (SwTxtFrm*)this );
+ SwTxtCursor aLine( ((SwTxtFrm*)this), &aInf );
+
+ // 8116: Flys ohne Umlauf und IsDummy(); hier wegoptimiert
+ if( nPos )
+ aLine.CharCrsrToLine( nPos );
+ else
+ aLine.Top();
+
+ const SwLineLayout *pPrevLine = aLine.GetPrevLine();
+ const xub_StrLen nStart = aLine.GetStart();
+ aLine.GetCharRect( &aCharBox, nPos );
+
+ sal_Bool bSecondOfDouble = ( aInf.IsMulti() && ! aInf.IsFirstMulti() );
+ sal_Bool bPrevLine = ( pPrevLine && pPrevLine != aLine.GetCurr() );
+
+ if( !pPrevLine && !bSecondOfDouble && GetOfst() && !IsFollow() )
+ {
+ nFormat = GetOfst();
+ xub_StrLen nDiff = aLine.GetLength();
+ if( !nDiff )
+ nDiff = MIN_OFFSET_STEP;
+ if( nFormat > nDiff )
+ nFormat = nFormat - nDiff;
+ else
+ nFormat = 0;
+ continue;
+ }
+
+ // we select the target line for the cursor, in case we are in a
+ // double line portion, prev line = curr line
+ if( bPrevLine && !bSecondOfDouble )
+ {
+ aLine.PrevLine();
+ while ( aLine.GetStart() == nStart &&
+ 0 != ( pPrevLine = aLine.GetPrevLine() ) &&
+ pPrevLine != aLine.GetCurr() )
+ aLine.PrevLine();
+ }
+
+ if ( bPrevLine || bSecondOfDouble )
+ {
+ aCharBox.SSize().Width() /= 2;
+ aCharBox.Pos().X() = aCharBox.Pos().X() - 150;
+
+ // siehe Kommentar in SwTxtFrm::GetCrsrOfst()
+#if OSL_DEBUG_LEVEL > 1
+ const sal_uLong nOldNode = pPam->GetPoint()->nNode.GetIndex();
+#endif
+ // Der Node soll nicht gewechselt werden
+ xub_StrLen nTmpOfst = aLine.GetCrsrOfst( pPam->GetPoint(),
+ aCharBox.Pos(), sal_False );
+#if OSL_DEBUG_LEVEL > 1
+ OSL_ENSURE( nOldNode == pPam->GetPoint()->nNode.GetIndex(),
+ "SwTxtFrm::UnitUp: illegal node change" );
+#endif
+
+ // 7684: Wir stellen sicher, dass wir uns nach oben bewegen.
+ if( nTmpOfst >= nStart && nStart && !bSecondOfDouble )
+ {
+ nTmpOfst = nStart;
+ aSet.SetRight( sal_True );
+ }
+ pPam->GetPoint()->nContent =
+ SwIndex( ((SwTxtFrm*)this)->GetTxtNode(), nTmpOfst );
+ return sal_True;
+ }
+
+ if ( IsFollow() )
+ {
+ aLine.GetCharRect( &aCharBox, nPos );
+ aCharBox.SSize().Width() /= 2;
+ }
+ break;
+ } while ( sal_True );
+ }
+ /* Wenn this ein Follow ist und ein Prev miszlang, so
+ * muessen wir in die letzte Zeile des Master ... und der sind wir.
+ * Oder wir sind ein Follow mit Follow, dann muessen wir uns den
+ * Master extra besorgen...
+ */
+ if ( IsFollow() )
+ {
+ const SwTxtFrm *pTmpPrev = FindMaster();
+ xub_StrLen nOffs = GetOfst();
+ if( pTmpPrev )
+ {
+ ViewShell *pSh = getRootFrm()->GetCurrShell();
+ sal_Bool bProtectedAllowed = pSh && pSh->GetViewOptions()->IsCursorInProtectedArea();
+ const SwTxtFrm *pPrevPrev = pTmpPrev;
+ // Hier werden geschuetzte Frames und Frame ohne Inhalt ausgelassen
+ while( pPrevPrev && ( pPrevPrev->GetOfst() == nOffs ||
+ ( !bProtectedAllowed && pPrevPrev->IsProtected() ) ) )
+ {
+ pTmpPrev = pPrevPrev;
+ nOffs = pTmpPrev->GetOfst();
+ if ( pPrevPrev->IsFollow() )
+ pPrevPrev = pTmpPrev->FindMaster();
+ else
+ pPrevPrev = NULL;
+ }
+ if ( !pPrevPrev )
+ return pTmpPrev->SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
+ aCharBox.Pos().Y() = pPrevPrev->Frm().Bottom() - 1;
+ return pPrevPrev->GetKeyCrsrOfst( pPam->GetPoint(), aCharBox.Pos() );
+ }
+ }
+ return SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
+}
+
+//
+// Used for Bidi. nPos is the logical position in the string, bLeft indicates
+// if left arrow or right arrow was pressed. The return values are:
+// nPos: the new visual position
+// bLeft: whether the break iterator has to add or subtract from the
+// current position
+void lcl_VisualMoveRecursion( const SwLineLayout& rCurrLine, xub_StrLen nIdx,
+ xub_StrLen& nPos, sal_Bool& bRight,
+ sal_uInt8& nCrsrLevel, sal_uInt8 nDefaultDir )
+{
+ const SwLinePortion* pPor = rCurrLine.GetFirstPortion();
+ const SwLinePortion* pLast = 0;
+
+ // what's the current portion
+ while ( pPor && nIdx + pPor->GetLen() <= nPos )
+ {
+ nIdx = nIdx + pPor->GetLen();
+ pLast = pPor;
+ pPor = pPor->GetPortion();
+ }
+
+ if ( bRight )
+ {
+ sal_Bool bRecurse = pPor && pPor->IsMultiPortion() &&
+ ((SwMultiPortion*)pPor)->IsBidi();
+
+ // 1. special case: at beginning of bidi portion
+ if ( bRecurse && nIdx == nPos )
+ {
+ nPos = nPos + pPor->GetLen();
+
+ // leave bidi portion
+ if ( nCrsrLevel != nDefaultDir )
+ {
+ bRecurse = sal_False;
+ }
+ else
+ // special case:
+ // buffer: abcXYZ123 in LTR paragraph
+ // view: abc123ZYX
+ // cursor is between c and X in the buffer and cursor level = 0
+ nCrsrLevel++;
+ }
+
+ // 2. special case: at beginning of portion after bidi portion
+ else if ( pLast && pLast->IsMultiPortion() &&
+ ((SwMultiPortion*)pLast)->IsBidi() && nIdx == nPos )
+ {
+ // enter bidi portion
+ if ( nCrsrLevel != nDefaultDir )
+ {
+ bRecurse = sal_True;
+ nIdx = nIdx - pLast->GetLen();
+ pPor = pLast;
+ }
+ }
+
+ // Recursion
+ if ( bRecurse )
+ {
+ const SwLineLayout& rLine = ((SwMultiPortion*)pPor)->GetRoot();
+ xub_StrLen nTmpPos = nPos - nIdx;
+ sal_Bool bTmpForward = ! bRight;
+ sal_uInt8 nTmpCrsrLevel = nCrsrLevel;
+ lcl_VisualMoveRecursion( rLine, 0, nTmpPos, bTmpForward,
+ nTmpCrsrLevel, nDefaultDir + 1 );
+
+ nPos = nTmpPos + nIdx;
+ bRight = bTmpForward;
+ nCrsrLevel = nTmpCrsrLevel;
+ }
+
+ // go forward
+ else
+ {
+ bRight = sal_True;
+ nCrsrLevel = nDefaultDir;
+ }
+
+ }
+ else
+ {
+ sal_Bool bRecurse = pPor && pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi();
+
+ // 1. special case: at beginning of bidi portion
+ if ( bRecurse && nIdx == nPos )
+ {
+ // leave bidi portion
+ if ( nCrsrLevel == nDefaultDir )
+ {
+ bRecurse = sal_False;
+ }
+ }
+
+ // 2. special case: at beginning of portion after bidi portion
+ else if ( pLast && pLast->IsMultiPortion() &&
+ ((SwMultiPortion*)pLast)->IsBidi() && nIdx == nPos )
+ {
+ nPos = nPos - pLast->GetLen();
+
+ // enter bidi portion
+ if ( nCrsrLevel % 2 == nDefaultDir % 2 )
+ {
+ bRecurse = sal_True;
+ nIdx = nIdx - pLast->GetLen();
+ pPor = pLast;
+
+ // special case:
+ // buffer: abcXYZ123 in LTR paragraph
+ // view: abc123ZYX
+ // cursor is behind 3 in the buffer and cursor level = 2
+ if ( nDefaultDir + 2 == nCrsrLevel )
+ nPos = nPos + pLast->GetLen();
+ }
+ }
+
+ // go forward
+ if ( bRecurse )
+ {
+ const SwLineLayout& rLine = ((SwMultiPortion*)pPor)->GetRoot();
+ xub_StrLen nTmpPos = nPos - nIdx;
+ sal_Bool bTmpForward = ! bRight;
+ sal_uInt8 nTmpCrsrLevel = nCrsrLevel;
+ lcl_VisualMoveRecursion( rLine, 0, nTmpPos, bTmpForward,
+ nTmpCrsrLevel, nDefaultDir + 1 );
+
+ // special case:
+ // buffer: abcXYZ123 in LTR paragraph
+ // view: abc123ZYX
+ // cursor is between Z and 1 in the buffer and cursor level = 2
+ if ( nTmpPos == pPor->GetLen() && nTmpCrsrLevel == nDefaultDir + 1 )
+ {
+ nTmpPos = nTmpPos - pPor->GetLen();
+ nTmpCrsrLevel = nDefaultDir;
+ bTmpForward = ! bTmpForward;
+ }
+
+ nPos = nTmpPos + nIdx;
+ bRight = bTmpForward;
+ nCrsrLevel = nTmpCrsrLevel;
+ }
+
+ // go backward
+ else
+ {
+ bRight = sal_False;
+ nCrsrLevel = nDefaultDir;
+ }
+ }
+}
+
+void SwTxtFrm::PrepareVisualMove( xub_StrLen& nPos, sal_uInt8& nCrsrLevel,
+ sal_Bool& bForward, sal_Bool bInsertCrsr )
+{
+ if( IsEmpty() || IsHiddenNow() )
+ return;
+
+ ((SwTxtFrm*)this)->GetFormatted();
+
+ SwTxtSizeInfo aInf( (SwTxtFrm*)this );
+ SwTxtCursor aLine( ((SwTxtFrm*)this), &aInf );
+
+ if( nPos )
+ aLine.CharCrsrToLine( nPos );
+ else
+ aLine.Top();
+
+ const SwLineLayout* pLine = aLine.GetCurr();
+ const xub_StrLen nStt = aLine.GetStart();
+ const xub_StrLen nLen = pLine->GetLen();
+
+ // We have to distinguish between an insert and overwrite cursor:
+ // The insert cursor position depends on the cursor level:
+ // buffer: abcXYZdef in LTR paragraph
+ // display: abcZYXdef
+ // If cursor is between c and X in the buffer and cursor level is 0,
+ // the cursor blinks between c and Z and -> sets the cursor between Z and Y.
+ // If the cursor level is 1, the cursor blinks between X and d and
+ // -> sets the cursor between d and e.
+ // The overwrite cursor simply travels to the next visual character.
+ if ( bInsertCrsr )
+ {
+ lcl_VisualMoveRecursion( *pLine, nStt, nPos, bForward,
+ nCrsrLevel, IsRightToLeft() ? 1 : 0 );
+ return;
+ }
+
+ const sal_uInt8 nDefaultDir = static_cast<sal_uInt8>(IsRightToLeft() ? UBIDI_RTL : UBIDI_LTR);
+ const sal_Bool bVisualRight = ( nDefaultDir == UBIDI_LTR && bForward ) ||
+ ( nDefaultDir == UBIDI_RTL && ! bForward );
+
+ //
+ // Bidi functions from icu 2.0
+ //
+ const sal_Unicode* pLineString = GetTxtNode()->GetTxt().GetBuffer();
+ pLine += nStt;
+
+ UErrorCode nError = U_ZERO_ERROR;
+ UBiDi* pBidi = ubidi_openSized( nLen, 0, &nError );
+ ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(pLineString), nLen, nDefaultDir, NULL, &nError ); // UChar != sal_Unicode in MinGW
+
+ xub_StrLen nTmpPos;
+ sal_Bool bOutOfBounds = sal_False;
+
+ if ( nPos < nStt + nLen )
+ {
+ nTmpPos = (xub_StrLen)ubidi_getVisualIndex( pBidi, nPos, &nError );
+
+ // visual indices are always LTR aligned
+ if ( bVisualRight )
+ {
+ if ( nTmpPos + 1 < nStt + nLen )
+ ++nTmpPos;
+ else
+ {
+ nPos = nDefaultDir == UBIDI_RTL ? 0 : nStt + nLen;
+ bOutOfBounds = sal_True;
+ }
+ }
+ else
+ {
+ if ( nTmpPos )
+ --nTmpPos;
+ else
+ {
+ nPos = nDefaultDir == UBIDI_RTL ? nStt + nLen : 0;
+ bOutOfBounds = sal_True;
+ }
+ }
+ }
+ else
+ {
+ nTmpPos = nDefaultDir == UBIDI_LTR ? nPos - 1 : 0;
+ }
+
+ if ( ! bOutOfBounds )
+ {
+ nPos = (xub_StrLen)ubidi_getLogicalIndex( pBidi, nTmpPos, &nError );
+
+ if ( bForward )
+ {
+ if ( nPos )
+ --nPos;
+ else
+ {
+ ++nPos;
+ bForward = ! bForward;
+ }
+ }
+ else
+ ++nPos;
+ }
+
+ ubidi_close( pBidi );
+}
+
+/*************************************************************************
+ * SwTxtFrm::_UnitDown()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::_UnitDown(SwPaM *pPam, const SwTwips nOffset,
+ sal_Bool bSetInReadOnly ) const
+{
+
+ if ( IsInTab() &&
+ pPam->GetNode( sal_True )->StartOfSectionNode() !=
+ pPam->GetNode( sal_False )->StartOfSectionNode() )
+ {
+ //Wenn der PaM in unterschiedlichen Boxen sitzt, so handelt es sich um
+ //eine Tabellenselektion; diese wird von der Basisklasse abgearbeitet.
+ return SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
+ }
+ ((SwTxtFrm*)this)->GetFormatted();
+ const xub_StrLen nPos = pPam->GetPoint()->nContent.GetIndex();
+ SwRect aCharBox;
+ const SwCntntFrm *pTmpFollow = 0;
+
+ if ( IsVertical() )
+ ((SwTxtFrm*)this)->SwapWidthAndHeight();
+
+ if ( !IsEmpty() && !IsHiddenNow() )
+ {
+ xub_StrLen nFormat = STRING_LEN;
+ do
+ {
+ if( nFormat != STRING_LEN && !IsFollow() &&
+ !lcl_ChangeOffset( ((SwTxtFrm*)this), nFormat ) )
+ break;
+
+ SwTxtSizeInfo aInf( (SwTxtFrm*)this );
+ SwTxtCursor aLine( ((SwTxtFrm*)this), &aInf );
+ nFormat = aLine.GetEnd();
+
+ aLine.CharCrsrToLine( nPos );
+
+ const SwLineLayout* pNextLine = aLine.GetNextLine();
+ const xub_StrLen nStart = aLine.GetStart();
+ aLine.GetCharRect( &aCharBox, nPos );
+
+ sal_Bool bFirstOfDouble = ( aInf.IsMulti() && aInf.IsFirstMulti() );
+
+ if( pNextLine || bFirstOfDouble )
+ {
+ aCharBox.SSize().Width() /= 2;
+#if OSL_DEBUG_LEVEL > 1
+ // siehe Kommentar in SwTxtFrm::GetCrsrOfst()
+ const sal_uLong nOldNode = pPam->GetPoint()->nNode.GetIndex();
+#endif
+ if ( pNextLine && ! bFirstOfDouble )
+ aLine.NextLine();
+
+ xub_StrLen nTmpOfst = aLine.GetCrsrOfst( pPam->GetPoint(),
+ aCharBox.Pos(), sal_False );
+#if OSL_DEBUG_LEVEL > 1
+ OSL_ENSURE( nOldNode == pPam->GetPoint()->nNode.GetIndex(),
+ "SwTxtFrm::UnitDown: illegal node change" );
+#endif
+
+ // 7684: Wir stellen sicher, dass wir uns nach unten bewegen.
+ if( nTmpOfst <= nStart && ! bFirstOfDouble )
+ nTmpOfst = nStart + 1;
+ pPam->GetPoint()->nContent =
+ SwIndex( ((SwTxtFrm*)this)->GetTxtNode(), nTmpOfst );
+
+ if ( IsVertical() )
+ ((SwTxtFrm*)this)->SwapWidthAndHeight();
+
+ return sal_True;
+ }
+ if( 0 != ( pTmpFollow = GetFollow() ) )
+ { // geschuetzte Follows auslassen
+ const SwCntntFrm* pTmp = pTmpFollow;
+ ViewShell *pSh = getRootFrm()->GetCurrShell();
+ if( !pSh || !pSh->GetViewOptions()->IsCursorInProtectedArea() )
+ {
+ while( pTmpFollow && pTmpFollow->IsProtected() )
+ {
+ pTmp = pTmpFollow;
+ pTmpFollow = pTmpFollow->GetFollow();
+ }
+ }
+ if( !pTmpFollow ) // nur noch geschuetzte
+ {
+ if ( IsVertical() )
+ ((SwTxtFrm*)this)->SwapWidthAndHeight();
+ return pTmp->SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
+ }
+
+ aLine.GetCharRect( &aCharBox, nPos );
+ aCharBox.SSize().Width() /= 2;
+ }
+ else if( !IsFollow() )
+ {
+ xub_StrLen nTmpLen = aInf.GetTxt().Len();
+ if( aLine.GetEnd() < nTmpLen )
+ {
+ if( nFormat <= GetOfst() )
+ {
+ nFormat = Min( xub_StrLen( GetOfst() + MIN_OFFSET_STEP ),
+ nTmpLen );
+ if( nFormat <= GetOfst() )
+ break;
+ }
+ continue;
+ }
+ }
+ break;
+ } while( sal_True );
+ }
+ else
+ pTmpFollow = GetFollow();
+
+ if ( IsVertical() )
+ ((SwTxtFrm*)this)->SwapWidthAndHeight();
+
+ // Bei Follows schlagen wir eine Abkuerzung
+ if( pTmpFollow )
+ {
+ aCharBox.Pos().Y() = pTmpFollow->Frm().Top() + 1;
+ return ((SwTxtFrm*)pTmpFollow)->GetKeyCrsrOfst( pPam->GetPoint(),
+ aCharBox.Pos() );
+ }
+ return SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
+}
+
+/*************************************************************************
+ * virtual SwTxtFrm::UnitUp()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::UnitUp(SwPaM *pPam, const SwTwips nOffset,
+ sal_Bool bSetInReadOnly ) const
+{
+ /* Im CrsrSh::Up() wird CntntNode::GetFrm() gerufen.
+ * Dies liefert _immer_ den Master zurueck.
+ * Um das Cursortravelling nicht zu belasten, korrigieren wir
+ * hier im SwTxtFrm.
+ * Wir ermittelt UnitUp fuer pFrm, pFrm ist entweder ein Master (=this)
+ * oder ein Follow (!=this)
+ */
+ const SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *(pPam->GetPoint()),
+ SwTxtCursor::IsRightMargin() );
+ const sal_Bool bRet = pFrm->_UnitUp( pPam, nOffset, bSetInReadOnly );
+
+ // 8626: kein SwTxtCursor::SetRightMargin( sal_False );
+ // statt dessen steht ein SwSetToRightMargin im _UnitUp
+ return bRet;
+}
+
+/*************************************************************************
+ * virtual SwTxtFrm::UnitDown()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::UnitDown(SwPaM *pPam, const SwTwips nOffset,
+ sal_Bool bSetInReadOnly ) const
+{
+ const SwTxtFrm *pFrm = GetAdjFrmAtPos((SwTxtFrm*)this, *(pPam->GetPoint()),
+ SwTxtCursor::IsRightMargin() );
+ const sal_Bool bRet = pFrm->_UnitDown( pPam, nOffset, bSetInReadOnly );
+ SwTxtCursor::SetRightMargin( sal_False );
+ return bRet;
+}
+
+void SwTxtFrm::FillCrsrPos( SwFillData& rFill ) const
+{
+ if( !rFill.bColumn && GetUpper()->IsColBodyFrm() ) // ColumnFrms jetzt mit BodyFrm
+ {
+ const SwColumnFrm* pTmp =
+ (SwColumnFrm*)GetUpper()->GetUpper()->GetUpper()->Lower(); // die 1. Spalte
+ // der erste SwFrm im BodyFrm der ersten Spalte
+ const SwFrm* pFrm = ((SwLayoutFrm*)pTmp->Lower())->Lower();
+ MSHORT nNextCol = 0;
+ // In welcher Spalte landen wir?
+ while( rFill.X() > pTmp->Frm().Right() && pTmp->GetNext() )
+ {
+ pTmp = (SwColumnFrm*)pTmp->GetNext();
+ if( ((SwLayoutFrm*)pTmp->Lower())->Lower() ) // ColumnFrms jetzt mit BodyFrm
+ {
+ pFrm = ((SwLayoutFrm*)pTmp->Lower())->Lower();
+ nNextCol = 0;
+ }
+ else
+ ++nNextCol; // leere Spalten erfordern Spaltenumbrueche
+ }
+ if( pTmp != GetUpper()->GetUpper() ) // Sind wir in einer anderen Spalte gelandet?
+ {
+ if( !pFrm )
+ return;
+ if( nNextCol )
+ {
+ while( pFrm->GetNext() )
+ pFrm = pFrm->GetNext();
+ }
+ else
+ {
+ while( pFrm->GetNext() && pFrm->Frm().Bottom() < rFill.Y() )
+ pFrm = pFrm->GetNext();
+ }
+ // Kein Fuellen, wenn als letzter Frame in der anvisierten
+ // Spalte kein Absatz, sondern z.B. eine Tabelle steht
+ if( pFrm->IsTxtFrm() )
+ {
+ rFill.Fill().nColumnCnt = nNextCol;
+ rFill.bColumn = sal_True;
+ if( rFill.pPos )
+ {
+ SwTxtNode* pTxtNd = ((SwTxtFrm*)pFrm)->GetTxtNode();
+ rFill.pPos->nNode = *pTxtNd;
+ rFill.pPos->nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() );
+ }
+ if( nNextCol )
+ {
+ rFill.aFrm = pTmp->Prt();
+ rFill.aFrm += pTmp->Frm().Pos();
+ }
+ else
+ rFill.aFrm = pFrm->Frm();
+ ((SwTxtFrm*)pFrm)->FillCrsrPos( rFill );
+ }
+ return;
+ }
+ }
+ sal_Bool bFill = sal_True;
+ SwFont *pFnt;
+ SwTxtFmtColl* pColl = GetTxtNode()->GetTxtColl();
+ MSHORT nFirst = GetTxtNode()->GetSwAttrSet().GetULSpace().GetLower();
+ SwTwips nDiff = rFill.Y() - Frm().Bottom();
+ if( nDiff < nFirst )
+ nDiff = -1;
+ else
+ pColl = &pColl->GetNextTxtFmtColl();
+ SwAttrSet aSet( ((SwDoc*)GetTxtNode()->GetDoc())->GetAttrPool(), aTxtFmtCollSetRange );
+ const SwAttrSet* pSet = &pColl->GetAttrSet();
+ ViewShell *pSh = getRootFrm()->GetCurrShell();
+ if( GetTxtNode()->HasSwAttrSet() )
+ {
+ aSet.Put( *GetTxtNode()->GetpSwAttrSet() );
+ aSet.SetParent( pSet );
+ pSet = &aSet;
+ pFnt = new SwFont( pSet, GetNode()->getIDocumentSettingAccess() );
+ }
+ else
+ {
+ SwFontAccess aFontAccess( pColl, pSh );
+ pFnt = new SwFont( *aFontAccess.Get()->GetFont() );
+ pFnt->ChkMagic( pSh, pFnt->GetActual() );
+ }
+ OutputDevice* pOut = pSh->GetOut();
+ if( !pSh->GetViewOptions()->getBrowseMode() || pSh->GetViewOptions()->IsPrtFormat() )
+ pOut = GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
+
+ pFnt->SetFntChg( sal_True );
+ pFnt->ChgPhysFnt( pSh, *pOut );
+
+ SwTwips nLineHeight = pFnt->GetHeight( pSh, *pOut );
+
+ if( nLineHeight )
+ {
+ const SvxULSpaceItem &rUL = pSet->GetULSpace();
+ SwTwips nDist = Max( rUL.GetLower(), rUL.GetUpper() );
+ if( rFill.Fill().nColumnCnt )
+ {
+ rFill.aFrm.Height( nLineHeight );
+ nDiff = rFill.Y() - rFill.Bottom();
+ nFirst = 0;
+ }
+ else if( nDist < nFirst )
+ nFirst = nFirst - (sal_uInt16)nDist;
+ else
+ nFirst = 0;
+ nDist = Max( nDist, long( GetLineSpace() ) );
+ nDist += nLineHeight;
+ nDiff -= nFirst;
+
+ if( nDiff > 0 )
+ {
+ nDiff /= nDist;
+ rFill.Fill().nParaCnt = static_cast<sal_uInt16>(nDiff + 1);
+ rFill.nLineWidth = 0;
+ rFill.bInner = sal_False;
+ rFill.bEmpty = sal_True;
+ rFill.SetOrient( text::HoriOrientation::LEFT );
+ }
+ else
+ nDiff = -1;
+ if( rFill.bInner )
+ bFill = sal_False;
+ else
+ {
+ const SvxTabStopItem &rRuler = pSet->GetTabStops();
+ const SvxLRSpaceItem &rLRSpace = pSet->GetLRSpace();
+
+ SwRect &rRect = rFill.Fill().aCrsr;
+ rRect.Top( rFill.Bottom() + (nDiff+1) * nDist - nLineHeight );
+ if( nFirst && nDiff > -1 )
+ rRect.Top( rRect.Top() + nFirst );
+ rRect.Height( nLineHeight );
+ SwTwips nLeft = rFill.Left() + rLRSpace.GetLeft() +
+ GetTxtNode()->GetLeftMarginWithNum( sal_False );
+ SwTwips nRight = rFill.Right() - rLRSpace.GetRight();
+ SwTwips nCenter = ( nLeft + nRight ) / 2;
+ rRect.Left( nLeft );
+ if( FILL_MARGIN == rFill.Mode() )
+ {
+ if( rFill.bEmpty )
+ {
+ rFill.SetOrient( text::HoriOrientation::LEFT );
+ if( rFill.X() < nCenter )
+ {
+ if( rFill.X() > ( nLeft + 2 * nCenter ) / 3 )
+ {
+ rFill.SetOrient( text::HoriOrientation::CENTER );
+ rRect.Left( nCenter );
+ }
+ }
+ else if( rFill.X() > ( nRight + 2 * nCenter ) / 3 )
+ {
+ rFill.SetOrient( text::HoriOrientation::RIGHT );
+ rRect.Left( nRight );
+ }
+ else
+ {
+ rFill.SetOrient( text::HoriOrientation::CENTER );
+ rRect.Left( nCenter );
+ }
+ }
+ else
+ bFill = sal_False;
+ }
+ else
+ {
+ SwTwips nSpace = 0;
+ if( FILL_TAB != rFill.Mode() )
+ {
+static sal_Char const sDoubleSpace[] = " ";
+ const XubString aTmp( sDoubleSpace, RTL_TEXTENCODING_MS_1252 );
+
+ SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTmp, 0, 2 );
+ nSpace = pFnt->_GetTxtSize( aDrawInf ).Width()/2;
+ }
+ if( rFill.X() >= nRight )
+ {
+ if( FILL_INDENT != rFill.Mode() && ( rFill.bEmpty ||
+ rFill.X() > rFill.nLineWidth + FILL_MIN_DIST ) )
+ {
+ rFill.SetOrient( text::HoriOrientation::RIGHT );
+ rRect.Left( nRight );
+ }
+ else
+ bFill = sal_False;
+ }
+ else if( FILL_INDENT == rFill.Mode() )
+ {
+ SwTwips nIndent = rFill.X();
+ if( !rFill.bEmpty || nIndent > nRight )
+ bFill = sal_False;
+ else
+ {
+ nIndent -= rFill.Left();
+ if( nIndent >= 0 && nSpace )
+ {
+ nIndent /= nSpace;
+ nIndent *= nSpace;
+ rFill.SetTab( MSHORT( nIndent ) );
+ rRect.Left( nIndent + rFill.Left() );
+ }
+ else
+ bFill = sal_False;
+ }
+ }
+ else if( rFill.X() > nLeft )
+ {
+ SwTwips nTxtLeft = rFill.Left() + rLRSpace.GetTxtLeft() +
+ GetTxtNode()->GetLeftMarginWithNum( sal_True );
+ rFill.nLineWidth += rFill.bFirstLine ? nLeft : nTxtLeft;
+ SwTwips nLeftTab = nLeft;
+ SwTwips nRightTab = nLeft;
+ MSHORT nSpaceCnt = 0;
+ MSHORT nTabCnt = 0;
+ MSHORT nIdx = 0;
+ do
+ {
+ nLeftTab = nRightTab;
+ if( nIdx < rRuler.Count() )
+ {
+ const SvxTabStop &rTabStop = rRuler.operator[](nIdx);
+ nRightTab = nTxtLeft + rTabStop.GetTabPos();
+ if( nLeftTab < nTxtLeft && nRightTab > nTxtLeft )
+ nRightTab = nTxtLeft;
+ else
+ ++nIdx;
+ if( nRightTab > rFill.nLineWidth )
+ ++nTabCnt;
+ }
+ else
+ {
+ const SvxTabStopItem& rTab =
+ (const SvxTabStopItem &)pSet->
+ GetPool()->GetDefaultItem( RES_PARATR_TABSTOP );
+ MSHORT nDefTabDist = (MSHORT)rTab.GetStart()->GetTabPos();
+ nRightTab = nLeftTab - nTxtLeft;
+ nRightTab /= nDefTabDist;
+ nRightTab = nRightTab * nDefTabDist + nTxtLeft;
+ while ( nRightTab <= nLeftTab )
+ nRightTab += nDefTabDist;
+ if( nRightTab > rFill.nLineWidth )
+ ++nTabCnt;
+ while ( nRightTab < rFill.X() )
+ {
+ nRightTab += nDefTabDist;
+ if( nRightTab > rFill.nLineWidth )
+ ++nTabCnt;
+ }
+ if( nLeftTab < nRightTab - nDefTabDist )
+ nLeftTab = nRightTab - nDefTabDist;
+ }
+ if( nRightTab > nRight )
+ nRightTab = nRight;
+ }
+ while( rFill.X() > nRightTab );
+ --nTabCnt;
+ if( FILL_TAB != rFill.Mode() )
+ {
+ if( nSpace > 0 )
+ {
+ if( !nTabCnt )
+ nLeftTab = rFill.nLineWidth;
+ while( nLeftTab < rFill.X() )
+ {
+ nLeftTab += nSpace;
+ ++nSpaceCnt;
+ }
+ if( nSpaceCnt )
+ {
+ nLeftTab -= nSpace;
+ --nSpaceCnt;
+ }
+ if( rFill.X() - nLeftTab > nRightTab - rFill.X() )
+ {
+ nSpaceCnt = 0;
+ ++nTabCnt;
+ rRect.Left( nRightTab );
+ }
+ else
+ {
+ if( rFill.X() - nLeftTab > nSpace/2 )
+ {
+ ++nSpaceCnt;
+ rRect.Left( nLeftTab + nSpace );
+ }
+ else
+ rRect.Left( nLeftTab );
+ }
+ }
+ else if( rFill.X() - nLeftTab < nRightTab - rFill.X() )
+ rRect.Left( nLeftTab );
+ else
+ {
+ if( nRightTab >= nRight )
+ {
+ rFill.SetOrient( text::HoriOrientation::RIGHT );
+ rRect.Left( nRight );
+ nTabCnt = 0;
+ nSpaceCnt = 0;
+ }
+ else
+ {
+ rRect.Left( nRightTab );
+ ++nTabCnt;
+ }
+ }
+ }
+ else
+ {
+ if( rFill.X() - nLeftTab < nRightTab - rFill.X() )
+ rRect.Left( nLeftTab );
+ else
+ {
+ if( nRightTab >= nRight )
+ {
+ rFill.SetOrient( text::HoriOrientation::RIGHT );
+ rRect.Left( nRight );
+ nTabCnt = 0;
+ nSpaceCnt = 0;
+ }
+ else
+ {
+ rRect.Left( nRightTab );
+ ++nTabCnt;
+ }
+ }
+ }
+ rFill.SetTab( nTabCnt );
+ rFill.SetSpace( nSpaceCnt );
+ if( bFill )
+ {
+ if( Abs( rFill.X() - nCenter ) <=
+ Abs( rFill.X() - rRect.Left() ) )
+ {
+ rFill.SetOrient( text::HoriOrientation::CENTER );
+ rFill.SetTab( 0 );
+ rFill.SetSpace( 0 );
+ rRect.Left( nCenter );
+ }
+ if( !rFill.bEmpty )
+ rFill.nLineWidth += FILL_MIN_DIST;
+ if( rRect.Left() < rFill.nLineWidth )
+ bFill = sal_False;
+ }
+ }
+ }
+ // Gehen wir ueber die Unterkante der Seite/Spalte etc. hinaus?
+ const SwFrm* pUp = GetUpper();
+ if( pUp->IsInSct() )
+ {
+ if( pUp->IsSctFrm() )
+ pUp = pUp->GetUpper();
+ else if( pUp->IsColBodyFrm() &&
+ pUp->GetUpper()->GetUpper()->IsSctFrm() )
+ pUp = pUp->GetUpper()->GetUpper()->GetUpper();
+ }
+ SWRECTFN( this )
+ SwTwips nLimit = (pUp->*fnRect->fnGetPrtBottom)();
+ SwTwips nRectBottom = rRect.Bottom();
+ if ( bVert )
+ nRectBottom = SwitchHorizontalToVertical( nRectBottom );
+
+ if( (*fnRect->fnYDiff)( nLimit, nRectBottom ) < 0 )
+ bFill = sal_False;
+ else
+ rRect.Width( 1 );
+ }
+ }
+ else
+ bFill = sal_False;
+ ((SwCrsrMoveState*)rFill.pCMS)->bFillRet = bFill;
+ delete pFnt;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */