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