xref: /trunk/main/sw/source/core/text/frmcrsr.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include "ndtxt.hxx"        // GetNode()
33 #include "pam.hxx"          // SwPosition
34 #include "frmtool.hxx"
35 #include "viewopt.hxx"
36 #include "paratr.hxx"
37 #include "rootfrm.hxx"
38 #include "pagefrm.hxx"
39 #include "colfrm.hxx"
40 #include "txttypes.hxx"
41 #include <sfx2/printer.hxx>
42 #include <editeng/lrspitem.hxx>
43 #include <editeng/tstpitem.hxx>
44 #include <editeng/ulspitem.hxx>
45 #include <editeng/lspcitem.hxx>
46 #include <pormulti.hxx>     // SwMultiPortion
47 #include <doc.hxx>
48 #include <sortedobjs.hxx>
49 
50 #include <unicode/ubidi.h>
51 
52 #include "txtcfg.hxx"
53 #include "txtfrm.hxx"       // SwTxtFrm
54 #include "inftxt.hxx"       // SwTxtSizeInfo
55 #include "itrtxt.hxx"       // SwTxtCursor
56 #include "crstate.hxx"      // SwTxtCursor
57 #include "viewsh.hxx"       // InvalidateWindows
58 #include "swfntcch.hxx"     // SwFontAccess
59 #include "flyfrm.hxx"
60 
61 #if OSL_DEBUG_LEVEL > 1
62 #include "txtpaint.hxx"
63 #endif
64 
65 #define MIN_OFFSET_STEP 10
66 
67 using namespace ::com::sun::star;
68 
69 
70 /*
71  * 1170-SurvivalKit: Wie gelangt man hinter das letzte Zeichen der Zeile.
72  * - RightMargin verzichtet auf den Positionsausgleich mit -1
73  * - GetCharRect liefert bei MV_RIGHTMARGIN ein GetEndCharRect
74  * - GetEndCharRect setzt bRightMargin auf sal_True
75  * - SwTxtCursor::bRightMargin wird per CharCrsrToLine auf sal_False gesetzt
76  */
77 
78 /*************************************************************************
79  *                      GetAdjFrmAtPos()
80  *************************************************************************/
81 
82 SwTxtFrm *GetAdjFrmAtPos( SwTxtFrm *pFrm, const SwPosition &rPos,
83                           const sal_Bool bRightMargin, const sal_Bool bNoScroll = sal_True )
84 {
85     // 8810: vgl. 1170, RightMargin in der letzten Masterzeile...
86     const xub_StrLen nOffset = rPos.nContent.GetIndex();
87     SwTxtFrm *pFrmAtPos = pFrm;
88     if( !bNoScroll || pFrm->GetFollow() )
89     {
90         pFrmAtPos = pFrm->GetFrmAtPos( rPos );
91         if( nOffset < pFrmAtPos->GetOfst() &&
92             !pFrmAtPos->IsFollow() )
93         {
94             xub_StrLen nNew = nOffset;
95             if( nNew < MIN_OFFSET_STEP )
96                 nNew = 0;
97             else
98                 nNew -= MIN_OFFSET_STEP;
99             lcl_ChangeOffset( pFrmAtPos, nNew );
100         }
101     }
102     while( pFrm != pFrmAtPos )
103     {
104         pFrm = pFrmAtPos;
105         pFrm->GetFormatted();
106         pFrmAtPos = (SwTxtFrm*)pFrm->GetFrmAtPos( rPos );
107     }
108 
109     if( nOffset && bRightMargin )
110     {
111         while( pFrmAtPos && pFrmAtPos->GetOfst() == nOffset &&
112                pFrmAtPos->IsFollow() )
113         {
114             pFrmAtPos->GetFormatted();
115             pFrmAtPos = pFrmAtPos->FindMaster();
116         }
117         ASSERT( pFrmAtPos, "+GetCharRect: no frame with my rightmargin" );
118     }
119     return pFrmAtPos ? pFrmAtPos : pFrm;
120 }
121 
122 sal_Bool lcl_ChangeOffset( SwTxtFrm* pFrm, xub_StrLen nNew )
123 {
124     // In Bereichen und ausserhalb von Flies wird nicht mehr gescrollt.
125     ASSERT( !pFrm->IsFollow(), "Illegal Scrolling by Follow!" );
126     if( pFrm->GetOfst() != nNew && !pFrm->IsInSct() )
127     {
128         SwFlyFrm *pFly = pFrm->FindFlyFrm();
129         // Vorsicht, wenn z.B. bei einem spaltigen Rahmen die Groesse noch invalide ist,
130         // duerfen wir nicht mal eben herumscrollen
131         if ( ( pFly && pFly->IsValid() &&
132              !pFly->GetNextLink() && !pFly->GetPrevLink() ) ||
133              ( !pFly && pFrm->IsInTab() ) )
134         {
135             ViewShell* pVsh = pFrm->getRootFrm()->GetCurrShell();
136             if( pVsh )
137             {
138                 if( pVsh->GetNext() != pVsh ||
139                     ( pFrm->GetDrawObjs() && pFrm->GetDrawObjs()->Count() ) )
140                 {
141                     if( !pFrm->GetOfst() )
142                         return sal_False;
143                     nNew = 0;
144                 }
145                 pFrm->SetOfst( nNew );
146                 pFrm->SetPara( 0 );
147                 pFrm->GetFormatted();
148                 if( pFrm->Frm().HasArea() )
149                     pFrm->getRootFrm()->GetCurrShell()->InvalidateWindows( pFrm->Frm() );
150                 return sal_True;
151             }
152         }
153     }
154     return sal_False;
155 }
156 
157 /*************************************************************************
158  *                      GetFrmAtOfst(), GetFrmAtPos()
159  *************************************************************************/
160 
161 // OD 07.10.2003 #110978#
162 SwTxtFrm& SwTxtFrm::GetFrmAtOfst( const xub_StrLen nWhere )
163 {
164     SwTxtFrm* pRet = this;
165     while( pRet->HasFollow() && nWhere >= pRet->GetFollow()->GetOfst() )
166         pRet = pRet->GetFollow();
167     return *pRet;
168 }
169 
170 SwTxtFrm *SwTxtFrm::GetFrmAtPos( const SwPosition &rPos )
171 {
172     SwTxtFrm *pFoll = (SwTxtFrm*)this;
173     while( pFoll->GetFollow() )
174     {
175         if( rPos.nContent.GetIndex() > pFoll->GetFollow()->GetOfst() )
176             pFoll = pFoll->GetFollow();
177         else
178         {
179             if( rPos.nContent.GetIndex() == pFoll->GetFollow()->GetOfst()
180                  && !SwTxtCursor::IsRightMargin() )
181                  pFoll = pFoll->GetFollow();
182             else
183                 break;
184         }
185     }
186     return pFoll;
187 }
188 
189 /*************************************************************************
190  *                      SwTxtFrm::GetCharRect()
191  *************************************************************************/
192 
193 /*
194  * GetCharRect() findet die Characterzelle des Characters, dass
195  * durch aPos beschrieben wird. GetCrsrOfst() findet den
196  * umgekehrten Weg: Von einer Dokumentkoordinate zu einem Pam.
197  * Beide sind virtuell in der Framebasisklasse und werden deshalb
198  * immer angezogen.
199  */
200 
201 sal_Bool SwTxtFrm::GetCharRect( SwRect& rOrig, const SwPosition &rPos,
202                             SwCrsrMoveState *pCMS ) const
203 {
204     ASSERT( ! IsVertical() || ! IsSwapped(),"SwTxtFrm::GetCharRect with swapped frame" );
205 
206     if( IsLocked() || IsHiddenNow() )
207         return sal_False;
208 
209     //Erstmal den richtigen Frm finden, dabei muss beachtet werden, dass:
210     //- die gecachten Informationen verworfen sein koennen (GetPara() == 0)
211     //- das ein Follow gemeint sein kann
212     //- das die Kette der Follows dynamisch waechst; der in den wir
213     //  schliesslich gelangen muss aber Formatiert sein.
214 
215     // opt: reading ahead erspart uns ein GetAdjFrmAtPos
216     const sal_Bool bRightMargin = pCMS && ( MV_RIGHTMARGIN == pCMS->eState );
217     const sal_Bool bNoScroll = pCMS && pCMS->bNoScroll;
218     SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, rPos, bRightMargin,
219                                      bNoScroll );
220     pFrm->GetFormatted();
221     const SwFrm* pTmpFrm = (SwFrm*)pFrm->GetUpper();
222 
223     SWRECTFN ( pFrm )
224     const SwTwips nUpperMaxY = (pTmpFrm->*fnRect->fnGetPrtBottom)();
225     const SwTwips nFrmMaxY = (pFrm->*fnRect->fnGetPrtBottom)();
226 
227     // nMaxY is an absolute value
228     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
229     SwTwips nMaxY = bVert ?
230                     ( bVertL2R ? Min( nFrmMaxY, nUpperMaxY ) : Max( nFrmMaxY, nUpperMaxY ) ) :
231                     Min( nFrmMaxY, nUpperMaxY );
232 
233     sal_Bool bRet = sal_False;
234 
235     if ( pFrm->IsEmpty() || ! (pFrm->Prt().*fnRect->fnGetHeight)() )
236     {
237         Point aPnt1 = pFrm->Frm().Pos() + pFrm->Prt().Pos();
238         SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
239         short nFirstOffset;
240         pTxtNd->GetFirstLineOfsWithNum( nFirstOffset );
241 
242         Point aPnt2;
243         if ( bVert )
244         {
245             if( nFirstOffset > 0 )
246                 aPnt1.Y() += nFirstOffset;
247             //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
248             if ( aPnt1.X() < nMaxY && !bVertL2R )
249                 aPnt1.X() = nMaxY;
250             aPnt2.X() = aPnt1.X() + pFrm->Prt().Width();
251             aPnt2.Y() = aPnt1.Y();
252             if( aPnt2.X() < nMaxY )
253                 aPnt2.X() = nMaxY;
254         }
255         else
256         {
257             if( nFirstOffset > 0 )
258                 aPnt1.X() += nFirstOffset;
259 
260             if( aPnt1.Y() > nMaxY )
261                 aPnt1.Y() = nMaxY;
262             aPnt2.X() = aPnt1.X();
263             aPnt2.Y() = aPnt1.Y() + pFrm->Prt().Height();
264             if( aPnt2.Y() > nMaxY )
265                 aPnt2.Y() = nMaxY;
266         }
267 
268         rOrig = SwRect( aPnt1, aPnt2 );
269 
270         if ( pCMS )
271         {
272             pCMS->aRealHeight.X() = 0;
273             pCMS->aRealHeight.Y() = bVert ? -rOrig.Width() : rOrig.Height();
274         }
275 
276         if ( pFrm->IsRightToLeft() )
277             pFrm->SwitchLTRtoRTL( rOrig );
278 
279         bRet = sal_True;
280     }
281     else
282     {
283         if( !pFrm->HasPara() )
284             return sal_False;
285 
286         SwFrmSwapper aSwapper( pFrm, sal_True );
287         if ( bVert )
288             nMaxY = pFrm->SwitchVerticalToHorizontal( nMaxY );
289 
290         sal_Bool bGoOn = sal_True;
291         xub_StrLen nOffset = rPos.nContent.GetIndex();
292         xub_StrLen nNextOfst;
293 
294         do
295         {
296             {
297                 SwTxtSizeInfo aInf( pFrm );
298                 SwTxtCursor  aLine( pFrm, &aInf );
299                 nNextOfst = aLine.GetEnd();
300                 // Siehe Kommentar in AdjustFrm
301                 // 1170: das letzte Zeichen der Zeile mitnehmen?
302                 bRet = bRightMargin ? aLine.GetEndCharRect( &rOrig, nOffset, pCMS, nMaxY )
303                                 : aLine.GetCharRect( &rOrig, nOffset, pCMS, nMaxY );
304             }
305 
306             if ( pFrm->IsRightToLeft() )
307                 pFrm->SwitchLTRtoRTL( rOrig );
308 
309             if ( bVert )
310                 pFrm->SwitchHorizontalToVertical( rOrig );
311 
312             if( pFrm->IsUndersized() && pCMS && !pFrm->GetNext() &&
313                 (rOrig.*fnRect->fnGetBottom)() == nUpperMaxY &&
314                 pFrm->GetOfst() < nOffset &&
315                 !pFrm->IsFollow() && !bNoScroll &&
316                 pFrm->GetTxtNode()->GetTxt().Len() != nNextOfst )
317                 bGoOn = lcl_ChangeOffset( pFrm, nNextOfst );
318             else
319                 bGoOn = sal_False;
320         } while ( bGoOn );
321 
322         if ( pCMS )
323         {
324             if ( pFrm->IsRightToLeft() )
325             {
326                 if( pCMS->b2Lines && pCMS->p2Lines)
327                 {
328                     pFrm->SwitchLTRtoRTL( pCMS->p2Lines->aLine );
329                     pFrm->SwitchLTRtoRTL( pCMS->p2Lines->aPortion );
330                 }
331             }
332 
333             if ( bVert )
334             {
335                 if ( pCMS->bRealHeight )
336                 {
337                     pCMS->aRealHeight.Y() = -pCMS->aRealHeight.Y();
338                     if ( pCMS->aRealHeight.Y() < 0 )
339                     {
340                         // writing direction is from top to bottom
341                         pCMS->aRealHeight.X() =  ( rOrig.Width() -
342                                                     pCMS->aRealHeight.X() +
343                                                     pCMS->aRealHeight.Y() );
344                     }
345                 }
346                 if( pCMS->b2Lines && pCMS->p2Lines)
347                 {
348                     pFrm->SwitchHorizontalToVertical( pCMS->p2Lines->aLine );
349                     pFrm->SwitchHorizontalToVertical( pCMS->p2Lines->aPortion );
350                 }
351             }
352 
353         }
354     }
355     if( bRet )
356     {
357         SwPageFrm *pPage = pFrm->FindPageFrm();
358         ASSERT( pPage, "Text esaped from page?" );
359         const SwTwips nOrigTop = (rOrig.*fnRect->fnGetTop)();
360         const SwTwips nPageTop = (pPage->Frm().*fnRect->fnGetTop)();
361         const SwTwips nPageBott = (pPage->Frm().*fnRect->fnGetBottom)();
362 
363         // Following situation: if the frame is in an invalid sectionframe,
364         // it's possible that the frame is outside the page. If we restrict
365         // the cursor position to the page area, we enforce the formatting
366         // of the page, of the section frame and the frame himself.
367         if( (*fnRect->fnYDiff)( nPageTop, nOrigTop ) > 0 )
368             (rOrig.*fnRect->fnSetTop)( nPageTop );
369 
370         if ( (*fnRect->fnYDiff)( nOrigTop, nPageBott ) > 0 )
371             (rOrig.*fnRect->fnSetTop)( nPageBott );
372     }
373 
374     return bRet;
375 }
376 
377 /*************************************************************************
378  *                      SwTxtFrm::GetAutoPos()
379  *************************************************************************/
380 
381 /*
382  * GetAutoPos() findet die Characterzelle des Characters, dass
383  * durch aPos beschrieben wird und wird von autopositionierten Rahmen genutzt.
384  */
385 
386 sal_Bool SwTxtFrm::GetAutoPos( SwRect& rOrig, const SwPosition &rPos ) const
387 {
388     if( IsHiddenNow() )
389         return sal_False;
390 
391     xub_StrLen nOffset = rPos.nContent.GetIndex();
392     SwTxtFrm* pFrm = &(const_cast<SwTxtFrm*>(this)->GetFrmAtOfst( nOffset ));
393 
394     pFrm->GetFormatted();
395     const SwFrm* pTmpFrm = (SwFrm*)pFrm->GetUpper();
396 
397     SWRECTFN( pTmpFrm )
398     SwTwips nUpperMaxY = (pTmpFrm->*fnRect->fnGetPrtBottom)();
399 
400     // nMaxY is in absolute value
401     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
402     SwTwips nMaxY = bVert ?
403                     ( bVertL2R ? Min( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY ) : Max( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY ) ) :
404                     Min( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY );
405 
406     if ( pFrm->IsEmpty() || ! (pFrm->Prt().*fnRect->fnGetHeight)() )
407     {
408         Point aPnt1 = pFrm->Frm().Pos() + pFrm->Prt().Pos();
409         Point aPnt2;
410         if ( bVert )
411         {
412             if ( aPnt1.X() < nMaxY && !bVertL2R )
413                 aPnt1.X() = nMaxY;
414 
415             aPnt2.X() = aPnt1.X() + pFrm->Prt().Width();
416             aPnt2.Y() = aPnt1.Y();
417             if( aPnt2.X() < nMaxY )
418                 aPnt2.X() = nMaxY;
419         }
420         else
421         {
422             if( aPnt1.Y() > nMaxY )
423                 aPnt1.Y() = nMaxY;
424             aPnt2.X() = aPnt1.X();
425             aPnt2.Y() = aPnt1.Y() + pFrm->Prt().Height();
426             if( aPnt2.Y() > nMaxY )
427                 aPnt2.Y() = nMaxY;
428         }
429         rOrig = SwRect( aPnt1, aPnt2 );
430         return sal_True;
431     }
432     else
433     {
434         if( !pFrm->HasPara() )
435             return sal_False;
436 
437         SwFrmSwapper aSwapper( pFrm, sal_True );
438         if ( bVert )
439             nMaxY = pFrm->SwitchVerticalToHorizontal( nMaxY );
440 
441         SwTxtSizeInfo aInf( pFrm );
442         SwTxtCursor aLine( pFrm, &aInf );
443         SwCrsrMoveState aTmpState( MV_SETONLYTEXT );
444         aTmpState.bRealHeight = sal_True;
445         if( aLine.GetCharRect( &rOrig, nOffset, &aTmpState, nMaxY ) )
446         {
447             if( aTmpState.aRealHeight.X() >= 0 )
448             {
449                 rOrig.Pos().Y() += aTmpState.aRealHeight.X();
450                 rOrig.Height( aTmpState.aRealHeight.Y() );
451             }
452 
453             if ( pFrm->IsRightToLeft() )
454                 pFrm->SwitchLTRtoRTL( rOrig );
455 
456             if ( bVert )
457                 pFrm->SwitchHorizontalToVertical( rOrig );
458 
459             return sal_True;
460         }
461         return sal_False;
462     }
463 }
464 
465 /** determine top of line for given position in the text frame
466 
467     OD 11.11.2003 #i22341#
468     OD 2004-03-18 #114789# - corrections:
469     - Top of first paragraph line is the top of the printing area of the text frame
470     - If a proportional line spacing is applied use top of anchor character as
471       top of the line.
472 
473     @author OD
474 */
475 bool SwTxtFrm::GetTopOfLine( SwTwips& _onTopOfLine,
476                              const SwPosition& _rPos ) const
477 {
478     bool bRet = true;
479 
480     // get position offset
481     xub_StrLen nOffset = _rPos.nContent.GetIndex();
482 
483     if ( GetTxt().Len() < nOffset )
484     {
485         bRet = false;
486     }
487     else
488     {
489         SWRECTFN( this )
490         if ( IsEmpty() || !(Prt().*fnRect->fnGetHeight)() )
491         {
492             // OD 2004-03-18 #i11860# - consider upper space amount considered
493             // for previous frame and the page grid.
494             _onTopOfLine = (this->*fnRect->fnGetPrtTop)();
495         }
496         else
497         {
498             // determine formatted text frame that contains the requested position
499             SwTxtFrm* pFrm = &(const_cast<SwTxtFrm*>(this)->GetFrmAtOfst( nOffset ));
500             pFrm->GetFormatted();
501             SWREFRESHFN( pFrm )
502             // OD 2004-03-18 #114789# - If proportional line spacing is applied
503             // to the text frame, the top of the anchor character is also the
504             // top of the line.
505             // Otherwise the line layout determines the top of the line
506             const SvxLineSpacingItem& rSpace = GetAttrSet()->GetLineSpacing();
507             if ( rSpace.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP )
508             {
509                 SwRect aCharRect;
510                 if ( GetAutoPos( aCharRect, _rPos ) )
511                 {
512                     _onTopOfLine = (aCharRect.*fnRect->fnGetTop)();
513                 }
514                 else
515                 {
516                     bRet = false;
517                 }
518             }
519             else
520             {
521                 // assure that text frame is in a horizontal layout
522                 SwFrmSwapper aSwapper( pFrm, sal_True );
523                 // determine text line that contains the requested position
524                 SwTxtSizeInfo aInf( pFrm );
525                 SwTxtCursor aLine( pFrm, &aInf );
526                 aLine.CharCrsrToLine( nOffset );
527                 // determine top of line
528                 _onTopOfLine = aLine.Y();
529                 if ( bVert )
530                 {
531                     _onTopOfLine = pFrm->SwitchHorizontalToVertical( _onTopOfLine );
532                 }
533             }
534         }
535     }
536 
537     return bRet;
538 }
539 
540 /*************************************************************************
541  *                      SwTxtFrm::_GetCrsrOfst()
542  *************************************************************************/
543 
544 // Minimaler Abstand von nichtleeren Zeilen etwas weniger als 2 cm
545 #define FILL_MIN_DIST 1100
546 
547 struct SwFillData
548 {
549     SwRect aFrm;
550     const SwCrsrMoveState *pCMS;
551     SwPosition* pPos;
552     const Point& rPoint;
553     SwTwips nLineWidth;
554     sal_Bool bFirstLine : 1;
555     sal_Bool bInner     : 1;
556     sal_Bool bColumn    : 1;
557     sal_Bool bEmpty     : 1;
558     SwFillData( const SwCrsrMoveState *pC, SwPosition* pP, const SwRect& rR,
559         const Point& rPt ) : aFrm( rR ), pCMS( pC ), pPos( pP ), rPoint( rPt ),
560         nLineWidth( 0 ), bFirstLine( sal_True ), bInner( sal_False ), bColumn( sal_False ),
561         bEmpty( sal_True ){}
562     SwFillMode Mode() const { return pCMS->pFill->eMode; }
563     long X() const { return rPoint.X(); }
564     long Y() const { return rPoint.Y(); }
565     long Left() const { return aFrm.Left(); }
566     long Right() const { return aFrm.Right(); }
567     long Bottom() const { return aFrm.Bottom(); }
568     SwRect& Frm() { return aFrm; }
569     SwFillCrsrPos &Fill() const { return *pCMS->pFill; }
570     void SetTab( MSHORT nNew ) { pCMS->pFill->nTabCnt = nNew; }
571     void SetSpace( MSHORT nNew ) { pCMS->pFill->nSpaceCnt = nNew; }
572     void SetOrient( const sal_Int16 eNew ){ pCMS->pFill->eOrient = eNew; }
573 };
574 
575 sal_Bool SwTxtFrm::_GetCrsrOfst(SwPosition* pPos, const Point& rPoint,
576                     const sal_Bool bChgFrm, SwCrsrMoveState* pCMS ) const
577 {
578     // 8804: _GetCrsrOfst wird vom GetCrsrOfst und GetKeyCrsrOfst gerufen.
579     // In keinem Fall nur ein return sal_False.
580 
581     if( IsLocked() || IsHiddenNow() )
582         return sal_False;
583 
584     ((SwTxtFrm*)this)->GetFormatted();
585 
586     Point aOldPoint( rPoint );
587 
588     if ( IsVertical() )
589     {
590         SwitchVerticalToHorizontal( (Point&)rPoint );
591         ((SwTxtFrm*)this)->SwapWidthAndHeight();
592     }
593 
594     if ( IsRightToLeft() )
595         SwitchRTLtoLTR( (Point&)rPoint );
596 
597     SwFillData *pFillData = ( pCMS && pCMS->pFill ) ?
598                         new SwFillData( pCMS, pPos, Frm(), rPoint ) : NULL;
599 
600     if ( IsEmpty() )
601     {
602         SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
603         pPos->nNode = *pTxtNd;
604         pPos->nContent.Assign( pTxtNd, 0 );
605         if( pCMS && pCMS->bFieldInfo )
606         {
607             SwTwips nDiff = rPoint.X() - Frm().Left() - Prt().Left();
608             if( nDiff > 50 || nDiff < 0 )
609                 ((SwCrsrMoveState*)pCMS)->bPosCorr = sal_True;
610         }
611     }
612     else
613     {
614         SwTxtSizeInfo aInf( (SwTxtFrm*)this );
615         SwTxtCursor  aLine( ((SwTxtFrm*)this), &aInf );
616 
617         // Siehe Kommentar in AdjustFrm()
618         SwTwips nMaxY = Frm().Top() + Prt().Top() + Prt().Height();
619         aLine.TwipsToLine( rPoint.Y() );
620         while( aLine.Y() + aLine.GetLineHeight() > nMaxY )
621         {
622             DBG_LOOP;
623             if( !aLine.Prev() )
624                 break;
625         }
626 
627         if( aLine.GetDropLines() >= aLine.GetLineNr() && 1 != aLine.GetLineNr()
628             && rPoint.X() < aLine.FirstLeft() + aLine.GetDropLeft() )
629             while( aLine.GetLineNr() > 1 )
630                 aLine.Prev();
631 
632         xub_StrLen nOffset = aLine.GetCrsrOfst( pPos, rPoint, bChgFrm, pCMS );
633 
634         if( pCMS && pCMS->eState == MV_NONE && aLine.GetEnd() == nOffset )
635             ((SwCrsrMoveState*)pCMS)->eState = MV_RIGHTMARGIN;
636 
637     // 6776: pPos ist ein reiner IN-Parameter, der nicht ausgewertet werden darf.
638     // Das pIter->GetCrsrOfst returnt aus einer Verschachtelung mit STRING_LEN.
639     // Wenn SwTxtIter::GetCrsrOfst von sich aus weitere GetCrsrOfst
640     // ruft, so aendert sich nNode der Position. In solchen Faellen
641     // darf pPos nicht berechnet werden.
642         if( STRING_LEN != nOffset )
643         {
644             SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
645             pPos->nNode = *pTxtNd;
646             pPos->nContent.Assign( pTxtNd, nOffset );
647             if( pFillData )
648             {
649                 if( pTxtNd->GetTxt().Len() > nOffset ||
650                     rPoint.Y() < Frm().Top() )
651                     pFillData->bInner = sal_True;
652                 pFillData->bFirstLine = aLine.GetLineNr() < 2;
653                 if( pTxtNd->GetTxt().Len() )
654                 {
655                     pFillData->bEmpty = sal_False;
656                     pFillData->nLineWidth = aLine.GetCurr()->Width();
657                 }
658             }
659         }
660     }
661     sal_Bool bChgFillData = sal_False;
662     if( pFillData && FindPageFrm()->Frm().IsInside( aOldPoint ) )
663     {
664         FillCrsrPos( *pFillData );
665         bChgFillData = sal_True;
666     }
667 
668     if ( IsVertical() )
669     {
670         if ( bChgFillData )
671             SwitchHorizontalToVertical( pFillData->Fill().aCrsr.Pos() );
672         ((SwTxtFrm*)this)->SwapWidthAndHeight();
673     }
674 
675     if ( IsRightToLeft() && bChgFillData )
676     {
677             SwitchLTRtoRTL( pFillData->Fill().aCrsr.Pos() );
678             const sal_Int16 eOrient = pFillData->pCMS->pFill->eOrient;
679 
680             if ( text::HoriOrientation::LEFT == eOrient )
681                 pFillData->SetOrient( text::HoriOrientation::RIGHT );
682             else if ( text::HoriOrientation::RIGHT == eOrient )
683                 pFillData->SetOrient( text::HoriOrientation::LEFT );
684     }
685 
686     (Point&)rPoint = aOldPoint;
687     delete pFillData;
688 
689     return sal_True;
690 }
691 
692 /*************************************************************************
693  *                 virtual SwTxtFrm::GetCrsrOfst()
694  *************************************************************************/
695 
696 sal_Bool SwTxtFrm::GetCrsrOfst(SwPosition* pPos, Point& rPoint,
697                                SwCrsrMoveState* pCMS ) const
698 {
699     MSHORT nChgFrm = 2;
700     if( pCMS )
701     {
702         if( MV_UPDOWN == pCMS->eState )
703             nChgFrm = 0;
704         else if( MV_SETONLYTEXT == pCMS->eState ||
705                  MV_TBLSEL == pCMS->eState )
706             nChgFrm = 1;
707     }
708     return _GetCrsrOfst( pPos, rPoint, nChgFrm != 0, pCMS );
709 }
710 
711 /*************************************************************************
712  *                      SwTxtFrm::LeftMargin()
713  *************************************************************************/
714 
715 /*
716  * Layout-orientierte Cursorbewegungen
717  */
718 
719 /*
720  * an den Zeilenanfang
721  */
722 
723 sal_Bool SwTxtFrm::LeftMargin(SwPaM *pPam) const
724 {
725     if( ((const SwNode*)pPam->GetNode()) != GetNode() )
726         pPam->GetPoint()->nNode = *((SwTxtFrm*)this)->GetTxtNode();
727 
728     SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *pPam->GetPoint(),
729                                      SwTxtCursor::IsRightMargin() );
730     pFrm->GetFormatted();
731     xub_StrLen nIndx;
732     if ( pFrm->IsEmpty() )
733         nIndx = 0;
734     else
735     {
736         SwTxtSizeInfo aInf( pFrm );
737         SwTxtCursor  aLine( pFrm, &aInf );
738 
739         aLine.CharCrsrToLine(pPam->GetPoint()->nContent.GetIndex());
740         nIndx = aLine.GetStart();
741         if( pFrm->GetOfst() && !pFrm->IsFollow() && !aLine.GetPrev() )
742         {
743             lcl_ChangeOffset( pFrm, 0 );
744             nIndx = 0;
745         }
746     }
747     pPam->GetPoint()->nContent = SwIndex( pFrm->GetTxtNode(), nIndx );
748     SwTxtCursor::SetRightMargin( sal_False );
749     return sal_True;
750 }
751 
752 /*************************************************************************
753  *                      SwTxtFrm::RightMargin()
754  *************************************************************************/
755 
756 /*
757  * An das Zeilenende:Das ist die Position vor dem letzten
758  * Character in der Zeile. Ausnahme: In der letzten Zeile soll
759  * der Cursor auch hinter dem letzten Character stehen koennen,
760  * um Text anhaengen zu koennen.
761  *
762  */
763 
764 sal_Bool SwTxtFrm::RightMargin(SwPaM *pPam, sal_Bool bAPI) const
765 {
766     if( ((const SwNode*)pPam->GetNode()) != GetNode() )
767         pPam->GetPoint()->nNode = *((SwTxtFrm*)this)->GetTxtNode();
768 
769     SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *pPam->GetPoint(),
770                                      SwTxtCursor::IsRightMargin() );
771     pFrm->GetFormatted();
772     xub_StrLen nRightMargin;
773     if ( IsEmpty() )
774         nRightMargin = 0;
775     else
776     {
777         SwTxtSizeInfo aInf( pFrm );
778         SwTxtCursor  aLine( pFrm, &aInf );
779 
780         aLine.CharCrsrToLine(pPam->GetPoint()->nContent.GetIndex());
781         nRightMargin = aLine.GetStart() + aLine.GetCurr()->GetLen();
782 
783         // Harte Zeilenumbrueche lassen wir hinter uns.
784         if( aLine.GetCurr()->GetLen() &&
785             CH_BREAK == aInf.GetTxt().GetChar( nRightMargin - 1 ) )
786             --nRightMargin;
787         else if( !bAPI && (aLine.GetNext() || pFrm->GetFollow()) )
788         {
789             while( nRightMargin > aLine.GetStart() &&
790                 ' ' == aInf.GetTxt().GetChar( nRightMargin - 1 ) )
791                 --nRightMargin;
792         }
793     }
794     pPam->GetPoint()->nContent = SwIndex( pFrm->GetTxtNode(), nRightMargin );
795     SwTxtCursor::SetRightMargin( !bAPI );
796     return sal_True;
797 }
798 
799 /*************************************************************************
800  *                      SwTxtFrm::_UnitUp()
801  *************************************************************************/
802 
803 //Die beiden folgenden Methoden versuchen zunaechst den Crsr in die
804 //nachste/folgende Zeile zu setzen. Gibt es im Frame keine vorhergehende/
805 //folgende Zeile, so wird der Aufruf an die Basisklasse weitergeleitet.
806 //Die Horizontale Ausrichtung des Crsr wird hinterher von der CrsrShell
807 //vorgenommen.
808 
809 class SwSetToRightMargin
810 {
811     sal_Bool bRight;
812 public:
813     inline SwSetToRightMargin() : bRight( sal_False ) { }
814     inline ~SwSetToRightMargin() { SwTxtCursor::SetRightMargin( bRight ); }
815     inline void SetRight( const sal_Bool bNew ) { bRight = bNew; }
816 };
817 
818 sal_Bool SwTxtFrm::_UnitUp( SwPaM *pPam, const SwTwips nOffset,
819                             sal_Bool bSetInReadOnly ) const
820 {
821     // 8626: Im Notfall den RightMargin setzen.
822     SwSetToRightMargin aSet;
823 
824     if( IsInTab() &&
825         pPam->GetNode( sal_True )->StartOfSectionNode() !=
826         pPam->GetNode( sal_False )->StartOfSectionNode() )
827     {
828         //Wenn der PaM in unterschiedlichen Boxen sitzt, so handelt es sich um
829         //eine Tabellenselektion; diese wird von der Basisklasse abgearbeitet.
830         return SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
831     }
832 
833     ((SwTxtFrm*)this)->GetFormatted();
834     const xub_StrLen nPos = pPam->GetPoint()->nContent.GetIndex();
835     SwRect aCharBox;
836 
837     if( !IsEmpty() && !IsHiddenNow() )
838     {
839         xub_StrLen nFormat = STRING_LEN;
840         do
841         {
842             if( nFormat != STRING_LEN && !IsFollow() )
843                 lcl_ChangeOffset( ((SwTxtFrm*)this), nFormat );
844 
845             SwTxtSizeInfo aInf( (SwTxtFrm*)this );
846             SwTxtCursor  aLine( ((SwTxtFrm*)this), &aInf );
847 
848             // 8116: Flys ohne Umlauf und IsDummy(); hier wegoptimiert
849             if( nPos )
850                 aLine.CharCrsrToLine( nPos );
851             else
852                 aLine.Top();
853 
854             const SwLineLayout *pPrevLine = aLine.GetPrevLine();
855             const xub_StrLen nStart = aLine.GetStart();
856             aLine.GetCharRect( &aCharBox, nPos );
857 
858             sal_Bool bSecondOfDouble = ( aInf.IsMulti() && ! aInf.IsFirstMulti() );
859             sal_Bool bPrevLine = ( pPrevLine && pPrevLine != aLine.GetCurr() );
860 
861             if( !pPrevLine && !bSecondOfDouble && GetOfst() && !IsFollow() )
862             {
863                 nFormat = GetOfst();
864                 xub_StrLen nDiff = aLine.GetLength();
865                 if( !nDiff )
866                     nDiff = MIN_OFFSET_STEP;
867                 if( nFormat > nDiff )
868                     nFormat = nFormat - nDiff;
869                 else
870                     nFormat = 0;
871                 continue;
872             }
873 
874             // we select the target line for the cursor, in case we are in a
875             // double line portion, prev line = curr line
876             if( bPrevLine && !bSecondOfDouble )
877             {
878                 aLine.PrevLine();
879                 while ( aLine.GetStart() == nStart &&
880                         0 != ( pPrevLine = aLine.GetPrevLine() ) &&
881                         pPrevLine != aLine.GetCurr() )
882                     aLine.PrevLine();
883             }
884 
885             if ( bPrevLine || bSecondOfDouble )
886             {
887                 aCharBox.SSize().Width() /= 2;
888                 aCharBox.Pos().X() = aCharBox.Pos().X() - 150;
889 
890                 // siehe Kommentar in SwTxtFrm::GetCrsrOfst()
891 #ifdef DBG_UTIL
892                 const sal_uLong nOldNode = pPam->GetPoint()->nNode.GetIndex();
893 #endif
894                 // Der Node soll nicht gewechselt werden
895                 xub_StrLen nTmpOfst = aLine.GetCrsrOfst( pPam->GetPoint(),
896                                                          aCharBox.Pos(), sal_False );
897                 ASSERT( nOldNode == pPam->GetPoint()->nNode.GetIndex(),
898                         "SwTxtFrm::UnitUp: illegal node change" )
899 
900                 // 7684: Wir stellen sicher, dass wir uns nach oben bewegen.
901                 if( nTmpOfst >= nStart && nStart && !bSecondOfDouble )
902                 {
903                     nTmpOfst = nStart;
904                     aSet.SetRight( sal_True );
905                 }
906                 pPam->GetPoint()->nContent =
907                       SwIndex( ((SwTxtFrm*)this)->GetTxtNode(), nTmpOfst );
908                 return sal_True;
909             }
910 
911             if ( IsFollow() )
912             {
913                 aLine.GetCharRect( &aCharBox, nPos );
914                 aCharBox.SSize().Width() /= 2;
915             }
916             break;
917         } while ( sal_True );
918     }
919     /* Wenn this ein Follow ist und ein Prev miszlang, so
920      * muessen wir in die letzte Zeile des Master ... und der sind wir.
921      * Oder wir sind ein Follow mit Follow, dann muessen wir uns den
922      * Master extra besorgen...
923      */
924     if ( IsFollow() )
925     {
926         const SwTxtFrm *pTmpPrev = FindMaster();
927         xub_StrLen nOffs = GetOfst();
928         if( pTmpPrev )
929         {
930             ViewShell *pSh = getRootFrm()->GetCurrShell();
931             sal_Bool bProtectedAllowed = pSh && pSh->GetViewOptions()->IsCursorInProtectedArea();
932             const SwTxtFrm *pPrevPrev = pTmpPrev;
933             // Hier werden geschuetzte Frames und Frame ohne Inhalt ausgelassen
934             while( pPrevPrev && ( pPrevPrev->GetOfst() == nOffs ||
935                    ( !bProtectedAllowed && pPrevPrev->IsProtected() ) ) )
936             {
937                 pTmpPrev = pPrevPrev;
938                 nOffs = pTmpPrev->GetOfst();
939                 if ( pPrevPrev->IsFollow() )
940                     pPrevPrev = pTmpPrev->FindMaster();
941                 else
942                     pPrevPrev = NULL;
943             }
944             if ( !pPrevPrev )
945                 return pTmpPrev->SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
946             aCharBox.Pos().Y() = pPrevPrev->Frm().Bottom() - 1;
947             return pPrevPrev->GetKeyCrsrOfst( pPam->GetPoint(), aCharBox.Pos() );
948         }
949     }
950     return SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
951 }
952 
953 //
954 // Used for Bidi. nPos is the logical position in the string, bLeft indicates
955 // if left arrow or right arrow was pressed. The return values are:
956 // nPos: the new visual position
957 // bLeft: whether the break iterator has to add or subtract from the
958 //          current position
959 void lcl_VisualMoveRecursion( const SwLineLayout& rCurrLine, xub_StrLen nIdx,
960                               xub_StrLen& nPos, sal_Bool& bRight,
961                               sal_uInt8& nCrsrLevel, sal_uInt8 nDefaultDir )
962 {
963     const SwLinePortion* pPor = rCurrLine.GetFirstPortion();
964     const SwLinePortion* pLast = 0;
965 
966     // what's the current portion
967     while ( pPor && nIdx + pPor->GetLen() <= nPos )
968     {
969         nIdx = nIdx + pPor->GetLen();
970         pLast = pPor;
971         pPor = pPor->GetPortion();
972     }
973 
974     if ( bRight )
975     {
976         sal_Bool bRecurse = pPor && pPor->IsMultiPortion() &&
977                            ((SwMultiPortion*)pPor)->IsBidi();
978 
979         // 1. special case: at beginning of bidi portion
980         if ( bRecurse && nIdx == nPos )
981         {
982             nPos = nPos + pPor->GetLen();
983 
984             // leave bidi portion
985             if ( nCrsrLevel != nDefaultDir )
986             {
987                 bRecurse = sal_False;
988             }
989             else
990                 // special case:
991                 // buffer: abcXYZ123 in LTR paragraph
992                 // view:   abc123ZYX
993                 // cursor is between c and X in the buffer and cursor level = 0
994                 nCrsrLevel++;
995         }
996 
997         // 2. special case: at beginning of portion after bidi portion
998         else if ( pLast && pLast->IsMultiPortion() &&
999                  ((SwMultiPortion*)pLast)->IsBidi() && nIdx == nPos )
1000         {
1001             // enter bidi portion
1002             if ( nCrsrLevel != nDefaultDir )
1003             {
1004                 bRecurse = sal_True;
1005                 nIdx = nIdx - pLast->GetLen();
1006                 pPor = pLast;
1007             }
1008         }
1009 
1010         // Recursion
1011         if ( bRecurse )
1012         {
1013             const SwLineLayout& rLine = ((SwMultiPortion*)pPor)->GetRoot();
1014             xub_StrLen nTmpPos = nPos - nIdx;
1015             sal_Bool bTmpForward = ! bRight;
1016             sal_uInt8 nTmpCrsrLevel = nCrsrLevel;
1017             lcl_VisualMoveRecursion( rLine, 0, nTmpPos, bTmpForward,
1018                                      nTmpCrsrLevel, nDefaultDir + 1 );
1019 
1020             nPos = nTmpPos + nIdx;
1021             bRight = bTmpForward;
1022             nCrsrLevel = nTmpCrsrLevel;
1023         }
1024 
1025         // go forward
1026         else
1027         {
1028             bRight = sal_True;
1029             nCrsrLevel = nDefaultDir;
1030         }
1031 
1032     }
1033     else
1034     {
1035         sal_Bool bRecurse = pPor && pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi();
1036 
1037         // 1. special case: at beginning of bidi portion
1038         if ( bRecurse && nIdx == nPos )
1039         {
1040             // leave bidi portion
1041             if ( nCrsrLevel == nDefaultDir )
1042             {
1043                 bRecurse = sal_False;
1044             }
1045         }
1046 
1047         // 2. special case: at beginning of portion after bidi portion
1048         else if ( pLast && pLast->IsMultiPortion() &&
1049                  ((SwMultiPortion*)pLast)->IsBidi() && nIdx == nPos )
1050         {
1051             nPos = nPos - pLast->GetLen();
1052 
1053             // enter bidi portion
1054             if ( nCrsrLevel % 2 == nDefaultDir % 2 )
1055             {
1056                 bRecurse = sal_True;
1057                 nIdx = nIdx - pLast->GetLen();
1058                 pPor = pLast;
1059 
1060                 // special case:
1061                 // buffer: abcXYZ123 in LTR paragraph
1062                 // view:   abc123ZYX
1063                 // cursor is behind 3 in the buffer and cursor level = 2
1064                 if ( nDefaultDir + 2 == nCrsrLevel )
1065                     nPos = nPos + pLast->GetLen();
1066             }
1067         }
1068 
1069         // go forward
1070         if ( bRecurse )
1071         {
1072             const SwLineLayout& rLine = ((SwMultiPortion*)pPor)->GetRoot();
1073             xub_StrLen nTmpPos = nPos - nIdx;
1074             sal_Bool bTmpForward = ! bRight;
1075             sal_uInt8 nTmpCrsrLevel = nCrsrLevel;
1076             lcl_VisualMoveRecursion( rLine, 0, nTmpPos, bTmpForward,
1077                                      nTmpCrsrLevel, nDefaultDir + 1 );
1078 
1079             // special case:
1080             // buffer: abcXYZ123 in LTR paragraph
1081             // view:   abc123ZYX
1082             // cursor is between Z and 1 in the buffer and cursor level = 2
1083             if ( nTmpPos == pPor->GetLen() && nTmpCrsrLevel == nDefaultDir + 1 )
1084             {
1085                 nTmpPos = nTmpPos - pPor->GetLen();
1086                 nTmpCrsrLevel = nDefaultDir;
1087                 bTmpForward = ! bTmpForward;
1088             }
1089 
1090             nPos = nTmpPos + nIdx;
1091             bRight = bTmpForward;
1092             nCrsrLevel = nTmpCrsrLevel;
1093         }
1094 
1095         // go backward
1096         else
1097         {
1098             bRight = sal_False;
1099             nCrsrLevel = nDefaultDir;
1100         }
1101     }
1102 }
1103 
1104 void SwTxtFrm::PrepareVisualMove( xub_StrLen& nPos, sal_uInt8& nCrsrLevel,
1105                                   sal_Bool& bForward, sal_Bool bInsertCrsr )
1106 {
1107     if( IsEmpty() || IsHiddenNow() )
1108         return;
1109 
1110     ((SwTxtFrm*)this)->GetFormatted();
1111 
1112     SwTxtSizeInfo aInf( (SwTxtFrm*)this );
1113     SwTxtCursor  aLine( ((SwTxtFrm*)this), &aInf );
1114 
1115     if( nPos )
1116         aLine.CharCrsrToLine( nPos );
1117     else
1118         aLine.Top();
1119 
1120     const SwLineLayout* pLine = aLine.GetCurr();
1121     const xub_StrLen nStt = aLine.GetStart();
1122     const xub_StrLen nLen = pLine->GetLen();
1123 
1124     // We have to distinguish between an insert and overwrite cursor:
1125     // The insert cursor position depends on the cursor level:
1126     // buffer:  abcXYZdef in LTR paragraph
1127     // display: abcZYXdef
1128     // If cursor is between c and X in the buffer and cursor level is 0,
1129     // the cursor blinks between c and Z and -> sets the cursor between Z and Y.
1130     // If the cursor level is 1, the cursor blinks between X and d and
1131     // -> sets the cursor between d and e.
1132     // The overwrite cursor simply travels to the next visual character.
1133     if ( bInsertCrsr )
1134     {
1135         lcl_VisualMoveRecursion( *pLine, nStt, nPos, bForward,
1136                                  nCrsrLevel, IsRightToLeft() ? 1 : 0 );
1137         return;
1138     }
1139 
1140     const sal_uInt8 nDefaultDir = static_cast<sal_uInt8>(IsRightToLeft() ? UBIDI_RTL : UBIDI_LTR);
1141     const sal_Bool bVisualRight = ( nDefaultDir == UBIDI_LTR && bForward ) ||
1142                                   ( nDefaultDir == UBIDI_RTL && ! bForward );
1143 
1144     //
1145     // Bidi functions from icu 2.0
1146     //
1147     const sal_Unicode* pLineString = GetTxtNode()->GetTxt().GetBuffer();
1148     pLine += nStt;
1149 
1150     UErrorCode nError = U_ZERO_ERROR;
1151     UBiDi* pBidi = ubidi_openSized( nLen, 0, &nError );
1152     ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(pLineString), nLen, nDefaultDir, NULL, &nError ); // UChar != sal_Unicode in MinGW
1153 
1154     xub_StrLen nTmpPos;
1155     sal_Bool bOutOfBounds = sal_False;
1156 
1157     if ( nPos < nStt + nLen )
1158     {
1159         nTmpPos = (xub_StrLen)ubidi_getVisualIndex( pBidi, nPos, &nError );
1160 
1161         // visual indices are always LTR aligned
1162         if ( bVisualRight )
1163         {
1164             if ( nTmpPos + 1 < nStt + nLen )
1165                 ++nTmpPos;
1166             else
1167             {
1168                 nPos = nDefaultDir == UBIDI_RTL ? 0 : nStt + nLen;
1169                 bOutOfBounds = sal_True;
1170             }
1171         }
1172         else
1173         {
1174             if ( nTmpPos )
1175                 --nTmpPos;
1176             else
1177             {
1178                 nPos = nDefaultDir == UBIDI_RTL ? nStt + nLen : 0;
1179                 bOutOfBounds = sal_True;
1180             }
1181         }
1182     }
1183     else
1184     {
1185         nTmpPos = nDefaultDir == UBIDI_LTR ? nPos - 1 : 0;
1186     }
1187 
1188     if ( ! bOutOfBounds )
1189     {
1190         nPos = (xub_StrLen)ubidi_getLogicalIndex( pBidi, nTmpPos, &nError );
1191 
1192         if ( bForward )
1193         {
1194             if ( nPos )
1195                 --nPos;
1196             else
1197             {
1198                 ++nPos;
1199                 bForward = ! bForward;
1200             }
1201         }
1202         else
1203             ++nPos;
1204     }
1205 
1206     ubidi_close( pBidi );
1207 }
1208 
1209 /*************************************************************************
1210  *                      SwTxtFrm::_UnitDown()
1211  *************************************************************************/
1212 
1213 sal_Bool SwTxtFrm::_UnitDown(SwPaM *pPam, const SwTwips nOffset,
1214                             sal_Bool bSetInReadOnly ) const
1215 {
1216 
1217     if ( IsInTab() &&
1218         pPam->GetNode( sal_True )->StartOfSectionNode() !=
1219         pPam->GetNode( sal_False )->StartOfSectionNode() )
1220     {
1221         //Wenn der PaM in unterschiedlichen Boxen sitzt, so handelt es sich um
1222         //eine Tabellenselektion; diese wird von der Basisklasse abgearbeitet.
1223         return SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
1224     }
1225     ((SwTxtFrm*)this)->GetFormatted();
1226     const xub_StrLen nPos = pPam->GetPoint()->nContent.GetIndex();
1227     SwRect aCharBox;
1228     const SwCntntFrm *pTmpFollow = 0;
1229 
1230     if ( IsVertical() )
1231         ((SwTxtFrm*)this)->SwapWidthAndHeight();
1232 
1233     if ( !IsEmpty() && !IsHiddenNow() )
1234     {
1235         xub_StrLen nFormat = STRING_LEN;
1236         do
1237         {
1238             if( nFormat != STRING_LEN && !IsFollow() &&
1239                 !lcl_ChangeOffset( ((SwTxtFrm*)this), nFormat ) )
1240                 break;
1241 
1242             SwTxtSizeInfo aInf( (SwTxtFrm*)this );
1243             SwTxtCursor  aLine( ((SwTxtFrm*)this), &aInf );
1244             nFormat = aLine.GetEnd();
1245 
1246             aLine.CharCrsrToLine( nPos );
1247 
1248             const SwLineLayout* pNextLine = aLine.GetNextLine();
1249             const xub_StrLen nStart = aLine.GetStart();
1250             aLine.GetCharRect( &aCharBox, nPos );
1251 
1252             sal_Bool bFirstOfDouble = ( aInf.IsMulti() && aInf.IsFirstMulti() );
1253 
1254             if( pNextLine || bFirstOfDouble )
1255             {
1256                 aCharBox.SSize().Width() /= 2;
1257 #ifdef DBG_UTIL
1258                 // siehe Kommentar in SwTxtFrm::GetCrsrOfst()
1259                 const sal_uLong nOldNode = pPam->GetPoint()->nNode.GetIndex();
1260 #endif
1261                 if ( pNextLine && ! bFirstOfDouble )
1262                     aLine.NextLine();
1263 
1264                 xub_StrLen nTmpOfst = aLine.GetCrsrOfst( pPam->GetPoint(),
1265                                  aCharBox.Pos(), sal_False );
1266                 ASSERT( nOldNode == pPam->GetPoint()->nNode.GetIndex(),
1267                     "SwTxtFrm::UnitDown: illegal node change" )
1268 
1269                 // 7684: Wir stellen sicher, dass wir uns nach unten bewegen.
1270                 if( nTmpOfst <= nStart && ! bFirstOfDouble )
1271                     nTmpOfst = nStart + 1;
1272                 pPam->GetPoint()->nContent =
1273                       SwIndex( ((SwTxtFrm*)this)->GetTxtNode(), nTmpOfst );
1274 
1275                 if ( IsVertical() )
1276                     ((SwTxtFrm*)this)->SwapWidthAndHeight();
1277 
1278                 return sal_True;
1279             }
1280             if( 0 != ( pTmpFollow = GetFollow() ) )
1281             {   // geschuetzte Follows auslassen
1282                 const SwCntntFrm* pTmp = pTmpFollow;
1283                 ViewShell *pSh = getRootFrm()->GetCurrShell();
1284                 if( !pSh || !pSh->GetViewOptions()->IsCursorInProtectedArea() )
1285                 {
1286                     while( pTmpFollow && pTmpFollow->IsProtected() )
1287                     {
1288                         pTmp = pTmpFollow;
1289                         pTmpFollow = pTmpFollow->GetFollow();
1290                     }
1291                 }
1292                 if( !pTmpFollow ) // nur noch geschuetzte
1293                 {
1294                     if ( IsVertical() )
1295                         ((SwTxtFrm*)this)->SwapWidthAndHeight();
1296                     return pTmp->SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
1297                 }
1298 
1299                 aLine.GetCharRect( &aCharBox, nPos );
1300                 aCharBox.SSize().Width() /= 2;
1301             }
1302             else if( !IsFollow() )
1303             {
1304                 xub_StrLen nTmpLen = aInf.GetTxt().Len();
1305                 if( aLine.GetEnd() < nTmpLen )
1306                 {
1307                     if( nFormat <= GetOfst() )
1308                     {
1309                         nFormat = Min( xub_StrLen( GetOfst() + MIN_OFFSET_STEP ),
1310                                        nTmpLen );
1311                         if( nFormat <= GetOfst() )
1312                             break;
1313                     }
1314                     continue;
1315                 }
1316             }
1317             break;
1318         } while( sal_True );
1319     }
1320     else
1321         pTmpFollow = GetFollow();
1322 
1323     if ( IsVertical() )
1324         ((SwTxtFrm*)this)->SwapWidthAndHeight();
1325 
1326     // Bei Follows schlagen wir eine Abkuerzung
1327     if( pTmpFollow )
1328     {
1329         aCharBox.Pos().Y() = pTmpFollow->Frm().Top() + 1;
1330         return ((SwTxtFrm*)pTmpFollow)->GetKeyCrsrOfst( pPam->GetPoint(),
1331                                                      aCharBox.Pos() );
1332     }
1333     return SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
1334 }
1335 
1336 /*************************************************************************
1337  *                   virtual SwTxtFrm::UnitUp()
1338  *************************************************************************/
1339 
1340 sal_Bool SwTxtFrm::UnitUp(SwPaM *pPam, const SwTwips nOffset,
1341                             sal_Bool bSetInReadOnly ) const
1342 {
1343     /* Im CrsrSh::Up() wird CntntNode::GetFrm() gerufen.
1344      * Dies liefert _immer_ den Master zurueck.
1345      * Um das Cursortravelling nicht zu belasten, korrigieren wir
1346      * hier im SwTxtFrm.
1347      * Wir ermittelt UnitUp fuer pFrm, pFrm ist entweder ein Master (=this)
1348      * oder ein Follow (!=this)
1349      */
1350     const SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *(pPam->GetPoint()),
1351                                            SwTxtCursor::IsRightMargin() );
1352     const sal_Bool bRet = pFrm->_UnitUp( pPam, nOffset, bSetInReadOnly );
1353 
1354     // 8626: kein SwTxtCursor::SetRightMargin( sal_False );
1355     // statt dessen steht ein SwSetToRightMargin im _UnitUp
1356     return bRet;
1357 }
1358 
1359 /*************************************************************************
1360  *                   virtual SwTxtFrm::UnitDown()
1361  *************************************************************************/
1362 
1363 sal_Bool SwTxtFrm::UnitDown(SwPaM *pPam, const SwTwips nOffset,
1364                             sal_Bool bSetInReadOnly ) const
1365 {
1366     const SwTxtFrm *pFrm = GetAdjFrmAtPos((SwTxtFrm*)this, *(pPam->GetPoint()),
1367                                            SwTxtCursor::IsRightMargin() );
1368     const sal_Bool bRet = pFrm->_UnitDown( pPam, nOffset, bSetInReadOnly );
1369     SwTxtCursor::SetRightMargin( sal_False );
1370     return bRet;
1371 }
1372 
1373 void SwTxtFrm::FillCrsrPos( SwFillData& rFill ) const
1374 {
1375     if( !rFill.bColumn && GetUpper()->IsColBodyFrm() ) // ColumnFrms jetzt mit BodyFrm
1376     {
1377         const SwColumnFrm* pTmp =
1378             (SwColumnFrm*)GetUpper()->GetUpper()->GetUpper()->Lower(); // die 1. Spalte
1379         // der erste SwFrm im BodyFrm der ersten Spalte
1380         const SwFrm* pFrm = ((SwLayoutFrm*)pTmp->Lower())->Lower();
1381         MSHORT nNextCol = 0;
1382         // In welcher Spalte landen wir?
1383         while( rFill.X() > pTmp->Frm().Right() && pTmp->GetNext() )
1384         {
1385             pTmp = (SwColumnFrm*)pTmp->GetNext();
1386             if( ((SwLayoutFrm*)pTmp->Lower())->Lower() ) // ColumnFrms jetzt mit BodyFrm
1387             {
1388                 pFrm = ((SwLayoutFrm*)pTmp->Lower())->Lower();
1389                 nNextCol = 0;
1390             }
1391             else
1392                 ++nNextCol; // leere Spalten erfordern Spaltenumbrueche
1393         }
1394         if( pTmp != GetUpper()->GetUpper() ) // Sind wir in einer anderen Spalte gelandet?
1395         {
1396             if( !pFrm )
1397                 return;
1398             if( nNextCol )
1399             {
1400                 while( pFrm->GetNext() )
1401                     pFrm = pFrm->GetNext();
1402             }
1403             else
1404             {
1405                 while( pFrm->GetNext() && pFrm->Frm().Bottom() < rFill.Y() )
1406                     pFrm = pFrm->GetNext();
1407             }
1408             // Kein Fuellen, wenn als letzter Frame in der anvisierten
1409             // Spalte kein Absatz, sondern z.B. eine Tabelle steht
1410             if( pFrm->IsTxtFrm() )
1411             {
1412                 rFill.Fill().nColumnCnt = nNextCol;
1413                 rFill.bColumn = sal_True;
1414                 if( rFill.pPos )
1415                 {
1416                     SwTxtNode* pTxtNd = ((SwTxtFrm*)pFrm)->GetTxtNode();
1417                     rFill.pPos->nNode = *pTxtNd;
1418                     rFill.pPos->nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() );
1419                 }
1420                 if( nNextCol )
1421                 {
1422                     rFill.aFrm = pTmp->Prt();
1423                     rFill.aFrm += pTmp->Frm().Pos();
1424                 }
1425                 else
1426                     rFill.aFrm = pFrm->Frm();
1427                 ((SwTxtFrm*)pFrm)->FillCrsrPos( rFill );
1428             }
1429             return;
1430         }
1431     }
1432     sal_Bool bFill = sal_True;
1433     SwFont *pFnt;
1434     SwTxtFmtColl* pColl = GetTxtNode()->GetTxtColl();
1435     MSHORT nFirst = GetTxtNode()->GetSwAttrSet().GetULSpace().GetLower();
1436     SwTwips nDiff = rFill.Y() - Frm().Bottom();
1437     if( nDiff < nFirst )
1438         nDiff = -1;
1439     else
1440         pColl = &pColl->GetNextTxtFmtColl();
1441     SwAttrSet aSet( ((SwDoc*)GetTxtNode()->GetDoc())->GetAttrPool(), aTxtFmtCollSetRange );
1442     const SwAttrSet* pSet = &pColl->GetAttrSet();
1443     ViewShell *pSh = getRootFrm()->GetCurrShell();
1444     if( GetTxtNode()->HasSwAttrSet() )
1445     {
1446         aSet.Put( *GetTxtNode()->GetpSwAttrSet() );
1447         aSet.SetParent( pSet );
1448         pSet = &aSet;
1449         pFnt = new SwFont( pSet, GetNode()->getIDocumentSettingAccess() );
1450     }
1451     else
1452     {
1453         SwFontAccess aFontAccess( pColl, pSh );
1454         pFnt = new SwFont( *aFontAccess.Get()->GetFont() );
1455         pFnt->ChkMagic( pSh, pFnt->GetActual() );
1456     }
1457     OutputDevice* pOut = pSh->GetOut();
1458     if( !pSh->GetViewOptions()->getBrowseMode() || pSh->GetViewOptions()->IsPrtFormat() )
1459         pOut = GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
1460 
1461     pFnt->SetFntChg( sal_True );
1462     pFnt->ChgPhysFnt( pSh, *pOut );
1463 
1464     SwTwips nLineHeight = pFnt->GetHeight( pSh, *pOut );
1465 
1466     if( nLineHeight )
1467     {
1468         const SvxULSpaceItem &rUL = pSet->GetULSpace();
1469         SwTwips nDist = Max( rUL.GetLower(), rUL.GetUpper() );
1470         if( rFill.Fill().nColumnCnt )
1471         {
1472             rFill.aFrm.Height( nLineHeight );
1473             nDiff = rFill.Y() - rFill.Bottom();
1474             nFirst = 0;
1475         }
1476         else if( nDist < nFirst )
1477             nFirst = nFirst - (sal_uInt16)nDist;
1478         else
1479             nFirst = 0;
1480         nDist = Max( nDist, long( GetLineSpace() ) );
1481         nDist += nLineHeight;
1482         nDiff -= nFirst;
1483 
1484         if( nDiff > 0 )
1485         {
1486             nDiff /= nDist;
1487             rFill.Fill().nParaCnt = static_cast<sal_uInt16>(nDiff + 1);
1488             rFill.nLineWidth = 0;
1489             rFill.bInner = sal_False;
1490             rFill.bEmpty = sal_True;
1491             rFill.SetOrient( text::HoriOrientation::LEFT );
1492         }
1493         else
1494             nDiff = -1;
1495         if( rFill.bInner )
1496             bFill = sal_False;
1497         else
1498         {
1499             const SvxTabStopItem &rRuler = pSet->GetTabStops();
1500             const SvxLRSpaceItem &rLRSpace = pSet->GetLRSpace();
1501 
1502             SwRect &rRect = rFill.Fill().aCrsr;
1503             rRect.Top( rFill.Bottom() + (nDiff+1) * nDist - nLineHeight );
1504             if( nFirst && nDiff > -1 )
1505                 rRect.Top( rRect.Top() + nFirst );
1506             rRect.Height( nLineHeight );
1507             SwTwips nLeft = rFill.Left() + rLRSpace.GetLeft() +
1508                             GetTxtNode()->GetLeftMarginWithNum( sal_False );
1509             SwTwips nRight = rFill.Right() - rLRSpace.GetRight();
1510             SwTwips nCenter = ( nLeft + nRight ) / 2;
1511             rRect.Left( nLeft );
1512             if( FILL_MARGIN == rFill.Mode() )
1513             {
1514                 if( rFill.bEmpty )
1515                 {
1516                     rFill.SetOrient( text::HoriOrientation::LEFT );
1517                     if( rFill.X() < nCenter )
1518                     {
1519                         if( rFill.X() > ( nLeft + 2 * nCenter ) / 3 )
1520                         {
1521                             rFill.SetOrient( text::HoriOrientation::CENTER );
1522                             rRect.Left( nCenter );
1523                         }
1524                     }
1525                     else if( rFill.X() > ( nRight + 2 * nCenter ) / 3 )
1526                     {
1527                         rFill.SetOrient( text::HoriOrientation::RIGHT );
1528                         rRect.Left( nRight );
1529                     }
1530                     else
1531                     {
1532                         rFill.SetOrient( text::HoriOrientation::CENTER );
1533                         rRect.Left( nCenter );
1534                     }
1535                 }
1536                 else
1537                     bFill = sal_False;
1538             }
1539             else
1540             {
1541                 SwTwips nSpace = 0;
1542                 if( FILL_TAB != rFill.Mode() )
1543                 {
1544 static sal_Char __READONLY_DATA sDoubleSpace[] = "  ";
1545                     const XubString aTmp( sDoubleSpace, RTL_TEXTENCODING_MS_1252 );
1546 
1547                     SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTmp, 0, 2 );
1548                     nSpace = pFnt->_GetTxtSize( aDrawInf ).Width()/2;
1549                 }
1550                 if( rFill.X() >= nRight )
1551                 {
1552                     if( FILL_INDENT != rFill.Mode() && ( rFill.bEmpty ||
1553                         rFill.X() > rFill.nLineWidth + FILL_MIN_DIST ) )
1554                     {
1555                         rFill.SetOrient( text::HoriOrientation::RIGHT );
1556                         rRect.Left( nRight );
1557                     }
1558                     else
1559                         bFill = sal_False;
1560                 }
1561                 else if( FILL_INDENT == rFill.Mode() )
1562                 {
1563                     SwTwips nIndent = rFill.X();
1564                     if( !rFill.bEmpty || nIndent > nRight )
1565                         bFill = sal_False;
1566                     else
1567                     {
1568                         nIndent -= rFill.Left();
1569                         if( nIndent >= 0 && nSpace )
1570                         {
1571                             nIndent /= nSpace;
1572                             nIndent *= nSpace;
1573                             rFill.SetTab( MSHORT( nIndent ) );
1574                             rRect.Left( nIndent + rFill.Left() );
1575                         }
1576                         else
1577                             bFill = sal_False;
1578                     }
1579                 }
1580                 else if( rFill.X() > nLeft )
1581                 {
1582                     SwTwips nTxtLeft = rFill.Left() + rLRSpace.GetTxtLeft() +
1583                                     GetTxtNode()->GetLeftMarginWithNum( sal_True );
1584                     rFill.nLineWidth += rFill.bFirstLine ? nLeft : nTxtLeft;
1585                     SwTwips nLeftTab = nLeft;
1586                     SwTwips nRightTab = nLeft;
1587                     MSHORT nSpaceCnt = 0;
1588                     MSHORT nTabCnt = 0;
1589                     MSHORT nIdx = 0;
1590                     do
1591                     {
1592                         nLeftTab = nRightTab;
1593                         if( nIdx < rRuler.Count() )
1594                         {
1595                             const SvxTabStop &rTabStop = rRuler.operator[](nIdx);
1596                             nRightTab = nTxtLeft + rTabStop.GetTabPos();
1597                             if( nLeftTab < nTxtLeft && nRightTab > nTxtLeft )
1598                                 nRightTab = nTxtLeft;
1599                             else
1600                                 ++nIdx;
1601                             if( nRightTab > rFill.nLineWidth )
1602                                 ++nTabCnt;
1603                         }
1604                         else
1605                         {
1606                             const SvxTabStopItem& rTab =
1607                                 (const SvxTabStopItem &)pSet->
1608                                 GetPool()->GetDefaultItem( RES_PARATR_TABSTOP );
1609                             MSHORT nDefTabDist = (MSHORT)rTab.GetStart()->GetTabPos();
1610                             nRightTab = nLeftTab - nTxtLeft;
1611                             nRightTab /= nDefTabDist;
1612                             nRightTab = nRightTab * nDefTabDist + nTxtLeft;
1613                             while ( nRightTab <= nLeftTab )
1614                                 nRightTab += nDefTabDist;
1615                             if( nRightTab > rFill.nLineWidth )
1616                                 ++nTabCnt;
1617                             while ( nRightTab < rFill.X() )
1618                             {
1619                                 nRightTab += nDefTabDist;
1620                                 if( nRightTab > rFill.nLineWidth )
1621                                     ++nTabCnt;
1622                             }
1623                             if( nLeftTab < nRightTab - nDefTabDist )
1624                                 nLeftTab = nRightTab - nDefTabDist;
1625                         }
1626                         if( nRightTab > nRight )
1627                             nRightTab = nRight;
1628                     }
1629                     while( rFill.X() > nRightTab );
1630                     --nTabCnt;
1631                     if( FILL_TAB != rFill.Mode() )
1632                     {
1633                         if( nSpace > 0 )
1634                         {
1635                             if( !nTabCnt )
1636                                 nLeftTab = rFill.nLineWidth;
1637                             while( nLeftTab < rFill.X() )
1638                             {
1639                                 nLeftTab += nSpace;
1640                                 ++nSpaceCnt;
1641                             }
1642                             if( nSpaceCnt )
1643                             {
1644                                 nLeftTab -= nSpace;
1645                                 --nSpaceCnt;
1646                             }
1647                             if( rFill.X() - nLeftTab > nRightTab - rFill.X() )
1648                             {
1649                                 nSpaceCnt = 0;
1650                                 ++nTabCnt;
1651                                 rRect.Left( nRightTab );
1652                             }
1653                             else
1654                             {
1655                                 if( rFill.X() - nLeftTab > nSpace/2 )
1656                                 {
1657                                     ++nSpaceCnt;
1658                                     rRect.Left( nLeftTab + nSpace );
1659                                 }
1660                                 else
1661                                     rRect.Left( nLeftTab );
1662                             }
1663                         }
1664                         else if( rFill.X() - nLeftTab < nRightTab - rFill.X() )
1665                             rRect.Left( nLeftTab );
1666                         else
1667                         {
1668                             if( nRightTab >= nRight )
1669                             {
1670                                 rFill.SetOrient( text::HoriOrientation::RIGHT );
1671                                 rRect.Left( nRight );
1672                                 nTabCnt = 0;
1673                                 nSpaceCnt = 0;
1674                             }
1675                             else
1676                             {
1677                                 rRect.Left( nRightTab );
1678                                 ++nTabCnt;
1679                             }
1680                         }
1681                     }
1682                     else
1683                     {
1684                         if( rFill.X() - nLeftTab < nRightTab - rFill.X() )
1685                             rRect.Left( nLeftTab );
1686                         else
1687                         {
1688                             if( nRightTab >= nRight )
1689                             {
1690                                 rFill.SetOrient( text::HoriOrientation::RIGHT );
1691                                 rRect.Left( nRight );
1692                                 nTabCnt = 0;
1693                                 nSpaceCnt = 0;
1694                             }
1695                             else
1696                             {
1697                                 rRect.Left( nRightTab );
1698                                 ++nTabCnt;
1699                             }
1700                         }
1701                     }
1702                     rFill.SetTab( nTabCnt );
1703                     rFill.SetSpace( nSpaceCnt );
1704                     if( bFill )
1705                     {
1706                         if( Abs( rFill.X() - nCenter ) <=
1707                             Abs( rFill.X() - rRect.Left() ) )
1708                         {
1709                             rFill.SetOrient( text::HoriOrientation::CENTER );
1710                             rFill.SetTab( 0 );
1711                             rFill.SetSpace( 0 );
1712                             rRect.Left( nCenter );
1713                         }
1714                         if( !rFill.bEmpty )
1715                             rFill.nLineWidth += FILL_MIN_DIST;
1716                         if( rRect.Left() < rFill.nLineWidth )
1717                             bFill = sal_False;
1718                     }
1719                 }
1720             }
1721             // Gehen wir ueber die Unterkante der Seite/Spalte etc. hinaus?
1722             const SwFrm* pUp = GetUpper();
1723             if( pUp->IsInSct() )
1724             {
1725                 if( pUp->IsSctFrm() )
1726                     pUp = pUp->GetUpper();
1727                 else if( pUp->IsColBodyFrm() &&
1728                          pUp->GetUpper()->GetUpper()->IsSctFrm() )
1729                     pUp = pUp->GetUpper()->GetUpper()->GetUpper();
1730             }
1731             SWRECTFN( this )
1732             SwTwips nLimit = (pUp->*fnRect->fnGetPrtBottom)();
1733             SwTwips nRectBottom = rRect.Bottom();
1734             if ( bVert )
1735                 nRectBottom = SwitchHorizontalToVertical( nRectBottom );
1736 
1737             if( (*fnRect->fnYDiff)( nLimit, nRectBottom ) < 0 )
1738                 bFill = sal_False;
1739             else
1740                 rRect.Width( 1 );
1741         }
1742     }
1743     else
1744         bFill = sal_False;
1745     ((SwCrsrMoveState*)rFill.pCMS)->bFillRet = bFill;
1746     delete pFnt;
1747 }
1748