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