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