xref: /aoo41x/main/sw/source/core/text/frmcrsr.cxx (revision efeef26f)
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