xref: /AOO41X/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