Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "ndtxt.hxx"
21 : #include "pam.hxx"
22 : #include "frmtool.hxx"
23 : #include "viewopt.hxx"
24 : #include "paratr.hxx"
25 : #include "rootfrm.hxx"
26 : #include "pagefrm.hxx"
27 : #include "colfrm.hxx"
28 : #include "swtypes.hxx"
29 : #include <sfx2/printer.hxx>
30 : #include <editeng/lrspitem.hxx>
31 : #include <editeng/tstpitem.hxx>
32 : #include <editeng/ulspitem.hxx>
33 : #include <editeng/lspcitem.hxx>
34 : #include <pormulti.hxx>
35 : #include <doc.hxx>
36 : #include <IDocumentDeviceAccess.hxx>
37 : #include <sortedobjs.hxx>
38 :
39 : #include <unicode/ubidi.h>
40 :
41 : #include "txtfrm.hxx"
42 : #include "inftxt.hxx"
43 : #include "itrtxt.hxx"
44 : #include "crstate.hxx"
45 : #include "viewsh.hxx"
46 : #include "swfntcch.hxx"
47 : #include "flyfrm.hxx"
48 :
49 : #define MIN_OFFSET_STEP 10
50 :
51 : using namespace ::com::sun::star;
52 :
53 : /*
54 : * - SurvivalKit: For how long do we get past the last char of the line.
55 : * - RightMargin abstains from adjusting position with -1
56 : * - GetCharRect returns a GetEndCharRect for MV_RIGHTMARGIN
57 : * - GetEndCharRect sets bRightMargin to true
58 : * - SwTxtCursor::bRightMargin is set to false by CharCrsrToLine
59 : */
60 :
61 : namespace
62 : {
63 :
64 148214 : SwTxtFrm *GetAdjFrmAtPos( SwTxtFrm *pFrm, const SwPosition &rPos,
65 : const bool bRightMargin, const bool bNoScroll = true )
66 : {
67 : // RightMargin in the last master line
68 148214 : const sal_Int32 nOffset = rPos.nContent.GetIndex();
69 148214 : SwTxtFrm *pFrmAtPos = pFrm;
70 148214 : if( !bNoScroll || pFrm->GetFollow() )
71 : {
72 145214 : pFrmAtPos = pFrm->GetFrmAtPos( rPos );
73 145214 : if( nOffset < pFrmAtPos->GetOfst() &&
74 0 : !pFrmAtPos->IsFollow() )
75 : {
76 0 : sal_Int32 nNew = nOffset;
77 0 : if( nNew < MIN_OFFSET_STEP )
78 0 : nNew = 0;
79 : else
80 0 : nNew -= MIN_OFFSET_STEP;
81 0 : sw_ChangeOffset( pFrmAtPos, nNew );
82 : }
83 : }
84 296428 : while( pFrm != pFrmAtPos )
85 : {
86 0 : pFrm = pFrmAtPos;
87 0 : pFrm->GetFormatted();
88 0 : pFrmAtPos = (SwTxtFrm*)pFrm->GetFrmAtPos( rPos );
89 : }
90 :
91 148214 : if( nOffset && bRightMargin )
92 : {
93 0 : while( pFrmAtPos && pFrmAtPos->GetOfst() == nOffset &&
94 0 : pFrmAtPos->IsFollow() )
95 : {
96 0 : pFrmAtPos->GetFormatted();
97 0 : pFrmAtPos = pFrmAtPos->FindMaster();
98 : }
99 : OSL_ENSURE( pFrmAtPos, "+GetCharRect: no frame with my rightmargin" );
100 : }
101 148214 : return pFrmAtPos ? pFrmAtPos : pFrm;
102 : }
103 :
104 : }
105 :
106 0 : bool sw_ChangeOffset( SwTxtFrm* pFrm, sal_Int32 nNew )
107 : {
108 : // Do not scroll in areas and outside of flies
109 : OSL_ENSURE( !pFrm->IsFollow(), "Illegal Scrolling by Follow!" );
110 0 : if( pFrm->GetOfst() != nNew && !pFrm->IsInSct() )
111 : {
112 0 : SwFlyFrm *pFly = pFrm->FindFlyFrm();
113 : // Attention: if e.g. in a column frame the size is still invalid
114 : // we must not scroll around just like that
115 0 : if ( ( pFly && pFly->IsValid() &&
116 0 : !pFly->GetNextLink() && !pFly->GetPrevLink() ) ||
117 0 : ( !pFly && pFrm->IsInTab() ) )
118 : {
119 0 : SwViewShell* pVsh = pFrm->getRootFrm()->GetCurrShell();
120 0 : if( pVsh )
121 : {
122 0 : if( pVsh->GetNext() != pVsh ||
123 0 : ( pFrm->GetDrawObjs() && pFrm->GetDrawObjs()->size() ) )
124 : {
125 0 : if( !pFrm->GetOfst() )
126 0 : return false;
127 0 : nNew = 0;
128 : }
129 0 : pFrm->SetOfst( nNew );
130 0 : pFrm->SetPara( 0 );
131 0 : pFrm->GetFormatted();
132 0 : if( pFrm->Frm().HasArea() )
133 0 : pFrm->getRootFrm()->GetCurrShell()->InvalidateWindows( pFrm->Frm() );
134 0 : return true;
135 : }
136 : }
137 : }
138 0 : return false;
139 : }
140 :
141 109132 : SwTxtFrm& SwTxtFrm::GetFrmAtOfst( const sal_Int32 nWhere )
142 : {
143 109132 : SwTxtFrm* pRet = this;
144 218416 : while( pRet->HasFollow() && nWhere >= pRet->GetFollow()->GetOfst() )
145 152 : pRet = pRet->GetFollow();
146 109132 : return *pRet;
147 : }
148 :
149 508585 : SwTxtFrm *SwTxtFrm::GetFrmAtPos( const SwPosition &rPos )
150 : {
151 508585 : SwTxtFrm *pFoll = (SwTxtFrm*)this;
152 1075170 : while( pFoll->GetFollow() )
153 : {
154 58608 : if( rPos.nContent.GetIndex() > pFoll->GetFollow()->GetOfst() )
155 57790 : pFoll = pFoll->GetFollow();
156 : else
157 : {
158 1636 : if( rPos.nContent.GetIndex() == pFoll->GetFollow()->GetOfst()
159 818 : && !SwTxtCursor::IsRightMargin() )
160 210 : pFoll = pFoll->GetFollow();
161 : else
162 608 : break;
163 : }
164 : }
165 508585 : return pFoll;
166 : }
167 :
168 : /*
169 : * GetCharRect() returns the char's char line described by aPos.
170 : * GetCrsrOfst() does the reverse: It goes from a document coordinate to
171 : * a Pam.
172 : * Both are virtual in the frame base class and thus are redefined here.
173 : */
174 :
175 148576 : bool SwTxtFrm::GetCharRect( SwRect& rOrig, const SwPosition &rPos,
176 : SwCrsrMoveState *pCMS ) const
177 : {
178 : OSL_ENSURE( ! IsVertical() || ! IsSwapped(),"SwTxtFrm::GetCharRect with swapped frame" );
179 :
180 148576 : if( IsLocked() || IsHiddenNow() )
181 368 : return false;
182 :
183 : // Find the right frame first. We need to keep in mind that:
184 : // - the cached information could be invalid (GetPara() == 0)
185 : // - we could have a Follow
186 : // - the Follow chain grows dynamically; the one we end up in
187 : // needs to be formatted
188 :
189 : // Optimisation: reading ahead saves us a GetAdjFrmAtPos
190 148208 : const bool bRightMargin = pCMS && ( MV_RIGHTMARGIN == pCMS->eState );
191 148208 : const bool bNoScroll = pCMS && pCMS->bNoScroll;
192 : SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, rPos, bRightMargin,
193 148208 : bNoScroll );
194 148208 : pFrm->GetFormatted();
195 148208 : const SwFrm* pTmpFrm = (SwFrm*)pFrm->GetUpper();
196 :
197 148208 : SWRECTFN ( pFrm )
198 148208 : const SwTwips nUpperMaxY = (pTmpFrm->*fnRect->fnGetPrtBottom)();
199 148208 : const SwTwips nFrmMaxY = (pFrm->*fnRect->fnGetPrtBottom)();
200 :
201 : // nMaxY is an absolute value
202 : SwTwips nMaxY = bVert ?
203 0 : ( bVertL2R ? std::min( nFrmMaxY, nUpperMaxY ) : std::max( nFrmMaxY, nUpperMaxY ) ) :
204 148208 : std::min( nFrmMaxY, nUpperMaxY );
205 :
206 148208 : bool bRet = false;
207 :
208 148208 : if ( pFrm->IsEmpty() || ! (pFrm->Prt().*fnRect->fnGetHeight)() )
209 : {
210 35330 : Point aPnt1 = pFrm->Frm().Pos() + pFrm->Prt().Pos();
211 35330 : SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
212 : short nFirstOffset;
213 35330 : pTxtNd->GetFirstLineOfsWithNum( nFirstOffset );
214 :
215 35330 : Point aPnt2;
216 35330 : if ( bVert )
217 : {
218 0 : if( nFirstOffset > 0 )
219 0 : aPnt1.Y() += nFirstOffset;
220 0 : if ( aPnt1.X() < nMaxY && !bVertL2R )
221 0 : aPnt1.X() = nMaxY;
222 0 : aPnt2.X() = aPnt1.X() + pFrm->Prt().Width();
223 0 : aPnt2.Y() = aPnt1.Y();
224 0 : if( aPnt2.X() < nMaxY )
225 0 : aPnt2.X() = nMaxY;
226 : }
227 : else
228 : {
229 35330 : if( nFirstOffset > 0 )
230 0 : aPnt1.X() += nFirstOffset;
231 :
232 35330 : if( aPnt1.Y() > nMaxY )
233 0 : aPnt1.Y() = nMaxY;
234 35330 : aPnt2.X() = aPnt1.X();
235 35330 : aPnt2.Y() = aPnt1.Y() + pFrm->Prt().Height();
236 35330 : if( aPnt2.Y() > nMaxY )
237 0 : aPnt2.Y() = nMaxY;
238 : }
239 :
240 35330 : rOrig = SwRect( aPnt1, aPnt2 );
241 :
242 35330 : if ( pCMS )
243 : {
244 35322 : pCMS->aRealHeight.X() = 0;
245 35322 : pCMS->aRealHeight.Y() = bVert ? -rOrig.Width() : rOrig.Height();
246 : }
247 :
248 35330 : if ( pFrm->IsRightToLeft() )
249 128 : pFrm->SwitchLTRtoRTL( rOrig );
250 :
251 35330 : bRet = true;
252 : }
253 : else
254 : {
255 112878 : if( !pFrm->HasPara() )
256 0 : return false;
257 :
258 112878 : SwFrmSwapper aSwapper( pFrm, true );
259 112878 : if ( bVert )
260 0 : nMaxY = pFrm->SwitchVerticalToHorizontal( nMaxY );
261 :
262 112878 : bool bGoOn = true;
263 112878 : const sal_Int32 nOffset = rPos.nContent.GetIndex();
264 : sal_Int32 nNextOfst;
265 :
266 112878 : do
267 : {
268 : {
269 112878 : SwTxtSizeInfo aInf( pFrm );
270 225756 : SwTxtCursor aLine( pFrm, &aInf );
271 112878 : nNextOfst = aLine.GetEnd();
272 : // See comment in AdjustFrm
273 : // Include the line's last char?
274 : bRet = bRightMargin ? aLine.GetEndCharRect( &rOrig, nOffset, pCMS, nMaxY )
275 225756 : : aLine.GetCharRect( &rOrig, nOffset, pCMS, nMaxY );
276 : }
277 :
278 112878 : if ( pFrm->IsRightToLeft() )
279 198 : pFrm->SwitchLTRtoRTL( rOrig );
280 :
281 112878 : if ( bVert )
282 0 : pFrm->SwitchHorizontalToVertical( rOrig );
283 :
284 226216 : if( pFrm->IsUndersized() && pCMS && !pFrm->GetNext() &&
285 386 : (rOrig.*fnRect->fnGetBottom)() == nUpperMaxY &&
286 164 : pFrm->GetOfst() < nOffset &&
287 112902 : !pFrm->IsFollow() && !bNoScroll &&
288 8 : pFrm->GetTxtNode()->GetTxt().getLength() != nNextOfst)
289 : {
290 0 : bGoOn = sw_ChangeOffset( pFrm, nNextOfst );
291 : }
292 : else
293 112878 : bGoOn = false;
294 : } while ( bGoOn );
295 :
296 112878 : if ( pCMS )
297 : {
298 111714 : if ( pFrm->IsRightToLeft() )
299 : {
300 198 : if( pCMS->b2Lines && pCMS->p2Lines)
301 : {
302 0 : pFrm->SwitchLTRtoRTL( pCMS->p2Lines->aLine );
303 0 : pFrm->SwitchLTRtoRTL( pCMS->p2Lines->aPortion );
304 : }
305 : }
306 :
307 111714 : if ( bVert )
308 : {
309 0 : if ( pCMS->bRealHeight )
310 : {
311 0 : pCMS->aRealHeight.Y() = -pCMS->aRealHeight.Y();
312 0 : if ( pCMS->aRealHeight.Y() < 0 )
313 : {
314 : // writing direction is from top to bottom
315 0 : pCMS->aRealHeight.X() = ( rOrig.Width() -
316 0 : pCMS->aRealHeight.X() +
317 0 : pCMS->aRealHeight.Y() );
318 : }
319 : }
320 0 : if( pCMS->b2Lines && pCMS->p2Lines)
321 : {
322 0 : pFrm->SwitchHorizontalToVertical( pCMS->p2Lines->aLine );
323 0 : pFrm->SwitchHorizontalToVertical( pCMS->p2Lines->aPortion );
324 : }
325 : }
326 :
327 112878 : }
328 : }
329 148208 : if( bRet )
330 : {
331 148208 : SwPageFrm *pPage = pFrm->FindPageFrm();
332 : OSL_ENSURE( pPage, "Text escaped from page?" );
333 148208 : const SwTwips nOrigTop = (rOrig.*fnRect->fnGetTop)();
334 148208 : const SwTwips nPageTop = (pPage->Frm().*fnRect->fnGetTop)();
335 148208 : const SwTwips nPageBott = (pPage->Frm().*fnRect->fnGetBottom)();
336 :
337 : // We have the following situation: if the frame is in an invalid
338 : // sectionframe, it's possible that the frame is outside the page.
339 : // If we restrict the cursor position to the page area, we enforce
340 : // the formatting of the page, of the section frame and the frame itself.
341 148208 : if( (*fnRect->fnYDiff)( nPageTop, nOrigTop ) > 0 )
342 0 : (rOrig.*fnRect->fnSetTop)( nPageTop );
343 :
344 148208 : if ( (*fnRect->fnYDiff)( nOrigTop, nPageBott ) > 0 )
345 0 : (rOrig.*fnRect->fnSetTop)( nPageBott );
346 : }
347 :
348 148208 : return bRet;
349 : }
350 :
351 : /*
352 : * GetAutoPos() looks up the char's char line which is described by rPos
353 : * and is used by the auto-positioned frame.
354 : */
355 :
356 3834 : bool SwTxtFrm::GetAutoPos( SwRect& rOrig, const SwPosition &rPos ) const
357 : {
358 3834 : if( IsHiddenNow() )
359 0 : return false;
360 :
361 3834 : const sal_Int32 nOffset = rPos.nContent.GetIndex();
362 3834 : SwTxtFrm* pFrm = &(const_cast<SwTxtFrm*>(this)->GetFrmAtOfst( nOffset ));
363 :
364 3834 : pFrm->GetFormatted();
365 3834 : const SwFrm* pTmpFrm = (SwFrm*)pFrm->GetUpper();
366 :
367 3834 : SWRECTFN( pTmpFrm )
368 3834 : SwTwips nUpperMaxY = (pTmpFrm->*fnRect->fnGetPrtBottom)();
369 :
370 : // nMaxY is in absolute value
371 : SwTwips nMaxY = bVert ?
372 3834 : ( bVertL2R ? std::min( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY ) : std::max( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY ) ) :
373 7668 : std::min( (pFrm->*fnRect->fnGetPrtBottom)(), nUpperMaxY );
374 :
375 3834 : if ( pFrm->IsEmpty() || ! (pFrm->Prt().*fnRect->fnGetHeight)() )
376 : {
377 1238 : Point aPnt1 = pFrm->Frm().Pos() + pFrm->Prt().Pos();
378 1238 : Point aPnt2;
379 1238 : if ( bVert )
380 : {
381 0 : if ( aPnt1.X() < nMaxY && !bVertL2R )
382 0 : aPnt1.X() = nMaxY;
383 :
384 0 : aPnt2.X() = aPnt1.X() + pFrm->Prt().Width();
385 0 : aPnt2.Y() = aPnt1.Y();
386 0 : if( aPnt2.X() < nMaxY )
387 0 : aPnt2.X() = nMaxY;
388 : }
389 : else
390 : {
391 1238 : if( aPnt1.Y() > nMaxY )
392 0 : aPnt1.Y() = nMaxY;
393 1238 : aPnt2.X() = aPnt1.X();
394 1238 : aPnt2.Y() = aPnt1.Y() + pFrm->Prt().Height();
395 1238 : if( aPnt2.Y() > nMaxY )
396 0 : aPnt2.Y() = nMaxY;
397 : }
398 1238 : rOrig = SwRect( aPnt1, aPnt2 );
399 1238 : return true;
400 : }
401 : else
402 : {
403 2596 : if( !pFrm->HasPara() )
404 0 : return false;
405 :
406 2596 : SwFrmSwapper aSwapper( pFrm, true );
407 2596 : if ( bVert )
408 0 : nMaxY = pFrm->SwitchVerticalToHorizontal( nMaxY );
409 :
410 5192 : SwTxtSizeInfo aInf( pFrm );
411 5192 : SwTxtCursor aLine( pFrm, &aInf );
412 2596 : SwCrsrMoveState aTmpState( MV_SETONLYTEXT );
413 2596 : aTmpState.bRealHeight = true;
414 2596 : if( aLine.GetCharRect( &rOrig, nOffset, &aTmpState, nMaxY ) )
415 : {
416 2596 : if( aTmpState.aRealHeight.X() >= 0 )
417 : {
418 2596 : rOrig.Pos().Y() += aTmpState.aRealHeight.X();
419 2596 : rOrig.Height( aTmpState.aRealHeight.Y() );
420 : }
421 :
422 2596 : if ( pFrm->IsRightToLeft() )
423 0 : pFrm->SwitchLTRtoRTL( rOrig );
424 :
425 2596 : if ( bVert )
426 0 : pFrm->SwitchHorizontalToVertical( rOrig );
427 :
428 2596 : return true;
429 : }
430 2596 : return false;
431 : }
432 : }
433 :
434 : /** determine top of line for given position in the text frame
435 :
436 : - Top of first paragraph line is the top of the printing area of the text frame
437 : - If a proportional line spacing is applied use top of anchor character as
438 : top of the line.
439 : */
440 3554 : bool SwTxtFrm::GetTopOfLine( SwTwips& _onTopOfLine,
441 : const SwPosition& _rPos ) const
442 : {
443 3554 : bool bRet = true;
444 :
445 : // get position offset
446 3554 : const sal_Int32 nOffset = _rPos.nContent.GetIndex();
447 :
448 3554 : if ( GetTxt().getLength() < nOffset )
449 : {
450 0 : bRet = false;
451 : }
452 : else
453 : {
454 3554 : SWRECTFN( this )
455 3554 : if ( IsEmpty() || !(Prt().*fnRect->fnGetHeight)() )
456 : {
457 : // consider upper space amount considered
458 : // for previous frame and the page grid.
459 1238 : _onTopOfLine = (this->*fnRect->fnGetPrtTop)();
460 : }
461 : else
462 : {
463 : // determine formatted text frame that contains the requested position
464 2316 : SwTxtFrm* pFrm = &(const_cast<SwTxtFrm*>(this)->GetFrmAtOfst( nOffset ));
465 2316 : pFrm->GetFormatted();
466 2316 : SWREFRESHFN( pFrm )
467 : // If proportional line spacing is applied
468 : // to the text frame, the top of the anchor character is also the
469 : // top of the line.
470 : // Otherwise the line layout determines the top of the line
471 2316 : const SvxLineSpacingItem& rSpace = GetAttrSet()->GetLineSpacing();
472 2316 : if ( rSpace.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP )
473 : {
474 280 : SwRect aCharRect;
475 280 : if ( GetAutoPos( aCharRect, _rPos ) )
476 : {
477 280 : _onTopOfLine = (aCharRect.*fnRect->fnGetTop)();
478 : }
479 : else
480 : {
481 0 : bRet = false;
482 : }
483 : }
484 : else
485 : {
486 : // assure that text frame is in a horizontal layout
487 2036 : SwFrmSwapper aSwapper( pFrm, true );
488 : // determine text line that contains the requested position
489 4072 : SwTxtSizeInfo aInf( pFrm );
490 4072 : SwTxtCursor aLine( pFrm, &aInf );
491 2036 : aLine.CharCrsrToLine( nOffset );
492 : // determine top of line
493 2036 : _onTopOfLine = aLine.Y();
494 2036 : if ( bVert )
495 : {
496 0 : _onTopOfLine = pFrm->SwitchHorizontalToVertical( _onTopOfLine );
497 2036 : }
498 : }
499 : }
500 : }
501 :
502 3554 : return bRet;
503 : }
504 :
505 : // Minimum distance of non-empty lines is a little less than 2 cm
506 : #define FILL_MIN_DIST 1100
507 :
508 : struct SwFillData
509 : {
510 : SwRect aFrm;
511 : const SwCrsrMoveState *pCMS;
512 : SwPosition* pPos;
513 : const Point& rPoint;
514 : SwTwips nLineWidth;
515 : bool bFirstLine : 1;
516 : bool bInner : 1;
517 : bool bColumn : 1;
518 : bool bEmpty : 1;
519 0 : SwFillData( const SwCrsrMoveState *pC, SwPosition* pP, const SwRect& rR,
520 : const Point& rPt ) : aFrm( rR ), pCMS( pC ), pPos( pP ), rPoint( rPt ),
521 : nLineWidth( 0 ), bFirstLine( true ), bInner( false ), bColumn( false ),
522 0 : bEmpty( true ){}
523 0 : SwFillMode Mode() const { return pCMS->pFill->eMode; }
524 0 : long X() const { return rPoint.X(); }
525 0 : long Y() const { return rPoint.Y(); }
526 0 : long Left() const { return aFrm.Left(); }
527 0 : long Right() const { return aFrm.Right(); }
528 0 : long Bottom() const { return aFrm.Bottom(); }
529 0 : SwFillCrsrPos &Fill() const { return *pCMS->pFill; }
530 0 : void SetTab( sal_uInt16 nNew ) { pCMS->pFill->nTabCnt = nNew; }
531 0 : void SetSpace( sal_uInt16 nNew ) { pCMS->pFill->nSpaceCnt = nNew; }
532 0 : void SetOrient( const sal_Int16 eNew ){ pCMS->pFill->eOrient = eNew; }
533 : };
534 :
535 789 : bool SwTxtFrm::_GetCrsrOfst(SwPosition* pPos, const Point& rPoint,
536 : const bool bChgFrm, SwCrsrMoveState* pCMS ) const
537 : {
538 : // _GetCrsrOfst is called by GetCrsrOfst and GetKeyCrsrOfst.
539 : // Never just a return false.
540 :
541 789 : if( IsLocked() || IsHiddenNow() )
542 315 : return false;
543 :
544 474 : ((SwTxtFrm*)this)->GetFormatted();
545 :
546 474 : Point aOldPoint( rPoint );
547 :
548 474 : if ( IsVertical() )
549 : {
550 0 : SwitchVerticalToHorizontal( (Point&)rPoint );
551 0 : ((SwTxtFrm*)this)->SwapWidthAndHeight();
552 : }
553 :
554 474 : if ( IsRightToLeft() )
555 0 : SwitchRTLtoLTR( (Point&)rPoint );
556 :
557 474 : SwFillData *pFillData = ( pCMS && pCMS->pFill ) ?
558 474 : new SwFillData( pCMS, pPos, Frm(), rPoint ) : NULL;
559 :
560 474 : if ( IsEmpty() )
561 : {
562 240 : SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
563 240 : pPos->nNode = *pTxtNd;
564 240 : pPos->nContent.Assign( pTxtNd, 0 );
565 240 : if( pCMS && pCMS->bFieldInfo )
566 : {
567 0 : SwTwips nDiff = rPoint.X() - Frm().Left() - Prt().Left();
568 0 : if( nDiff > 50 || nDiff < 0 )
569 0 : ((SwCrsrMoveState*)pCMS)->bPosCorr = true;
570 : }
571 : }
572 : else
573 : {
574 234 : SwTxtSizeInfo aInf( (SwTxtFrm*)this );
575 468 : SwTxtCursor aLine( ((SwTxtFrm*)this), &aInf );
576 :
577 : // See comment in AdjustFrm()
578 234 : SwTwips nMaxY = Frm().Top() + Prt().Top() + Prt().Height();
579 234 : aLine.TwipsToLine( rPoint.Y() );
580 468 : while( aLine.Y() + aLine.GetLineHeight() > nMaxY )
581 : {
582 0 : if( !aLine.Prev() )
583 0 : break;
584 : }
585 :
586 468 : if( aLine.GetDropLines() >= aLine.GetLineNr() && 1 != aLine.GetLineNr()
587 234 : && rPoint.X() < aLine.FirstLeft() + aLine.GetDropLeft() )
588 0 : while( aLine.GetLineNr() > 1 )
589 0 : aLine.Prev();
590 :
591 234 : sal_Int32 nOffset = aLine.GetCrsrOfst( pPos, rPoint, bChgFrm, pCMS );
592 :
593 234 : if( pCMS && pCMS->eState == MV_NONE && aLine.GetEnd() == nOffset )
594 0 : ((SwCrsrMoveState*)pCMS)->eState = MV_RIGHTMARGIN;
595 :
596 : // pPos is a pure IN parameter and must not be evaluated.
597 : // pIter->GetCrsrOfst returns from a nesting with COMPLETE_STRING.
598 : // If SwTxtIter::GetCrsrOfst calls GetCrsrOfst further by itself
599 : // nNode changes the position.
600 : // In such cases, pPos must not be calculated.
601 234 : if( COMPLETE_STRING != nOffset )
602 : {
603 234 : SwTxtNode* pTxtNd = ((SwTxtFrm*)this)->GetTxtNode();
604 234 : pPos->nNode = *pTxtNd;
605 234 : pPos->nContent.Assign( pTxtNd, nOffset );
606 234 : if( pFillData )
607 : {
608 0 : if (pTxtNd->GetTxt().getLength() > nOffset ||
609 0 : rPoint.Y() < Frm().Top() )
610 0 : pFillData->bInner = true;
611 0 : pFillData->bFirstLine = aLine.GetLineNr() < 2;
612 0 : if (pTxtNd->GetTxt().getLength())
613 : {
614 0 : pFillData->bEmpty = false;
615 0 : pFillData->nLineWidth = aLine.GetCurr()->Width();
616 : }
617 : }
618 234 : }
619 : }
620 474 : bool bChgFillData = false;
621 474 : if( pFillData && FindPageFrm()->Frm().IsInside( aOldPoint ) )
622 : {
623 0 : FillCrsrPos( *pFillData );
624 0 : bChgFillData = true;
625 : }
626 :
627 474 : if ( IsVertical() )
628 : {
629 0 : if ( bChgFillData )
630 0 : SwitchHorizontalToVertical( pFillData->Fill().aCrsr.Pos() );
631 0 : ((SwTxtFrm*)this)->SwapWidthAndHeight();
632 : }
633 :
634 474 : if ( IsRightToLeft() && bChgFillData )
635 : {
636 0 : SwitchLTRtoRTL( pFillData->Fill().aCrsr.Pos() );
637 0 : const sal_Int16 eOrient = pFillData->pCMS->pFill->eOrient;
638 :
639 0 : if ( text::HoriOrientation::LEFT == eOrient )
640 0 : pFillData->SetOrient( text::HoriOrientation::RIGHT );
641 0 : else if ( text::HoriOrientation::RIGHT == eOrient )
642 0 : pFillData->SetOrient( text::HoriOrientation::LEFT );
643 : }
644 :
645 474 : (Point&)rPoint = aOldPoint;
646 474 : delete pFillData;
647 :
648 474 : return true;
649 : }
650 :
651 789 : bool SwTxtFrm::GetCrsrOfst(SwPosition* pPos, Point& rPoint,
652 : SwCrsrMoveState* pCMS, bool ) const
653 : {
654 789 : const bool bChgFrm = !(pCMS && MV_UPDOWN == pCMS->eState);
655 789 : return _GetCrsrOfst( pPos, rPoint, bChgFrm, pCMS );
656 : }
657 :
658 : /*
659 : * Layout-oriented cursor movement to the line start.
660 : */
661 :
662 0 : bool SwTxtFrm::LeftMargin(SwPaM *pPam) const
663 : {
664 0 : if( &pPam->GetNode() != GetNode() )
665 0 : pPam->GetPoint()->nNode = *((SwTxtFrm*)this)->GetTxtNode();
666 :
667 0 : SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *pPam->GetPoint(),
668 0 : SwTxtCursor::IsRightMargin() );
669 0 : pFrm->GetFormatted();
670 : sal_Int32 nIndx;
671 0 : if ( pFrm->IsEmpty() )
672 0 : nIndx = 0;
673 : else
674 : {
675 0 : SwTxtSizeInfo aInf( pFrm );
676 0 : SwTxtCursor aLine( pFrm, &aInf );
677 :
678 0 : aLine.CharCrsrToLine(pPam->GetPoint()->nContent.GetIndex());
679 0 : nIndx = aLine.GetStart();
680 0 : if( pFrm->GetOfst() && !pFrm->IsFollow() && !aLine.GetPrev() )
681 : {
682 0 : sw_ChangeOffset( pFrm, 0 );
683 0 : nIndx = 0;
684 0 : }
685 : }
686 0 : pPam->GetPoint()->nContent = SwIndex( pFrm->GetTxtNode(), nIndx );
687 0 : SwTxtCursor::SetRightMargin( false );
688 0 : return true;
689 : }
690 :
691 : /*
692 : * To the line end: That's the position before the last char of the line.
693 : * Exception: In the last line, it should be able to place the cursor after
694 : * the last char in order to append text.
695 : */
696 :
697 0 : bool SwTxtFrm::RightMargin(SwPaM *pPam, bool bAPI) const
698 : {
699 0 : if( &pPam->GetNode() != GetNode() )
700 0 : pPam->GetPoint()->nNode = *((SwTxtFrm*)this)->GetTxtNode();
701 :
702 0 : SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *pPam->GetPoint(),
703 0 : SwTxtCursor::IsRightMargin() );
704 0 : pFrm->GetFormatted();
705 : sal_Int32 nRightMargin;
706 0 : if ( IsEmpty() )
707 0 : nRightMargin = 0;
708 : else
709 : {
710 0 : SwTxtSizeInfo aInf( pFrm );
711 0 : SwTxtCursor aLine( pFrm, &aInf );
712 :
713 0 : aLine.CharCrsrToLine(pPam->GetPoint()->nContent.GetIndex());
714 0 : nRightMargin = aLine.GetStart() + aLine.GetCurr()->GetLen();
715 :
716 : // We skip hard line brakes
717 0 : if( aLine.GetCurr()->GetLen() &&
718 0 : CH_BREAK == aInf.GetTxt()[nRightMargin - 1])
719 0 : --nRightMargin;
720 0 : else if( !bAPI && (aLine.GetNext() || pFrm->GetFollow()) )
721 : {
722 0 : while( nRightMargin > aLine.GetStart() &&
723 0 : ' ' == aInf.GetTxt()[nRightMargin - 1])
724 0 : --nRightMargin;
725 0 : }
726 : }
727 0 : pPam->GetPoint()->nContent = SwIndex( pFrm->GetTxtNode(), nRightMargin );
728 0 : SwTxtCursor::SetRightMargin( !bAPI );
729 0 : return true;
730 : }
731 :
732 : // The following two methods try to put the Crsr into the next/succsessive
733 : // line. If we do not have a preceding/successive line we forward the call
734 : // to the base class.
735 : // The Crsr's horizontal justification is done afterwards by the CrsrShell.
736 :
737 : class SwSetToRightMargin
738 : {
739 : bool bRight;
740 : public:
741 4 : inline SwSetToRightMargin() : bRight( false ) { }
742 4 : inline ~SwSetToRightMargin() { SwTxtCursor::SetRightMargin( bRight ); }
743 0 : inline void SetRight( const bool bNew ) { bRight = bNew; }
744 : };
745 :
746 4 : bool SwTxtFrm::_UnitUp( SwPaM *pPam, const SwTwips nOffset,
747 : bool bSetInReadOnly ) const
748 : {
749 : // Set the RightMargin if needed
750 4 : SwSetToRightMargin aSet;
751 :
752 8 : if( IsInTab() &&
753 4 : pPam->GetNode( true ).StartOfSectionNode() !=
754 4 : pPam->GetNode( false ).StartOfSectionNode() )
755 : {
756 : // If the PaM is located within different boxes, we have a table selection,
757 : // which is handled by the base class.
758 0 : return SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
759 : }
760 :
761 4 : ((SwTxtFrm*)this)->GetFormatted();
762 4 : const sal_Int32 nPos = pPam->GetPoint()->nContent.GetIndex();
763 4 : SwRect aCharBox;
764 :
765 4 : if( !IsEmpty() && !IsHiddenNow() )
766 : {
767 0 : sal_Int32 nFormat = COMPLETE_STRING;
768 : do
769 : {
770 0 : if( nFormat != COMPLETE_STRING && !IsFollow() )
771 0 : sw_ChangeOffset( ((SwTxtFrm*)this), nFormat );
772 :
773 0 : SwTxtSizeInfo aInf( (SwTxtFrm*)this );
774 0 : SwTxtCursor aLine( ((SwTxtFrm*)this), &aInf );
775 :
776 : // Optimize away flys with no flow and IsDummy()
777 0 : if( nPos )
778 0 : aLine.CharCrsrToLine( nPos );
779 : else
780 0 : aLine.Top();
781 :
782 0 : const SwLineLayout *pPrevLine = aLine.GetPrevLine();
783 0 : const sal_Int32 nStart = aLine.GetStart();
784 0 : aLine.GetCharRect( &aCharBox, nPos );
785 :
786 0 : bool bSecondOfDouble = ( aInf.IsMulti() && ! aInf.IsFirstMulti() );
787 0 : bool bPrevLine = ( pPrevLine && pPrevLine != aLine.GetCurr() );
788 :
789 0 : if( !pPrevLine && !bSecondOfDouble && GetOfst() && !IsFollow() )
790 : {
791 0 : nFormat = GetOfst();
792 0 : sal_Int32 nDiff = aLine.GetLength();
793 0 : if( !nDiff )
794 0 : nDiff = MIN_OFFSET_STEP;
795 0 : if( nFormat > nDiff )
796 0 : nFormat = nFormat - nDiff;
797 : else
798 0 : nFormat = 0;
799 0 : continue;
800 : }
801 :
802 : // We select the target line for the cursor, in case we are in a
803 : // double line portion, prev line = curr line
804 0 : if( bPrevLine && !bSecondOfDouble )
805 : {
806 0 : aLine.PrevLine();
807 0 : while ( aLine.GetStart() == nStart &&
808 0 : 0 != ( pPrevLine = aLine.GetPrevLine() ) &&
809 0 : pPrevLine != aLine.GetCurr() )
810 0 : aLine.PrevLine();
811 : }
812 :
813 0 : if ( bPrevLine || bSecondOfDouble )
814 : {
815 0 : aCharBox.SSize().Width() /= 2;
816 0 : aCharBox.Pos().X() = aCharBox.Pos().X() - 150;
817 :
818 : // See comment in SwTxtFrm::GetCrsrOfst()
819 : #if OSL_DEBUG_LEVEL > 0
820 : const sal_uLong nOldNode = pPam->GetPoint()->nNode.GetIndex();
821 : #endif
822 : // The node should not be changed
823 : sal_Int32 nTmpOfst = aLine.GetCrsrOfst( pPam->GetPoint(),
824 0 : aCharBox.Pos(), false );
825 : #if OSL_DEBUG_LEVEL > 0
826 : OSL_ENSURE( nOldNode == pPam->GetPoint()->nNode.GetIndex(),
827 : "SwTxtFrm::UnitUp: illegal node change" );
828 : #endif
829 :
830 : // We make sure that we move up.
831 0 : if( nTmpOfst >= nStart && nStart && !bSecondOfDouble )
832 : {
833 0 : nTmpOfst = nStart;
834 0 : aSet.SetRight( true );
835 : }
836 0 : pPam->GetPoint()->nContent =
837 0 : SwIndex( ((SwTxtFrm*)this)->GetTxtNode(), nTmpOfst );
838 0 : return true;
839 : }
840 :
841 0 : if ( IsFollow() )
842 : {
843 0 : aLine.GetCharRect( &aCharBox, nPos );
844 0 : aCharBox.SSize().Width() /= 2;
845 : }
846 0 : break;
847 0 : } while ( true );
848 : }
849 : /* If 'this' is a follow and a prev failed, we need to go to the
850 : * last line of the master, which is us.
851 : * Or: If we are a follow with follow, we need to get the master.
852 : */
853 4 : if ( IsFollow() )
854 : {
855 0 : const SwTxtFrm *pTmpPrev = FindMaster();
856 0 : sal_Int32 nOffs = GetOfst();
857 0 : if( pTmpPrev )
858 : {
859 0 : SwViewShell *pSh = getRootFrm()->GetCurrShell();
860 0 : const bool bProtectedAllowed = pSh && pSh->GetViewOptions()->IsCursorInProtectedArea();
861 0 : const SwTxtFrm *pPrevPrev = pTmpPrev;
862 : // We skip protected frames and frames without content here
863 0 : while( pPrevPrev && ( pPrevPrev->GetOfst() == nOffs ||
864 0 : ( !bProtectedAllowed && pPrevPrev->IsProtected() ) ) )
865 : {
866 0 : pTmpPrev = pPrevPrev;
867 0 : nOffs = pTmpPrev->GetOfst();
868 0 : if ( pPrevPrev->IsFollow() )
869 0 : pPrevPrev = pTmpPrev->FindMaster();
870 : else
871 0 : pPrevPrev = NULL;
872 : }
873 0 : if ( !pPrevPrev )
874 0 : return pTmpPrev->SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
875 0 : aCharBox.Pos().Y() = pPrevPrev->Frm().Bottom() - 1;
876 0 : return pPrevPrev->GetKeyCrsrOfst( pPam->GetPoint(), aCharBox.Pos() );
877 : }
878 : }
879 4 : return SwCntntFrm::UnitUp( pPam, nOffset, bSetInReadOnly );
880 : }
881 :
882 : // Used for Bidi. nPos is the logical position in the string, bLeft indicates
883 : // if left arrow or right arrow was pressed. The return values are:
884 : // nPos: the new visual position
885 : // bLeft: whether the break iterator has to add or subtract from the
886 : // current position
887 0 : static void lcl_VisualMoveRecursion( const SwLineLayout& rCurrLine, sal_Int32 nIdx,
888 : sal_Int32& nPos, bool& bRight,
889 : sal_uInt8& nCrsrLevel, sal_uInt8 nDefaultDir )
890 : {
891 0 : const SwLinePortion* pPor = rCurrLine.GetFirstPortion();
892 0 : const SwLinePortion* pLast = 0;
893 :
894 : // What's the current portion?
895 0 : while ( pPor && nIdx + pPor->GetLen() <= nPos )
896 : {
897 0 : nIdx = nIdx + pPor->GetLen();
898 0 : pLast = pPor;
899 0 : pPor = pPor->GetPortion();
900 : }
901 :
902 0 : if ( bRight )
903 : {
904 0 : bool bRecurse = pPor && pPor->IsMultiPortion() &&
905 0 : ((SwMultiPortion*)pPor)->IsBidi();
906 :
907 : // 1. special case: at beginning of bidi portion
908 0 : if ( bRecurse && nIdx == nPos )
909 : {
910 0 : nPos = nPos + pPor->GetLen();
911 :
912 : // leave bidi portion
913 0 : if ( nCrsrLevel != nDefaultDir )
914 : {
915 0 : bRecurse = false;
916 : }
917 : else
918 : // special case:
919 : // buffer: abcXYZ123 in LTR paragraph
920 : // view: abc123ZYX
921 : // cursor is between c and X in the buffer and cursor level = 0
922 0 : nCrsrLevel++;
923 : }
924 :
925 : // 2. special case: at beginning of portion after bidi portion
926 0 : else if ( pLast && pLast->IsMultiPortion() &&
927 0 : ((SwMultiPortion*)pLast)->IsBidi() && nIdx == nPos )
928 : {
929 : // enter bidi portion
930 0 : if ( nCrsrLevel != nDefaultDir )
931 : {
932 0 : bRecurse = true;
933 0 : nIdx = nIdx - pLast->GetLen();
934 0 : pPor = pLast;
935 : }
936 : }
937 :
938 : // Recursion
939 0 : if ( bRecurse )
940 : {
941 0 : const SwLineLayout& rLine = ((SwMultiPortion*)pPor)->GetRoot();
942 0 : sal_Int32 nTmpPos = nPos - nIdx;
943 0 : bool bTmpForward = ! bRight;
944 0 : sal_uInt8 nTmpCrsrLevel = nCrsrLevel;
945 : lcl_VisualMoveRecursion( rLine, 0, nTmpPos, bTmpForward,
946 0 : nTmpCrsrLevel, nDefaultDir + 1 );
947 :
948 0 : nPos = nTmpPos + nIdx;
949 0 : bRight = bTmpForward;
950 0 : nCrsrLevel = nTmpCrsrLevel;
951 : }
952 :
953 : // go forward
954 : else
955 : {
956 0 : bRight = true;
957 0 : nCrsrLevel = nDefaultDir;
958 : }
959 :
960 : }
961 : else
962 : {
963 0 : bool bRecurse = pPor && pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi();
964 :
965 : // 1. special case: at beginning of bidi portion
966 0 : if ( bRecurse && nIdx == nPos )
967 : {
968 : // leave bidi portion
969 0 : if ( nCrsrLevel == nDefaultDir )
970 : {
971 0 : bRecurse = false;
972 : }
973 : }
974 :
975 : // 2. special case: at beginning of portion after bidi portion
976 0 : else if ( pLast && pLast->IsMultiPortion() &&
977 0 : ((SwMultiPortion*)pLast)->IsBidi() && nIdx == nPos )
978 : {
979 0 : nPos = nPos - pLast->GetLen();
980 :
981 : // enter bidi portion
982 0 : if ( nCrsrLevel % 2 == nDefaultDir % 2 )
983 : {
984 0 : bRecurse = true;
985 0 : nIdx = nIdx - pLast->GetLen();
986 0 : pPor = pLast;
987 :
988 : // special case:
989 : // buffer: abcXYZ123 in LTR paragraph
990 : // view: abc123ZYX
991 : // cursor is behind 3 in the buffer and cursor level = 2
992 0 : if ( nDefaultDir + 2 == nCrsrLevel )
993 0 : nPos = nPos + pLast->GetLen();
994 : }
995 : }
996 :
997 : // go forward
998 0 : if ( bRecurse )
999 : {
1000 0 : const SwLineLayout& rLine = ((SwMultiPortion*)pPor)->GetRoot();
1001 0 : sal_Int32 nTmpPos = nPos - nIdx;
1002 0 : bool bTmpForward = ! bRight;
1003 0 : sal_uInt8 nTmpCrsrLevel = nCrsrLevel;
1004 : lcl_VisualMoveRecursion( rLine, 0, nTmpPos, bTmpForward,
1005 0 : nTmpCrsrLevel, nDefaultDir + 1 );
1006 :
1007 : // special case:
1008 : // buffer: abcXYZ123 in LTR paragraph
1009 : // view: abc123ZYX
1010 : // cursor is between Z and 1 in the buffer and cursor level = 2
1011 0 : if ( nTmpPos == pPor->GetLen() && nTmpCrsrLevel == nDefaultDir + 1 )
1012 : {
1013 0 : nTmpPos = nTmpPos - pPor->GetLen();
1014 0 : nTmpCrsrLevel = nDefaultDir;
1015 0 : bTmpForward = ! bTmpForward;
1016 : }
1017 :
1018 0 : nPos = nTmpPos + nIdx;
1019 0 : bRight = bTmpForward;
1020 0 : nCrsrLevel = nTmpCrsrLevel;
1021 : }
1022 :
1023 : // go backward
1024 : else
1025 : {
1026 0 : bRight = false;
1027 0 : nCrsrLevel = nDefaultDir;
1028 : }
1029 : }
1030 0 : }
1031 :
1032 0 : void SwTxtFrm::PrepareVisualMove( sal_Int32& nPos, sal_uInt8& nCrsrLevel,
1033 : bool& bForward, bool bInsertCrsr )
1034 : {
1035 0 : if( IsEmpty() || IsHiddenNow() )
1036 0 : return;
1037 :
1038 0 : ((SwTxtFrm*)this)->GetFormatted();
1039 :
1040 0 : SwTxtSizeInfo aInf( (SwTxtFrm*)this );
1041 0 : SwTxtCursor aLine( ((SwTxtFrm*)this), &aInf );
1042 :
1043 0 : if( nPos )
1044 0 : aLine.CharCrsrToLine( nPos );
1045 : else
1046 0 : aLine.Top();
1047 :
1048 0 : const SwLineLayout* pLine = aLine.GetCurr();
1049 0 : const sal_Int32 nStt = aLine.GetStart();
1050 0 : const sal_Int32 nLen = pLine->GetLen();
1051 :
1052 : // We have to distinguish between an insert and overwrite cursor:
1053 : // The insert cursor position depends on the cursor level:
1054 : // buffer: abcXYZdef in LTR paragraph
1055 : // display: abcZYXdef
1056 : // If cursor is between c and X in the buffer and cursor level is 0,
1057 : // the cursor blinks between c and Z and -> sets the cursor between Z and Y.
1058 : // If the cursor level is 1, the cursor blinks between X and d and
1059 : // -> sets the cursor between d and e.
1060 : // The overwrite cursor simply travels to the next visual character.
1061 0 : if ( bInsertCrsr )
1062 : {
1063 : lcl_VisualMoveRecursion( *pLine, nStt, nPos, bForward,
1064 0 : nCrsrLevel, IsRightToLeft() ? 1 : 0 );
1065 0 : return;
1066 : }
1067 :
1068 0 : const sal_uInt8 nDefaultDir = static_cast<sal_uInt8>(IsRightToLeft() ? UBIDI_RTL : UBIDI_LTR);
1069 0 : const bool bVisualRight = ( nDefaultDir == UBIDI_LTR && bForward ) ||
1070 0 : ( nDefaultDir == UBIDI_RTL && ! bForward );
1071 :
1072 : // Bidi functions from icu 2.0
1073 :
1074 0 : const sal_Unicode* pLineString = GetTxtNode()->GetTxt().getStr();
1075 :
1076 0 : UErrorCode nError = U_ZERO_ERROR;
1077 0 : UBiDi* pBidi = ubidi_openSized( nLen, 0, &nError );
1078 0 : ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(pLineString), nLen, nDefaultDir, NULL, &nError ); // UChar != sal_Unicode in MinGW
1079 :
1080 0 : sal_Int32 nTmpPos = 0;
1081 0 : bool bOutOfBounds = false;
1082 :
1083 0 : if ( nPos < nStt + nLen )
1084 : {
1085 0 : nTmpPos = ubidi_getVisualIndex( pBidi, nPos, &nError );
1086 :
1087 : // visual indices are always LTR aligned
1088 0 : if ( bVisualRight )
1089 : {
1090 0 : if ( nTmpPos + 1 < nStt + nLen )
1091 0 : ++nTmpPos;
1092 : else
1093 : {
1094 0 : nPos = nDefaultDir == UBIDI_RTL ? 0 : nStt + nLen;
1095 0 : bOutOfBounds = true;
1096 : }
1097 : }
1098 : else
1099 : {
1100 0 : if ( nTmpPos )
1101 0 : --nTmpPos;
1102 : else
1103 : {
1104 0 : nPos = nDefaultDir == UBIDI_RTL ? nStt + nLen : 0;
1105 0 : bOutOfBounds = true;
1106 : }
1107 : }
1108 : }
1109 : else
1110 : {
1111 0 : nTmpPos = nDefaultDir == UBIDI_LTR ? nPos - 1 : 0;
1112 : }
1113 :
1114 0 : if ( ! bOutOfBounds )
1115 : {
1116 0 : nPos = ubidi_getLogicalIndex( pBidi, nTmpPos, &nError );
1117 :
1118 0 : if ( bForward )
1119 : {
1120 0 : if ( nPos )
1121 0 : --nPos;
1122 : else
1123 : {
1124 0 : ++nPos;
1125 0 : bForward = ! bForward;
1126 : }
1127 : }
1128 : else
1129 0 : ++nPos;
1130 : }
1131 :
1132 0 : ubidi_close( pBidi );
1133 : }
1134 :
1135 2 : bool SwTxtFrm::_UnitDown(SwPaM *pPam, const SwTwips nOffset,
1136 : bool bSetInReadOnly ) const
1137 : {
1138 :
1139 4 : if ( IsInTab() &&
1140 2 : pPam->GetNode( true ).StartOfSectionNode() !=
1141 2 : pPam->GetNode( false ).StartOfSectionNode() )
1142 : {
1143 : // If the PaM is located within different boxes, we have a table selection,
1144 : // which is handled by the base class.
1145 0 : return SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
1146 : }
1147 2 : ((SwTxtFrm*)this)->GetFormatted();
1148 2 : const sal_Int32 nPos = pPam->GetPoint()->nContent.GetIndex();
1149 2 : SwRect aCharBox;
1150 2 : const SwCntntFrm *pTmpFollow = 0;
1151 :
1152 2 : if ( IsVertical() )
1153 0 : ((SwTxtFrm*)this)->SwapWidthAndHeight();
1154 :
1155 2 : if ( !IsEmpty() && !IsHiddenNow() )
1156 : {
1157 2 : sal_Int32 nFormat = COMPLETE_STRING;
1158 : do
1159 : {
1160 2 : if( nFormat != COMPLETE_STRING && !IsFollow() &&
1161 0 : !sw_ChangeOffset( ((SwTxtFrm*)this), nFormat ) )
1162 2 : break;
1163 :
1164 2 : SwTxtSizeInfo aInf( (SwTxtFrm*)this );
1165 2 : SwTxtCursor aLine( ((SwTxtFrm*)this), &aInf );
1166 2 : nFormat = aLine.GetEnd();
1167 :
1168 2 : aLine.CharCrsrToLine( nPos );
1169 :
1170 2 : const SwLineLayout* pNextLine = aLine.GetNextLine();
1171 2 : const sal_Int32 nStart = aLine.GetStart();
1172 2 : aLine.GetCharRect( &aCharBox, nPos );
1173 :
1174 2 : bool bFirstOfDouble = ( aInf.IsMulti() && aInf.IsFirstMulti() );
1175 :
1176 2 : if( pNextLine || bFirstOfDouble )
1177 : {
1178 0 : aCharBox.SSize().Width() /= 2;
1179 : #if OSL_DEBUG_LEVEL > 0
1180 : // See comment in SwTxtFrm::GetCrsrOfst()
1181 : const sal_uLong nOldNode = pPam->GetPoint()->nNode.GetIndex();
1182 : #endif
1183 0 : if ( pNextLine && ! bFirstOfDouble )
1184 0 : aLine.NextLine();
1185 :
1186 : sal_Int32 nTmpOfst = aLine.GetCrsrOfst( pPam->GetPoint(),
1187 0 : aCharBox.Pos(), false );
1188 : #if OSL_DEBUG_LEVEL > 0
1189 : OSL_ENSURE( nOldNode == pPam->GetPoint()->nNode.GetIndex(),
1190 : "SwTxtFrm::UnitDown: illegal node change" );
1191 : #endif
1192 :
1193 : // We make sure that we move down.
1194 0 : if( nTmpOfst <= nStart && ! bFirstOfDouble )
1195 0 : nTmpOfst = nStart + 1;
1196 0 : pPam->GetPoint()->nContent =
1197 0 : SwIndex( ((SwTxtFrm*)this)->GetTxtNode(), nTmpOfst );
1198 :
1199 0 : if ( IsVertical() )
1200 0 : ((SwTxtFrm*)this)->SwapWidthAndHeight();
1201 :
1202 0 : return true;
1203 : }
1204 2 : if( 0 != ( pTmpFollow = GetFollow() ) )
1205 : { // Skip protected follows
1206 0 : const SwCntntFrm* pTmp = pTmpFollow;
1207 0 : SwViewShell *pSh = getRootFrm()->GetCurrShell();
1208 0 : if( !pSh || !pSh->GetViewOptions()->IsCursorInProtectedArea() )
1209 : {
1210 0 : while( pTmpFollow && pTmpFollow->IsProtected() )
1211 : {
1212 0 : pTmp = pTmpFollow;
1213 0 : pTmpFollow = pTmpFollow->GetFollow();
1214 : }
1215 : }
1216 0 : if( !pTmpFollow ) // Only protected ones left
1217 : {
1218 0 : if ( IsVertical() )
1219 0 : ((SwTxtFrm*)this)->SwapWidthAndHeight();
1220 0 : return pTmp->SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
1221 : }
1222 :
1223 0 : aLine.GetCharRect( &aCharBox, nPos );
1224 0 : aCharBox.SSize().Width() /= 2;
1225 : }
1226 2 : else if( !IsFollow() )
1227 : {
1228 2 : sal_Int32 nTmpLen = aInf.GetTxt().getLength();
1229 2 : if( aLine.GetEnd() < nTmpLen )
1230 : {
1231 0 : if( nFormat <= GetOfst() )
1232 : {
1233 0 : nFormat = std::min( sal_Int32( GetOfst() + MIN_OFFSET_STEP ),
1234 0 : static_cast<sal_Int32>(nTmpLen) );
1235 0 : if( nFormat <= GetOfst() )
1236 0 : break;
1237 : }
1238 0 : continue;
1239 : }
1240 : }
1241 2 : break;
1242 0 : } while( true );
1243 : }
1244 : else
1245 0 : pTmpFollow = GetFollow();
1246 :
1247 2 : if ( IsVertical() )
1248 0 : ((SwTxtFrm*)this)->SwapWidthAndHeight();
1249 :
1250 : // We take a shortcut for follows
1251 2 : if( pTmpFollow )
1252 : {
1253 0 : aCharBox.Pos().Y() = pTmpFollow->Frm().Top() + 1;
1254 : return ((SwTxtFrm*)pTmpFollow)->GetKeyCrsrOfst( pPam->GetPoint(),
1255 0 : aCharBox.Pos() );
1256 : }
1257 2 : return SwCntntFrm::UnitDown( pPam, nOffset, bSetInReadOnly );
1258 : }
1259 :
1260 4 : bool SwTxtFrm::UnitUp(SwPaM *pPam, const SwTwips nOffset,
1261 : bool bSetInReadOnly ) const
1262 : {
1263 : /* We call CntntNode::GertFrm() in CrsrSh::Up().
1264 : * This _always returns the master.
1265 : * In order to not mess with cursor travelling, we correct here
1266 : * in SwTxtFrm.
1267 : * We calculate UnitUp for pFrm. pFrm is either a master (= this) or a
1268 : * follow (!= this).
1269 : */
1270 4 : const SwTxtFrm *pFrm = GetAdjFrmAtPos( (SwTxtFrm*)this, *(pPam->GetPoint()),
1271 8 : SwTxtCursor::IsRightMargin() );
1272 4 : const bool bRet = pFrm->_UnitUp( pPam, nOffset, bSetInReadOnly );
1273 :
1274 : // No SwTxtCursor::SetRightMargin( false );
1275 : // Instead we have a SwSetToRightMargin in _UnitUp
1276 4 : return bRet;
1277 : }
1278 :
1279 2 : bool SwTxtFrm::UnitDown(SwPaM *pPam, const SwTwips nOffset,
1280 : bool bSetInReadOnly ) const
1281 : {
1282 2 : const SwTxtFrm *pFrm = GetAdjFrmAtPos((SwTxtFrm*)this, *(pPam->GetPoint()),
1283 4 : SwTxtCursor::IsRightMargin() );
1284 2 : const bool bRet = pFrm->_UnitDown( pPam, nOffset, bSetInReadOnly );
1285 2 : SwTxtCursor::SetRightMargin( false );
1286 2 : return bRet;
1287 : }
1288 :
1289 0 : void SwTxtFrm::FillCrsrPos( SwFillData& rFill ) const
1290 : {
1291 0 : if( !rFill.bColumn && GetUpper()->IsColBodyFrm() ) // ColumnFrms now with BodyFrm
1292 : {
1293 : const SwColumnFrm* pTmp =
1294 0 : (SwColumnFrm*)GetUpper()->GetUpper()->GetUpper()->Lower(); // The 1st column
1295 : // The first SwFrm in BodyFrm of the first column
1296 0 : const SwFrm* pFrm = ((SwLayoutFrm*)pTmp->Lower())->Lower();
1297 0 : sal_uInt16 nNextCol = 0;
1298 : // In which column do we end up in?
1299 0 : while( rFill.X() > pTmp->Frm().Right() && pTmp->GetNext() )
1300 : {
1301 0 : pTmp = (SwColumnFrm*)pTmp->GetNext();
1302 0 : if( ((SwLayoutFrm*)pTmp->Lower())->Lower() ) // ColumnFrms now with BodyFrm
1303 : {
1304 0 : pFrm = ((SwLayoutFrm*)pTmp->Lower())->Lower();
1305 0 : nNextCol = 0;
1306 : }
1307 : else
1308 0 : ++nNextCol; // Empty columns require column brakes
1309 : }
1310 0 : if( pTmp != GetUpper()->GetUpper() ) // Did we end up in another column?
1311 : {
1312 0 : if( !pFrm )
1313 0 : return;
1314 0 : if( nNextCol )
1315 : {
1316 0 : while( pFrm->GetNext() )
1317 0 : pFrm = pFrm->GetNext();
1318 : }
1319 : else
1320 : {
1321 0 : while( pFrm->GetNext() && pFrm->Frm().Bottom() < rFill.Y() )
1322 0 : pFrm = pFrm->GetNext();
1323 : }
1324 : // No filling, if the last frame in the targeted column does
1325 : // not contain a paragraph, but e.g. a table
1326 0 : if( pFrm->IsTxtFrm() )
1327 : {
1328 0 : rFill.Fill().nColumnCnt = nNextCol;
1329 0 : rFill.bColumn = true;
1330 0 : if( rFill.pPos )
1331 : {
1332 0 : SwTxtNode* pTxtNd = ((SwTxtFrm*)pFrm)->GetTxtNode();
1333 0 : rFill.pPos->nNode = *pTxtNd;
1334 : rFill.pPos->nContent.Assign(
1335 0 : pTxtNd, pTxtNd->GetTxt().getLength());
1336 : }
1337 0 : if( nNextCol )
1338 : {
1339 0 : rFill.aFrm = pTmp->Prt();
1340 0 : rFill.aFrm += pTmp->Frm().Pos();
1341 : }
1342 : else
1343 0 : rFill.aFrm = pFrm->Frm();
1344 0 : ((SwTxtFrm*)pFrm)->FillCrsrPos( rFill );
1345 : }
1346 0 : return;
1347 : }
1348 : }
1349 : SwFont *pFnt;
1350 0 : SwTxtFmtColl* pColl = GetTxtNode()->GetTxtColl();
1351 0 : SwTwips nFirst = GetTxtNode()->GetSwAttrSet().GetULSpace().GetLower();
1352 0 : SwTwips nDiff = rFill.Y() - Frm().Bottom();
1353 0 : if( nDiff < nFirst )
1354 0 : nDiff = -1;
1355 : else
1356 0 : pColl = &pColl->GetNextTxtFmtColl();
1357 0 : SwAttrSet aSet( ((SwDoc*)GetTxtNode()->GetDoc())->GetAttrPool(), aTxtFmtCollSetRange );
1358 0 : const SwAttrSet* pSet = &pColl->GetAttrSet();
1359 0 : SwViewShell *pSh = getRootFrm()->GetCurrShell();
1360 0 : if( GetTxtNode()->HasSwAttrSet() )
1361 : {
1362 0 : aSet.Put( *GetTxtNode()->GetpSwAttrSet() );
1363 0 : aSet.SetParent( pSet );
1364 0 : pSet = &aSet;
1365 0 : pFnt = new SwFont( pSet, GetNode()->getIDocumentSettingAccess() );
1366 : }
1367 : else
1368 : {
1369 0 : SwFontAccess aFontAccess( pColl, pSh );
1370 0 : pFnt = new SwFont( aFontAccess.Get()->GetFont() );
1371 0 : pFnt->ChkMagic( pSh, pFnt->GetActual() );
1372 : }
1373 0 : OutputDevice* pOut = pSh->GetOut();
1374 0 : if( !pSh->GetViewOptions()->getBrowseMode() || pSh->GetViewOptions()->IsPrtFormat() )
1375 0 : pOut = GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
1376 :
1377 0 : pFnt->SetFntChg( true );
1378 0 : pFnt->ChgPhysFnt( pSh, *pOut );
1379 :
1380 0 : SwTwips nLineHeight = pFnt->GetHeight( pSh, *pOut );
1381 :
1382 0 : bool bFill = false;
1383 0 : if( nLineHeight )
1384 : {
1385 0 : bFill = true;
1386 0 : const SvxULSpaceItem &rUL = pSet->GetULSpace();
1387 0 : SwTwips nDist = std::max( rUL.GetLower(), rUL.GetUpper() );
1388 0 : if( rFill.Fill().nColumnCnt )
1389 : {
1390 0 : rFill.aFrm.Height( nLineHeight );
1391 0 : nDiff = rFill.Y() - rFill.Bottom();
1392 0 : nFirst = 0;
1393 : }
1394 0 : else if( nDist < nFirst )
1395 0 : nFirst = nFirst - nDist;
1396 : else
1397 0 : nFirst = 0;
1398 0 : nDist = std::max( nDist, long( GetLineSpace() ) );
1399 0 : nDist += nLineHeight;
1400 0 : nDiff -= nFirst;
1401 :
1402 0 : if( nDiff > 0 )
1403 : {
1404 0 : nDiff /= nDist;
1405 0 : rFill.Fill().nParaCnt = static_cast<sal_uInt16>(nDiff + 1);
1406 0 : rFill.nLineWidth = 0;
1407 0 : rFill.bInner = false;
1408 0 : rFill.bEmpty = true;
1409 0 : rFill.SetOrient( text::HoriOrientation::LEFT );
1410 : }
1411 : else
1412 0 : nDiff = -1;
1413 0 : if( rFill.bInner )
1414 0 : bFill = false;
1415 : else
1416 : {
1417 0 : const SvxTabStopItem &rRuler = pSet->GetTabStops();
1418 0 : const SvxLRSpaceItem &rLRSpace = pSet->GetLRSpace();
1419 :
1420 0 : SwRect &rRect = rFill.Fill().aCrsr;
1421 0 : rRect.Top( rFill.Bottom() + (nDiff+1) * nDist - nLineHeight );
1422 0 : if( nFirst && nDiff > -1 )
1423 0 : rRect.Top( rRect.Top() + nFirst );
1424 0 : rRect.Height( nLineHeight );
1425 0 : SwTwips nLeft = rFill.Left() + rLRSpace.GetLeft() +
1426 0 : GetTxtNode()->GetLeftMarginWithNum();
1427 0 : SwTwips nRight = rFill.Right() - rLRSpace.GetRight();
1428 0 : SwTwips nCenter = ( nLeft + nRight ) / 2;
1429 0 : rRect.Left( nLeft );
1430 0 : if( FILL_MARGIN == rFill.Mode() )
1431 : {
1432 0 : if( rFill.bEmpty )
1433 : {
1434 0 : rFill.SetOrient( text::HoriOrientation::LEFT );
1435 0 : if( rFill.X() < nCenter )
1436 : {
1437 0 : if( rFill.X() > ( nLeft + 2 * nCenter ) / 3 )
1438 : {
1439 0 : rFill.SetOrient( text::HoriOrientation::CENTER );
1440 0 : rRect.Left( nCenter );
1441 : }
1442 : }
1443 0 : else if( rFill.X() > ( nRight + 2 * nCenter ) / 3 )
1444 : {
1445 0 : rFill.SetOrient( text::HoriOrientation::RIGHT );
1446 0 : rRect.Left( nRight );
1447 : }
1448 : else
1449 : {
1450 0 : rFill.SetOrient( text::HoriOrientation::CENTER );
1451 0 : rRect.Left( nCenter );
1452 : }
1453 : }
1454 : else
1455 0 : bFill = false;
1456 : }
1457 : else
1458 : {
1459 0 : SwTwips nSpace = 0;
1460 0 : if( FILL_TAB != rFill.Mode() )
1461 : {
1462 0 : const OUString aTmp(" ");
1463 0 : SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTmp, 0, 2 );
1464 0 : nSpace = pFnt->_GetTxtSize( aDrawInf ).Width()/2;
1465 : }
1466 0 : if( rFill.X() >= nRight )
1467 : {
1468 0 : if( FILL_INDENT != rFill.Mode() && ( rFill.bEmpty ||
1469 0 : rFill.X() > rFill.nLineWidth + FILL_MIN_DIST ) )
1470 : {
1471 0 : rFill.SetOrient( text::HoriOrientation::RIGHT );
1472 0 : rRect.Left( nRight );
1473 : }
1474 : else
1475 0 : bFill = false;
1476 : }
1477 0 : else if( FILL_INDENT == rFill.Mode() )
1478 : {
1479 0 : SwTwips nIndent = rFill.X();
1480 0 : if( !rFill.bEmpty || nIndent > nRight )
1481 0 : bFill = false;
1482 : else
1483 : {
1484 0 : nIndent -= rFill.Left();
1485 0 : if( nIndent >= 0 && nSpace )
1486 : {
1487 0 : nIndent /= nSpace;
1488 0 : nIndent *= nSpace;
1489 0 : rFill.SetTab( sal_uInt16( nIndent ) );
1490 0 : rRect.Left( nIndent + rFill.Left() );
1491 : }
1492 : else
1493 0 : bFill = false;
1494 : }
1495 : }
1496 0 : else if( rFill.X() > nLeft )
1497 : {
1498 0 : SwTwips nTxtLeft = rFill.Left() + rLRSpace.GetTxtLeft() +
1499 0 : GetTxtNode()->GetLeftMarginWithNum( true );
1500 0 : rFill.nLineWidth += rFill.bFirstLine ? nLeft : nTxtLeft;
1501 0 : SwTwips nLeftTab = nLeft;
1502 0 : SwTwips nRightTab = nLeft;
1503 0 : sal_uInt16 nSpaceCnt = 0;
1504 0 : sal_uInt16 nTabCnt = 0;
1505 0 : sal_uInt16 nIdx = 0;
1506 0 : do
1507 : {
1508 0 : nLeftTab = nRightTab;
1509 0 : if( nIdx < rRuler.Count() )
1510 : {
1511 0 : const SvxTabStop &rTabStop = rRuler.operator[](nIdx);
1512 0 : nRightTab = nTxtLeft + rTabStop.GetTabPos();
1513 0 : if( nLeftTab < nTxtLeft && nRightTab > nTxtLeft )
1514 0 : nRightTab = nTxtLeft;
1515 : else
1516 0 : ++nIdx;
1517 0 : if( nRightTab > rFill.nLineWidth )
1518 0 : ++nTabCnt;
1519 : }
1520 : else
1521 : {
1522 : const SvxTabStopItem& rTab =
1523 : (const SvxTabStopItem &)pSet->
1524 0 : GetPool()->GetDefaultItem( RES_PARATR_TABSTOP );
1525 0 : const SwTwips nDefTabDist = rTab[0].GetTabPos();
1526 0 : nRightTab = nLeftTab - nTxtLeft;
1527 0 : nRightTab /= nDefTabDist;
1528 0 : nRightTab = nRightTab * nDefTabDist + nTxtLeft;
1529 0 : while ( nRightTab <= nLeftTab )
1530 0 : nRightTab += nDefTabDist;
1531 0 : if( nRightTab > rFill.nLineWidth )
1532 0 : ++nTabCnt;
1533 0 : while ( nRightTab < rFill.X() )
1534 : {
1535 0 : nRightTab += nDefTabDist;
1536 0 : if( nRightTab > rFill.nLineWidth )
1537 0 : ++nTabCnt;
1538 : }
1539 0 : if( nLeftTab < nRightTab - nDefTabDist )
1540 0 : nLeftTab = nRightTab - nDefTabDist;
1541 : }
1542 0 : if( nRightTab > nRight )
1543 0 : nRightTab = nRight;
1544 : }
1545 0 : while( rFill.X() > nRightTab );
1546 0 : --nTabCnt;
1547 0 : if( FILL_TAB != rFill.Mode() )
1548 : {
1549 0 : if( nSpace > 0 )
1550 : {
1551 0 : if( !nTabCnt )
1552 0 : nLeftTab = rFill.nLineWidth;
1553 0 : while( nLeftTab < rFill.X() )
1554 : {
1555 0 : nLeftTab += nSpace;
1556 0 : ++nSpaceCnt;
1557 : }
1558 0 : if( nSpaceCnt )
1559 : {
1560 0 : nLeftTab -= nSpace;
1561 0 : --nSpaceCnt;
1562 : }
1563 0 : if( rFill.X() - nLeftTab > nRightTab - rFill.X() )
1564 : {
1565 0 : nSpaceCnt = 0;
1566 0 : ++nTabCnt;
1567 0 : rRect.Left( nRightTab );
1568 : }
1569 : else
1570 : {
1571 0 : if( rFill.X() - nLeftTab > nSpace/2 )
1572 : {
1573 0 : ++nSpaceCnt;
1574 0 : rRect.Left( nLeftTab + nSpace );
1575 : }
1576 : else
1577 0 : rRect.Left( nLeftTab );
1578 : }
1579 : }
1580 0 : else if( rFill.X() - nLeftTab < nRightTab - rFill.X() )
1581 0 : rRect.Left( nLeftTab );
1582 : else
1583 : {
1584 0 : if( nRightTab >= nRight )
1585 : {
1586 0 : rFill.SetOrient( text::HoriOrientation::RIGHT );
1587 0 : rRect.Left( nRight );
1588 0 : nTabCnt = 0;
1589 0 : nSpaceCnt = 0;
1590 : }
1591 : else
1592 : {
1593 0 : rRect.Left( nRightTab );
1594 0 : ++nTabCnt;
1595 : }
1596 : }
1597 : }
1598 : else
1599 : {
1600 0 : if( rFill.X() - nLeftTab < nRightTab - rFill.X() )
1601 0 : rRect.Left( nLeftTab );
1602 : else
1603 : {
1604 0 : if( nRightTab >= nRight )
1605 : {
1606 0 : rFill.SetOrient( text::HoriOrientation::RIGHT );
1607 0 : rRect.Left( nRight );
1608 0 : nTabCnt = 0;
1609 0 : nSpaceCnt = 0;
1610 : }
1611 : else
1612 : {
1613 0 : rRect.Left( nRightTab );
1614 0 : ++nTabCnt;
1615 : }
1616 : }
1617 : }
1618 0 : rFill.SetTab( nTabCnt );
1619 0 : rFill.SetSpace( nSpaceCnt );
1620 0 : if( bFill )
1621 : {
1622 0 : if( std::abs( rFill.X() - nCenter ) <=
1623 0 : std::abs( rFill.X() - rRect.Left() ) )
1624 : {
1625 0 : rFill.SetOrient( text::HoriOrientation::CENTER );
1626 0 : rFill.SetTab( 0 );
1627 0 : rFill.SetSpace( 0 );
1628 0 : rRect.Left( nCenter );
1629 : }
1630 0 : if( !rFill.bEmpty )
1631 0 : rFill.nLineWidth += FILL_MIN_DIST;
1632 0 : if( rRect.Left() < rFill.nLineWidth )
1633 0 : bFill = false;
1634 : }
1635 : }
1636 : }
1637 : // Do we extend over the page's/column's/etc. lower edge?
1638 0 : const SwFrm* pUp = GetUpper();
1639 0 : if( pUp->IsInSct() )
1640 : {
1641 0 : if( pUp->IsSctFrm() )
1642 0 : pUp = pUp->GetUpper();
1643 0 : else if( pUp->IsColBodyFrm() &&
1644 0 : pUp->GetUpper()->GetUpper()->IsSctFrm() )
1645 0 : pUp = pUp->GetUpper()->GetUpper()->GetUpper();
1646 : }
1647 0 : SWRECTFN( this )
1648 0 : SwTwips nLimit = (pUp->*fnRect->fnGetPrtBottom)();
1649 0 : SwTwips nRectBottom = rRect.Bottom();
1650 0 : if ( bVert )
1651 0 : nRectBottom = SwitchHorizontalToVertical( nRectBottom );
1652 :
1653 0 : if( (*fnRect->fnYDiff)( nLimit, nRectBottom ) < 0 )
1654 0 : bFill = false;
1655 : else
1656 0 : rRect.Width( 1 );
1657 : }
1658 : }
1659 0 : ((SwCrsrMoveState*)rFill.pCMS)->bFillRet = bFill;
1660 0 : delete pFnt;
1661 270 : }
1662 :
1663 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|