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