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