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