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