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 : :
30 : : #include <vcl/wrkwin.hxx>
31 : : #include <vcl/dialog.hxx>
32 : : #include <vcl/msgbox.hxx>
33 : : #include <vcl/svapp.hxx>
34 : : #include <vcl/metaact.hxx>
35 : : #include <vcl/gdimtf.hxx>
36 : :
37 : : #include <editeng/adjitem.hxx>
38 : : #include <editeng/tstpitem.hxx>
39 : : #include <editeng/lspcitem.hxx>
40 : : #include <editeng/flditem.hxx>
41 : : #include <impedit.hxx>
42 : : #include <editeng/editeng.hxx>
43 : : #include <editeng/editview.hxx>
44 : : #include <editeng/txtrange.hxx>
45 : : #include <editeng/cscoitem.hxx>
46 : : #include <editeng/colritem.hxx>
47 : : #include <editeng/udlnitem.hxx>
48 : : #include <editeng/fhgtitem.hxx>
49 : : #include <editeng/kernitem.hxx>
50 : : #include <editeng/lrspitem.hxx>
51 : : #include <editeng/ulspitem.hxx>
52 : : #include <editeng/fontitem.hxx>
53 : : #include <editeng/wghtitem.hxx>
54 : : #include <editeng/postitem.hxx>
55 : : #include <editeng/langitem.hxx>
56 : : #include <editeng/scriptspaceitem.hxx>
57 : : #include <editeng/charscaleitem.hxx>
58 : : #include <editeng/numitem.hxx>
59 : : #include <editeng/justifyitem.hxx>
60 : :
61 : : #include <svtools/colorcfg.hxx>
62 : : #include <svl/ctloptions.hxx>
63 : :
64 : : #include <editeng/forbiddencharacterstable.hxx>
65 : :
66 : : #include <unotools/localedatawrapper.hxx>
67 : :
68 : : #include <editeng/unolingu.hxx>
69 : :
70 : : #include <set>
71 : : #include <math.h>
72 : : #include <vcl/metric.hxx>
73 : : #include <com/sun/star/i18n/ScriptType.hpp>
74 : : #include <com/sun/star/text/CharacterCompressionType.hpp>
75 : : #include <vcl/pdfextoutdevdata.hxx>
76 : : #include <i18npool/mslangid.hxx>
77 : :
78 : : #include <comphelper/processfactory.hxx>
79 : : #include <rtl/ustrbuf.hxx>
80 : : #include <comphelper/string.hxx>
81 : :
82 : : using ::rtl::OUString;
83 : : using namespace ::com::sun::star;
84 : : using namespace ::com::sun::star::uno;
85 : : using namespace ::com::sun::star::beans;
86 : : using namespace ::com::sun::star::linguistic2;
87 : :
88 : : #define CH_HYPH '-'
89 : :
90 : : #define RESDIFF 10
91 : :
92 : : #define WRONG_SHOW_MIN 5
93 : : #define WRONG_SHOW_SMALL 11
94 : : #define WRONG_SHOW_MEDIUM 15
95 : :
96 : : struct TabInfo
97 : : {
98 : : sal_Bool bValid;
99 : :
100 : : SvxTabStop aTabStop;
101 : : xub_StrLen nCharPos;
102 : : sal_uInt16 nTabPortion;
103 : : long nStartPosX;
104 : : long nTabPos;
105 : :
106 : 114343 : TabInfo() { bValid = sal_False; }
107 : : };
108 : :
109 : 680 : Point Rotate( const Point& rPoint, short nOrientation, const Point& rOrigin )
110 : : {
111 : 680 : double nRealOrientation = nOrientation*F_PI1800;
112 : 680 : double nCos = cos( nRealOrientation );
113 : 680 : double nSin = sin( nRealOrientation );
114 : :
115 : 680 : Point aRotatedPos;
116 : 680 : Point aTranslatedPos( rPoint );
117 : :
118 : : // Translation
119 : 680 : aTranslatedPos -= rOrigin;
120 : :
121 : : // Rotation...
122 : 680 : aRotatedPos.X() = (long) ( nCos*aTranslatedPos.X() + nSin*aTranslatedPos.Y() );
123 : 680 : aRotatedPos.Y() = (long) - ( nSin*aTranslatedPos.X() - nCos*aTranslatedPos.Y() );
124 : 680 : aTranslatedPos = aRotatedPos;
125 : :
126 : : // Translation...
127 : 680 : aTranslatedPos += rOrigin;
128 : 680 : return aTranslatedPos;
129 : : }
130 : :
131 : 0 : sal_uInt8 GetCharTypeForCompression( xub_Unicode cChar )
132 : : {
133 [ # # # ]: 0 : switch ( cChar )
134 : : {
135 : : case 0x3008: case 0x300A: case 0x300C: case 0x300E:
136 : : case 0x3010: case 0x3014: case 0x3016: case 0x3018:
137 : : case 0x301A: case 0x301D:
138 : : {
139 : 0 : return CHAR_PUNCTUATIONRIGHT;
140 : : }
141 : : case 0x3001: case 0x3002: case 0x3009: case 0x300B:
142 : : case 0x300D: case 0x300F: case 0x3011: case 0x3015:
143 : : case 0x3017: case 0x3019: case 0x301B: case 0x301E:
144 : : case 0x301F:
145 : : {
146 : 0 : return CHAR_PUNCTUATIONLEFT;
147 : : }
148 : : default:
149 : : {
150 [ # # ][ # # ]: 0 : return ( ( 0x3040 <= cChar ) && ( 0x3100 > cChar ) ) ? CHAR_KANA : CHAR_NORMAL;
151 : : }
152 : : }
153 : : }
154 : :
155 : 517 : void lcl_DrawRedLines(
156 : : OutputDevice* pOutDev,
157 : : long nFontHeight,
158 : : const Point& rPnt,
159 : : sal_uInt16 nIndex,
160 : : sal_uInt16 nMaxEnd,
161 : : const sal_Int32* pDXArray,
162 : : WrongList* pWrongs,
163 : : short nOrientation,
164 : : const Point& rOrigin,
165 : : sal_Bool bVertical,
166 : : sal_Bool bIsRightToLeft )
167 : : {
168 : : // But only if font is not too small ...
169 [ + - ]: 517 : long nHght = pOutDev->LogicToPixel( Size( 0, nFontHeight ) ).Height();
170 [ + - ]: 517 : if( WRONG_SHOW_MIN < nHght )
171 : : {
172 : : sal_uInt16 nStyle;
173 [ + + ]: 517 : if( WRONG_SHOW_MEDIUM < nHght )
174 : 431 : nStyle = WAVE_NORMAL;
175 [ + - ]: 86 : else if( WRONG_SHOW_SMALL < nHght )
176 : 86 : nStyle = WAVE_SMALL;
177 : : else
178 : 0 : nStyle = WAVE_FLAT;
179 : :
180 : 517 : sal_uInt16 nEnd, nStart = nIndex;
181 [ + - ]: 517 : sal_Bool bWrong = pWrongs->NextWrong( nStart, nEnd );
182 [ + + ]: 1034 : while ( bWrong )
183 : : {
184 [ + - ]: 517 : if ( nStart >= nMaxEnd )
185 : : break;
186 : :
187 [ + + ]: 517 : if ( nStart < nIndex ) // Corrected
188 : 248 : nStart = nIndex;
189 [ + + ]: 517 : if ( nEnd > nMaxEnd )
190 : 248 : nEnd = nMaxEnd;
191 : 517 : Point aPnt1( rPnt );
192 [ - + ][ # # ]: 517 : if ( bVertical && ( nStyle != WAVE_FLAT ) )
193 : : {
194 : : // VCL doesn't know that the text is vertical, and is manipulating
195 : : // the positions a little bit in y direction...
196 [ # # ]: 0 : long nOnePixel = pOutDev->PixelToLogic( Size( 0, 1 ) ).Height();
197 [ # # ]: 0 : long nCorrect = ( nStyle == WAVE_NORMAL ) ? 2*nOnePixel : nOnePixel;
198 : 0 : aPnt1.Y() -= nCorrect;
199 : 0 : aPnt1.X() -= nCorrect;
200 : : }
201 [ + + ]: 517 : if ( nStart > nIndex )
202 : : {
203 [ + - ]: 1 : if ( !bVertical )
204 : : {
205 : : // since for RTL portions rPnt is on the visual right end of the portion
206 : : // (i.e. at the start of the first RTL char) we need to subtract the offset
207 : : // for RTL portions...
208 [ - + ]: 1 : aPnt1.X() += (bIsRightToLeft ? -1 : 1) * pDXArray[ nStart - nIndex - 1 ];
209 : : }
210 : : else
211 : 0 : aPnt1.Y() += pDXArray[ nStart - nIndex - 1 ];
212 : : }
213 : 517 : Point aPnt2( rPnt );
214 : : DBG_ASSERT( nEnd > nIndex, "RedLine: aPnt2?" );
215 [ + - ]: 517 : if ( !bVertical )
216 : : {
217 : : // since for RTL portions rPnt is on the visual right end of the portion
218 : : // (i.e. at the start of the first RTL char) we need to subtract the offset
219 : : // for RTL portions...
220 [ - + ]: 517 : aPnt2.X() += (bIsRightToLeft ? -1 : 1) * pDXArray[ nEnd - nIndex - 1 ];
221 : : }
222 : : else
223 : 0 : aPnt2.Y() += pDXArray[ nEnd - nIndex - 1 ];
224 [ + + ]: 517 : if ( nOrientation )
225 : : {
226 : 340 : aPnt1 = Rotate( aPnt1, nOrientation, rOrigin );
227 : 340 : aPnt2 = Rotate( aPnt2, nOrientation, rOrigin );
228 : : }
229 : :
230 [ + - ]: 517 : pOutDev->DrawWaveLine( aPnt1, aPnt2, nStyle );
231 : :
232 : 517 : nStart = nEnd+1;
233 [ + + ]: 517 : if ( nEnd < nMaxEnd )
234 [ + - ]: 1 : bWrong = pWrongs->NextWrong( nStart, nEnd );
235 : : else
236 : 517 : bWrong = sal_False;
237 : : }
238 : : }
239 : 517 : }
240 : :
241 : 1390 : Point lcl_ImplCalcRotatedPos( Point rPos, Point rOrigin, double nSin, double nCos )
242 : : {
243 : 1390 : Point aRotatedPos;
244 : : // Translation...
245 : 1390 : Point aTranslatedPos( rPos);
246 : 1390 : aTranslatedPos -= rOrigin;
247 : :
248 : 1390 : aRotatedPos.X() = (long) ( nCos*aTranslatedPos.X() + nSin*aTranslatedPos.Y() );
249 : 1390 : aRotatedPos.Y() = (long) - ( nSin*aTranslatedPos.X() - nCos*aTranslatedPos.Y() );
250 : 1390 : aTranslatedPos = aRotatedPos;
251 : : // Translation...
252 : 1390 : aTranslatedPos += rOrigin;
253 : :
254 : 1390 : return aTranslatedPos;
255 : : }
256 : :
257 : 0 : sal_Bool lcl_IsLigature( xub_Unicode cCh, xub_Unicode cNextCh ) // For Kashidas from sw/source/core/text/porlay.txt
258 : : {
259 : : // Lam + Alef
260 : : return ( 0x644 == cCh && 0x627 == cNextCh ) ||
261 : : // Beh + Reh
262 [ # # ][ # # ]: 0 : ( 0x628 == cCh && 0x631 == cNextCh );
[ # # ][ # # ]
263 : : }
264 : :
265 : 0 : sal_Bool lcl_ConnectToPrev( xub_Unicode cCh, xub_Unicode cPrevCh ) // For Kashidas from sw/source/core/text/porlay.txt
266 : : {
267 : : // Alef, Dal, Thal, Reh, Zain, and Waw do not connect to the left
268 : : sal_Bool bRet = 0x627 != cPrevCh && 0x62F != cPrevCh && 0x630 != cPrevCh &&
269 [ # # ][ # # ]: 0 : 0x631 != cPrevCh && 0x632 != cPrevCh && 0x648 != cPrevCh;
[ # # ][ # # ]
[ # # ][ # # ]
270 : :
271 : : // check for ligatures cPrevChar + cChar
272 [ # # ]: 0 : if ( bRet )
273 : 0 : bRet = ! lcl_IsLigature( cPrevCh, cCh );
274 : :
275 : 0 : return bRet;
276 : : }
277 : :
278 : :
279 : : // ----------------------------------------------------------------------
280 : : // class ImpEditEngine
281 : : // ----------------------------------------------------------------------
282 : 1248995 : void ImpEditEngine::UpdateViews( EditView* pCurView )
283 : : {
284 [ + + ][ + - ]: 1248995 : if ( !GetUpdateMode() || IsFormatting() || aInvalidRec.IsEmpty() )
[ + + ][ + + ]
285 : 1248995 : return;
286 : :
287 : : DBG_ASSERT( IsFormatted(), "UpdateViews: Doc not formatted!" );
288 : :
289 [ + + ]: 315313 : for (size_t nView = 0; nView < aEditViews.size(); ++nView)
290 : : {
291 : 423 : EditView* pView = aEditViews[nView];
292 : : DBG_CHKOBJ( pView, EditView, 0 );
293 [ + - ]: 423 : pView->HideCursor();
294 : :
295 : 423 : Rectangle aClipRec( aInvalidRec );
296 [ + - ]: 423 : Rectangle aVisArea( pView->GetVisArea() );
297 [ + - ]: 423 : aClipRec.Intersection( aVisArea );
298 : :
299 [ + - ][ + - ]: 423 : if ( !aClipRec.IsEmpty() )
300 : : {
301 : : // convert to window coordinates ....
302 [ + - ]: 423 : aClipRec = pView->pImpEditView->GetWindowPos( aClipRec );
303 : :
304 [ + + ]: 423 : if ( pView == pCurView )
305 [ + - ]: 271 : Paint( pView->pImpEditView, aClipRec, sal_True );
306 : : else
307 [ + - ][ + - ]: 152 : pView->GetWindow()->Invalidate( aClipRec );
308 : : }
309 : : }
310 : :
311 [ + + ]: 314890 : if ( pCurView )
312 : : {
313 : 271 : sal_Bool bGotoCursor = pCurView->pImpEditView->DoAutoScroll();
314 : 271 : pCurView->ShowCursor( bGotoCursor );
315 : : }
316 : :
317 : 314890 : aInvalidRec = Rectangle();
318 : 314890 : CallStatusHdl();
319 : : }
320 : :
321 : 836 : IMPL_LINK_NOARG(ImpEditEngine, OnlineSpellHdl)
322 : : {
323 [ + - ][ + + ]: 836 : if ( !Application::AnyInput( VCL_INPUT_KEYBOARD ) && GetUpdateMode() && IsFormatted() )
[ + + ][ + + ]
324 : 6 : DoOnlineSpelling();
325 : : else
326 : 830 : aOnlineSpellTimer.Start();
327 : :
328 : 836 : return 0;
329 : : }
330 : :
331 : 0 : IMPL_LINK_NOARG_INLINE_START(ImpEditEngine, IdleFormatHdl)
332 : : {
333 : 0 : aIdleFormatter.ResetRestarts();
334 : :
335 : : // #i97146# check if that view is still available
336 : : // else probably the idle format timer fired while we're already
337 : : // downing
338 : 0 : EditView* pView = aIdleFormatter.GetView();
339 [ # # ]: 0 : for (size_t nView = 0; nView < aEditViews.size(); ++nView)
340 : : {
341 [ # # ]: 0 : if( aEditViews[nView] == pView )
342 : : {
343 : 0 : FormatAndUpdate( pView );
344 : 0 : break;
345 : : }
346 : : }
347 : 0 : return 0;
348 : : }
349 : 0 : IMPL_LINK_NOARG_INLINE_END(ImpEditEngine, IdleFormatHdl)
350 : :
351 : 1283 : void ImpEditEngine::CheckIdleFormatter()
352 : : {
353 : 1283 : aIdleFormatter.ForceTimeout();
354 : : // If not idle, but still not formatted:
355 [ + + ]: 1283 : if ( !IsFormatted() )
356 : 46 : FormatDoc();
357 : 1283 : }
358 : :
359 : 174236 : void ImpEditEngine::FormatFullDoc()
360 : : {
361 [ + + ]: 348526 : for ( sal_uInt16 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
362 : 174290 : GetParaPortions()[nPortion]->MarkSelectionInvalid( 0, GetParaPortions()[nPortion]->GetNode()->Len() );
363 : 174236 : FormatDoc();
364 : 174236 : }
365 : :
366 : 1251241 : void ImpEditEngine::FormatDoc()
367 : : {
368 [ + + ][ + + ]: 1251241 : if ( !GetUpdateMode() || IsFormatting() )
[ + + ]
369 : 1251241 : return;
370 : :
371 [ + - ]: 332033 : EnterBlockNotifications();
372 : :
373 : 332033 : bIsFormatting = true;
374 : :
375 : : // Then I can also start the spell-timer ...
376 [ + + ]: 332033 : if ( GetStatus().DoOnlineSpelling() )
377 [ + - ]: 25043 : StartOnlineSpellTimer();
378 : :
379 : 332033 : long nY = 0;
380 : 332033 : sal_Bool bGrow = sal_False;
381 : :
382 [ + - ]: 332033 : Font aOldFont( GetRefDevice()->GetFont() );
383 : :
384 : : // Here already, so that not always in CreateLines...
385 [ + - ]: 332033 : sal_Bool bMapChanged = ImpCheckRefMapMode();
386 : :
387 [ + - ]: 332033 : aInvalidRec = Rectangle(); // make empty
388 [ + - ][ + + ]: 674413 : for ( sal_uInt16 nPara = 0; nPara < GetParaPortions().Count(); nPara++ )
389 : : {
390 [ + - ]: 342380 : ParaPortion* pParaPortion = GetParaPortions()[nPara];
391 [ + - ][ + + ]: 342380 : if ( pParaPortion->MustRepaint() || ( pParaPortion->IsInvalid() && pParaPortion->IsVisible() ) )
[ + - ][ + + ]
392 : : {
393 [ + - ]: 323744 : if ( pParaPortion->IsInvalid() )
394 : : {
395 [ + - ]: 323744 : sal_Bool bChangedByDerivedClass = GetEditEnginePtr()->FormattingParagraph( nPara );
396 [ - + ]: 323744 : if ( bChangedByDerivedClass )
397 : : {
398 [ # # ]: 0 : pParaPortion->GetTextPortions().Reset();
399 [ # # ][ # # ]: 0 : pParaPortion->MarkSelectionInvalid( 0, pParaPortion->GetNode()->Len() );
400 : : }
401 : : }
402 : : // No formatting should be necessary for MustRepaint()!
403 [ - + ][ # # ]: 647488 : if ( ( pParaPortion->MustRepaint() && !pParaPortion->IsInvalid() )
[ + + ][ + + ]
404 [ + - ]: 323744 : || CreateLines( nPara, nY ) )
405 : : {
406 [ + + ][ - + ]: 249795 : if ( !bGrow && GetTextRanger() )
[ - + ]
407 : : {
408 : : // For a change in height all below must be reformatted ...
409 [ # # ][ # # ]: 0 : for ( sal_uInt16 n = nPara+1; n < GetParaPortions().Count(); n++ )
410 : : {
411 [ # # ]: 0 : ParaPortion* pPP = GetParaPortions()[n];
412 [ # # ][ # # ]: 0 : pPP->MarkSelectionInvalid( 0, pPP->GetNode()->Len() );
413 [ # # ]: 0 : pPP->GetLines().Reset();
414 : : }
415 : : }
416 : 249795 : bGrow = sal_True;
417 [ + - ]: 249795 : if ( IsCallParaInsertedOrDeleted() )
418 [ + - ]: 249795 : GetEditEnginePtr()->ParagraphHeightChanged( nPara );
419 : 249795 : pParaPortion->SetMustRepaint( sal_False );
420 : : }
421 : :
422 : : // InvalidRec set only once...
423 [ + - ][ + + ]: 323744 : if ( aInvalidRec.IsEmpty() )
424 : : {
425 : : // For Paperwidth 0 (AutoPageSize) it would otherwise be Empty()...
426 [ + - ]: 314936 : long nWidth = Max( (long)1, ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) );
427 [ + - ]: 314936 : Range aInvRange( GetInvalidYOffsets( pParaPortion ) );
428 : 314936 : aInvalidRec = Rectangle( Point( 0, nY+aInvRange.Min() ),
429 [ + - ]: 629872 : Size( nWidth, aInvRange.Len() ) );
430 : : }
431 : : else
432 : : {
433 : 8808 : aInvalidRec.Bottom() = nY + pParaPortion->GetHeight();
434 : : }
435 : : }
436 [ + + ]: 18636 : else if ( bGrow )
437 : : {
438 : 74 : aInvalidRec.Bottom() = nY + pParaPortion->GetHeight();
439 : : }
440 : 342380 : nY += pParaPortion->GetHeight();
441 : : }
442 : :
443 : : // One can also get into the formatting through UpdateMode ON=>OFF=>ON...
444 : : // enable optimization first after Vobis delivery ...
445 : : {
446 : : sal_uInt32 nNewHeightNTP;
447 [ + - ]: 332033 : sal_uInt32 nNewHeight = CalcTextHeight( &nNewHeightNTP );
448 : 332033 : long nDiff = nNewHeight - nCurTextHeight;
449 [ + + ]: 332033 : if ( nDiff )
450 [ + - ]: 239154 : aStatus.GetStatusWord() |= !IsVertical() ? EE_STAT_TEXTHEIGHTCHANGED : EE_STAT_TEXTWIDTHCHANGED;
451 [ + + ]: 332033 : if ( nNewHeight < nCurTextHeight )
452 : : {
453 : 263 : aInvalidRec.Bottom() = (long)Max( nNewHeight, nCurTextHeight );
454 [ - + ][ + - ]: 263 : if ( aInvalidRec.IsEmpty() )
455 : : {
456 : 0 : aInvalidRec.Top() = 0;
457 : : // Left and Right are not evaluated, are however set due to IsEmpty.
458 : 0 : aInvalidRec.Left() = 0;
459 [ # # ]: 0 : aInvalidRec.Right() = !IsVertical() ? aPaperSize.Width() : aPaperSize.Height();
460 : : }
461 : : }
462 : :
463 : 332033 : nCurTextHeight = nNewHeight;
464 : 332033 : nCurTextHeightNTP = nNewHeightNTP;
465 : :
466 [ + + ]: 332033 : if ( aStatus.AutoPageSize() )
467 [ + - ]: 27392 : CheckAutoPageSize();
468 [ + + ]: 304641 : else if ( nDiff )
469 : : {
470 [ + + ]: 212277 : for (size_t nView = 0; nView < aEditViews.size(); ++nView)
471 : : {
472 : 80 : EditView* pView = aEditViews[nView];
473 : 80 : ImpEditView* pImpView = pView->pImpEditView;
474 [ - + ]: 80 : if ( pImpView->DoAutoHeight() )
475 : : {
476 [ # # ]: 0 : Size aSz( pImpView->GetOutputArea().GetWidth(), nCurTextHeight );
477 [ # # ]: 0 : if ( aSz.Height() > aMaxAutoPaperSize.Height() )
478 : 0 : aSz.Height() = aMaxAutoPaperSize.Height();
479 [ # # ]: 0 : else if ( aSz.Height() < aMinAutoPaperSize.Height() )
480 : 0 : aSz.Height() = aMinAutoPaperSize.Height();
481 : : pImpView->ResetOutputArea( Rectangle(
482 [ # # ][ # # ]: 0 : pImpView->GetOutputArea().TopLeft(), aSz ) );
483 : : }
484 : : }
485 : : }
486 : : }
487 : :
488 [ - + ]: 332033 : if ( aStatus.DoRestoreFont() )
489 [ # # ]: 0 : GetRefDevice()->SetFont( aOldFont );
490 : 332033 : bIsFormatting = false;
491 : 332033 : bFormatted = true;
492 : :
493 [ - + ]: 332033 : if ( bMapChanged )
494 [ # # ]: 0 : GetRefDevice()->Pop();
495 : :
496 [ + - ]: 332033 : CallStatusHdl(); // If Modified...
497 : :
498 [ + - ][ + - ]: 1251241 : LeaveBlockNotifications();
499 : : }
500 : :
501 : 446376 : sal_Bool ImpEditEngine::ImpCheckRefMapMode()
502 : : {
503 : 446376 : sal_Bool bChange = sal_False;
504 : :
505 [ + + ]: 446376 : if ( aStatus.DoFormat100() )
506 : : {
507 [ + - ]: 441330 : MapMode aMapMode( GetRefDevice()->GetMapMode() );
508 [ - + ]: 441330 : if ( aMapMode.GetScaleX().GetNumerator() != aMapMode.GetScaleX().GetDenominator() )
509 : 0 : bChange = sal_True;
510 [ - + ]: 441330 : else if ( aMapMode.GetScaleY().GetNumerator() != aMapMode.GetScaleY().GetDenominator() )
511 : 0 : bChange = sal_True;
512 : :
513 [ - + ]: 441330 : if ( bChange )
514 : : {
515 [ # # ]: 0 : Fraction Scale1( 1, 1 );
516 [ # # ]: 0 : aMapMode.SetScaleX( Scale1 );
517 [ # # ]: 0 : aMapMode.SetScaleY( Scale1 );
518 [ # # ]: 0 : GetRefDevice()->Push();
519 [ # # ]: 0 : GetRefDevice()->SetMapMode( aMapMode );
520 [ + - ]: 441330 : }
521 : : }
522 : :
523 : 446376 : return bChange;
524 : : }
525 : :
526 : 27392 : void ImpEditEngine::CheckAutoPageSize()
527 : : {
528 : 27392 : Size aPrevPaperSize( GetPaperSize() );
529 [ + - ]: 27392 : if ( GetStatus().AutoPageWidth() )
530 [ + - ][ + - ]: 27392 : aPaperSize.Width() = (long) !IsVertical() ? CalcTextWidth( sal_True ) : GetTextHeight();
[ # # ]
531 [ + - ]: 27392 : if ( GetStatus().AutoPageHeight() )
532 [ + - ][ + - ]: 27392 : aPaperSize.Height() = (long) !IsVertical() ? GetTextHeight() : CalcTextWidth( sal_True );
[ # # ]
533 : :
534 [ + - ]: 27392 : SetValidPaperSize( aPaperSize ); // consider Min, Max
535 : :
536 [ + + ]: 27392 : if ( aPaperSize != aPrevPaperSize )
537 : : {
538 [ + - ][ + + : 31921 : if ( ( !IsVertical() && ( aPaperSize.Width() != aPrevPaperSize.Width() ) )
- + # # ]
[ + + ]
539 : 4562 : || ( IsVertical() && ( aPaperSize.Height() != aPrevPaperSize.Height() ) ) )
540 : : {
541 : : // If ahead is centered / right or tabs ...
542 [ + - ]: 22797 : aStatus.GetStatusWord() |= !IsVertical() ? EE_STAT_TEXTWIDTHCHANGED : EE_STAT_TEXTHEIGHTCHANGED;
543 [ + - ][ + + ]: 45791 : for ( sal_uInt16 nPara = 0; nPara < GetParaPortions().Count(); nPara++ )
544 : : {
545 : : // Only paragraphs which are not aligned to the left need to be
546 : : // reformatted, the height can not be changed here anymore.
547 [ + - ]: 22994 : ParaPortion* pParaPortion = GetParaPortions()[nPara];
548 : 22994 : ContentNode* pNode = pParaPortion->GetNode();
549 [ + - ]: 22994 : SvxAdjust eJustification = GetJustification( nPara );
550 [ + + ]: 22994 : if ( eJustification != SVX_ADJUST_LEFT )
551 : : {
552 [ + - ][ + - ]: 837 : pParaPortion->MarkSelectionInvalid( 0, pNode->Len() );
553 [ + - ]: 837 : CreateLines( nPara, 0 ); // 0: For AutoPageSize no TextRange!
554 : : }
555 : : }
556 : : }
557 : :
558 : 27359 : Size aInvSize = aPaperSize;
559 [ - + ]: 27359 : if ( aPaperSize.Width() < aPrevPaperSize.Width() )
560 : 0 : aInvSize.Width() = aPrevPaperSize.Width();
561 [ + + ]: 27359 : if ( aPaperSize.Height() < aPrevPaperSize.Height() )
562 : 11066 : aInvSize.Height() = aPrevPaperSize.Height();
563 : :
564 : 27359 : Size aSz( aInvSize );
565 [ - + ]: 27359 : if ( IsVertical() )
566 : : {
567 : 0 : aSz.Width() = aInvSize.Height();
568 : 0 : aSz.Height() = aInvSize.Width();
569 : : }
570 [ + - ]: 27359 : aInvalidRec = Rectangle( Point(), aSz );
571 : :
572 : :
573 [ - + ]: 27359 : for (size_t nView = 0; nView < aEditViews.size(); ++nView)
574 : : {
575 : 0 : EditView* pView = aEditViews[nView];
576 [ # # ]: 0 : pView->pImpEditView->RecalcOutputArea();
577 : : }
578 : : }
579 : 27392 : }
580 : :
581 : 2139 : static sal_Int32 ImplCalculateFontIndependentLineSpacing( const sal_Int32 nFontHeight )
582 : : {
583 : 2139 : return ( nFontHeight * 12 ) / 10; // + 20%
584 : : }
585 : :
586 : 324581 : sal_Bool ImpEditEngine::CreateLines( sal_uInt16 nPara, sal_uInt32 nStartPosY )
587 : : {
588 [ + - ]: 324581 : ParaPortion* pParaPortion = GetParaPortions()[nPara];
589 : :
590 : : // sal_Bool: Changes in the height of paragraph Yes / No - sal_True/sal_False
591 : : DBG_ASSERT( pParaPortion->GetNode(), "Portion without Node in CreateLines" );
592 : : DBG_ASSERT( pParaPortion->IsVisible(), "Invisible paragraphs not formatted!" );
593 : : DBG_ASSERT( pParaPortion->IsInvalid(), "CreateLines: Portion not invalid!" );
594 : :
595 [ + - ]: 324581 : sal_Bool bProcessingEmptyLine = ( pParaPortion->GetNode()->Len() == 0 );
596 [ + - ][ + + ]: 324581 : sal_Bool bEmptyNodeWithPolygon = ( pParaPortion->GetNode()->Len() == 0 ) && GetTextRanger();
[ - + ]
597 : :
598 : : // ---------------------------------------------------------------
599 : : // Fast special treatment for empty paragraphs ...
600 : : // ---------------------------------------------------------------
601 [ + - ][ + + ]: 324581 : if ( ( pParaPortion->GetNode()->Len() == 0 ) && !GetTextRanger() )
[ + - ][ + + ]
602 : : {
603 : : // fast special treatment ...
604 [ + - ][ + + ]: 210238 : if ( pParaPortion->GetTextPortions().Count() )
605 [ + - ]: 72036 : pParaPortion->GetTextPortions().Reset();
606 [ + - ][ + + ]: 210238 : if ( pParaPortion->GetLines().Count() )
607 [ + - ]: 72036 : pParaPortion->GetLines().Reset();
608 [ + - ]: 210238 : CreateAndInsertEmptyLine( pParaPortion, nStartPosY );
609 [ + - ]: 210238 : return FinishCreateLines( pParaPortion );
610 : : }
611 : :
612 : : // ---------------------------------------------------------------
613 : : // Initialization ......
614 : : // ---------------------------------------------------------------
615 : :
616 : : // Always format for 100%:
617 [ + - ]: 114343 : sal_Bool bMapChanged = ImpCheckRefMapMode();
618 : :
619 [ + - ][ + + ]: 114343 : if ( pParaPortion->GetLines().Count() == 0 )
620 : : {
621 [ + - ][ + - ]: 110559 : EditLine* pL = new EditLine;
622 [ + - ]: 110559 : pParaPortion->GetLines().Append(pL);
623 : : }
624 : :
625 : : // ---------------------------------------------------------------
626 : : // Get Paragraph attributes ......
627 : : // ---------------------------------------------------------------
628 : 114343 : ContentNode* const pNode = pParaPortion->GetNode();
629 : :
630 [ + - ]: 114343 : sal_Bool bRightToLeftPara = IsRightToLeft( nPara );
631 : :
632 [ + - ]: 114343 : SvxAdjust eJustification = GetJustification( nPara );
633 [ + - ]: 114343 : sal_Bool bHyphenatePara = ((const SfxBoolItem&)pNode->GetContentAttribs().GetItem( EE_PARA_HYPHENATE )).GetValue();
634 : 114343 : sal_Int32 nSpaceBefore = 0;
635 : 114343 : sal_Int32 nMinLabelWidth = 0;
636 [ + - ]: 114343 : sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pNode, &nSpaceBefore, &nMinLabelWidth );
637 [ + - ]: 114343 : const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pNode );
638 [ + - ]: 114343 : const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&) pNode->GetContentAttribs().GetItem( EE_PARA_SBL );
639 [ + - ]: 114343 : const sal_Bool bScriptSpace = ((const SvxScriptSpaceItem&) pNode->GetContentAttribs().GetItem( EE_PARA_ASIANCJKSPACING )).GetValue();
640 : :
641 : 114343 : const short nInvalidDiff = pParaPortion->GetInvalidDiff();
642 : 114343 : const sal_uInt16 nInvalidStart = pParaPortion->GetInvalidPosStart();
643 : 114343 : const sal_uInt16 nInvalidEnd = nInvalidStart + Abs( nInvalidDiff );
644 : :
645 : 114343 : sal_Bool bQuickFormat = sal_False;
646 [ + - ][ + - ]: 114343 : if ( !bEmptyNodeWithPolygon && !HasScriptType( nPara, i18n::ScriptType::COMPLEX ) )
[ + - ][ + - ]
647 : : {
648 [ + + ][ + + ]: 114399 : if ( ( pParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff > 0 ) &&
[ + - ][ + + ]
649 [ + - ][ + - ]: 56 : ( pNode->GetString().Search( CH_FEATURE, nInvalidStart ) > nInvalidEnd ) )
650 : : {
651 : 56 : bQuickFormat = sal_True;
652 : : }
653 [ + + ][ - + ]: 114287 : else if ( ( pParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff < 0 ) )
[ - + ]
654 : : {
655 : : // check if delete over the portion boundaries was done ...
656 : 0 : sal_uInt16 nStart = nInvalidStart; // DOUBLE !!!!!!!!!!!!!!!
657 : 0 : sal_uInt16 nEnd = nStart - nInvalidDiff; // negative
658 : 0 : bQuickFormat = sal_True;
659 : 0 : sal_uInt16 nPos = 0;
660 [ # # ]: 0 : sal_uInt16 nPortions = pParaPortion->GetTextPortions().Count();
661 [ # # ]: 0 : for ( sal_uInt16 nTP = 0; nTP < nPortions; nTP++ )
662 : : {
663 : : // There must be no start / end in the deleted area.
664 [ # # ]: 0 : TextPortion* const pTP = pParaPortion->GetTextPortions()[ nTP ];
665 : 0 : nPos = nPos + pTP->GetLen();
666 [ # # ][ # # ]: 0 : if ( ( nPos > nStart ) && ( nPos < nEnd ) )
667 : : {
668 : 0 : bQuickFormat = sal_False;
669 : 0 : break;
670 : : }
671 : : }
672 : : }
673 : : }
674 : :
675 : : // SW disables TEXT_LAYOUT_COMPLEX_DISABLED, so maybe I have to enable it...
676 : :
677 : : // Saving both layout mode and language (since I'm potentially changing both)
678 [ + - ]: 114343 : GetRefDevice()->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE );
679 : :
680 [ + - ]: 114343 : ImplInitLayoutMode( GetRefDevice(), nPara, 0xFFFF );
681 : :
682 : 114343 : sal_uInt16 nRealInvalidStart = nInvalidStart;
683 : :
684 [ - + ]: 114343 : if ( bEmptyNodeWithPolygon )
685 : : {
686 [ # # ]: 0 : TextPortion* pDummyPortion = new TextPortion( 0 );
687 [ # # ]: 0 : pParaPortion->GetTextPortions().Reset();
688 [ # # ]: 0 : pParaPortion->GetTextPortions().Append(pDummyPortion);
689 : : }
690 [ + + ]: 114343 : else if ( bQuickFormat )
691 : : {
692 : : // faster Method:
693 [ + - ]: 56 : RecalcTextPortion( pParaPortion, nInvalidStart, nInvalidDiff );
694 : : }
695 : : else // nRealInvalidStart can be before InvalidStart, since Portions were deleted....
696 : : {
697 [ + - ]: 114287 : CreateTextPortions( pParaPortion, nRealInvalidStart );
698 : : }
699 : :
700 : :
701 : : // ---------------------------------------------------------------
702 : : // Search for line with InvalidPos, start one line before
703 : : // Flag the line => do not remove it !
704 : : // ---------------------------------------------------------------
705 : :
706 [ + - ]: 114343 : sal_uInt16 nLine = pParaPortion->GetLines().Count()-1;
707 [ + + ]: 225507 : for ( sal_uInt16 nL = 0; nL <= nLine; nL++ )
708 : : {
709 [ + - ]: 114343 : EditLine* pLine = pParaPortion->GetLines()[nL];
710 [ + + ]: 114343 : if ( pLine->GetEnd() > nRealInvalidStart ) // not nInvalidStart!
711 : : {
712 : 3179 : nLine = nL;
713 : 3179 : break;
714 : : }
715 : 111164 : pLine->SetValid();
716 : : }
717 : : // Begin one line before...
718 : : // If it is typed at the end, the line in front cannot change.
719 [ - + ][ # # ]: 114343 : if ( nLine && ( !pParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->Len() ) || ( nInvalidDiff <= 0 ) ) )
[ # # ][ # # ]
[ # # ][ - + ]
720 : 0 : nLine--;
721 : :
722 [ + - ]: 114343 : EditLine* pLine = pParaPortion->GetLines()[nLine];
723 : :
724 [ + + ][ + - ]: 114343 : static Rectangle aZeroArea = Rectangle( Point(), Point() );
[ + - ][ # # ]
725 : 114343 : Rectangle aBulletArea( aZeroArea );
726 [ + - ]: 114343 : if ( !nLine )
727 : : {
728 [ + - ][ + - ]: 114343 : aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion ) );
729 [ + + ]: 114343 : if ( aBulletArea.Right() > 0 )
730 : 2008 : pParaPortion->SetBulletX( (sal_uInt16) GetXValue( aBulletArea.Right() ) );
731 : : else
732 : 112335 : pParaPortion->SetBulletX( 0 ); // if Bullet is set incorrectly
733 : : }
734 : :
735 : : // ---------------------------------------------------------------
736 : : // Reformat all lines from here ...
737 : : // ---------------------------------------------------------------
738 : 114343 : sal_uInt16 nDelFromLine = 0xFFFF;
739 : 114343 : sal_Bool bLineBreak = sal_False;
740 : :
741 : 114343 : sal_uInt16 nIndex = pLine->GetStart();
742 [ + - ]: 114343 : EditLine aSaveLine( *pLine );
743 [ + - ]: 114343 : SvxFont aTmpFont( pNode->GetCharAttribs().GetDefFont() );
744 : :
745 : 114343 : sal_Bool bCalcCharPositions = sal_True;
746 [ + - ][ + - ]: 114343 : sal_Int32* pBuf = new sal_Int32[ pNode->Len() ];
747 : :
748 : 114343 : sal_Bool bSameLineAgain = sal_False; // For TextRanger, if the height changes.
749 [ + - ]: 114343 : TabInfo aCurrentTab;
750 : :
751 : 114343 : sal_Bool bForceOneRun = bEmptyNodeWithPolygon;
752 : 114343 : sal_Bool bCompressedChars = sal_False;
753 : :
754 [ + - ][ + + ]: 322895 : while ( ( nIndex < pNode->Len() ) || bForceOneRun )
[ - + ][ + + ]
755 : : {
756 : 208554 : bForceOneRun = sal_False;
757 : :
758 : 208554 : sal_Bool bEOL = sal_False;
759 : 208554 : sal_Bool bEOC = sal_False;
760 : 208554 : sal_uInt16 nPortionStart = 0;
761 : 208554 : sal_uInt16 nPortionEnd = 0;
762 : :
763 : 208554 : long nStartX = GetXValue( rLRItem.GetTxtLeft() + nSpaceBeforeAndMinLabelWidth );
764 [ + + ]: 208554 : if ( nIndex == 0 )
765 : : {
766 : 114343 : long nFI = GetXValue( rLRItem.GetTxtFirstLineOfst() );
767 : 114343 : nStartX += nFI;
768 : :
769 [ + + ][ + + ]: 114343 : if ( !nLine && ( pParaPortion->GetBulletX() > nStartX ) )
[ + - ]
770 : : {
771 : 175 : nStartX = pParaPortion->GetBulletX();
772 : : }
773 : : }
774 : :
775 : : long nMaxLineWidth;
776 [ + - ]: 208554 : if ( !IsVertical() )
777 [ + + ]: 208554 : nMaxLineWidth = aStatus.AutoPageWidth() ? aMaxAutoPaperSize.Width() : aPaperSize.Width();
778 : : else
779 [ # # ]: 0 : nMaxLineWidth = aStatus.AutoPageHeight() ? aMaxAutoPaperSize.Height() : aPaperSize.Height();
780 : :
781 : 208554 : nMaxLineWidth -= GetXValue( rLRItem.GetRight() );
782 : 208554 : nMaxLineWidth -= nStartX;
783 : :
784 : : // If PaperSize == long_max, one cannot take away any negative
785 : : // first line indent. (Overflow)
786 [ # # ][ - + ]: 208554 : if ( ( nMaxLineWidth < 0 ) && ( nStartX < 0 ) )
787 [ # # ]: 0 : nMaxLineWidth = ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) - GetXValue( rLRItem.GetRight() );
788 : :
789 : : // If still less than 0, it may be just the right edge.
790 [ - + ]: 208554 : if ( nMaxLineWidth <= 0 )
791 : 0 : nMaxLineWidth = 1;
792 : :
793 : : // Problem:
794 : : // Since formatting starts a line _before_ the invalid position,
795 : : // the positions unfortunately have to be redefined ...
796 : : // Solution:
797 : : // The line before can only become longer, not smaller
798 : : // => ...
799 [ + - ]: 208554 : if ( bCalcCharPositions )
800 [ + - ]: 208554 : pLine->GetCharPosArray().clear();
801 : :
802 : 208554 : sal_uInt16 nTmpPos = nIndex;
803 : 208554 : sal_uInt16 nTmpPortion = pLine->GetStartPortion();
804 : 208554 : long nTmpWidth = 0;
805 : 208554 : long nXWidth = nMaxLineWidth;
806 [ - + ]: 208554 : if ( nXWidth <= nTmpWidth ) // while has to be looped once
807 : 0 : nXWidth = nTmpWidth+1;
808 : :
809 : 208554 : LongDqPtr pTextRanges = 0;
810 : 208554 : long nTextExtraYOffset = 0;
811 : 208554 : long nTextXOffset = 0;
812 : 208554 : long nTextLineHeight = 0;
813 [ - + ]: 208554 : if ( GetTextRanger() )
814 : : {
815 [ # # ]: 0 : GetTextRanger()->SetVertical( IsVertical() );
816 : :
817 [ # # ]: 0 : long nTextY = nStartPosY + GetEditCursor( pParaPortion, pLine->GetStart() ).Top();
818 [ # # ]: 0 : if ( !bSameLineAgain )
819 : : {
820 [ # # ]: 0 : SeekCursor( pNode, nTmpPos+1, aTmpFont );
821 [ # # ]: 0 : aTmpFont.SetPhysFont( GetRefDevice() );
822 [ # # ]: 0 : ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() );
823 : :
824 [ # # ]: 0 : if ( IsFixedCellHeight() )
825 [ # # ]: 0 : nTextLineHeight = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() );
826 : : else
827 [ # # ][ # # ]: 0 : nTextLineHeight = aTmpFont.GetPhysTxtSize( GetRefDevice(), String() ).Height();
[ # # ]
828 : : // Metrics can be greater
829 : 0 : FormatterFontMetric aTempFormatterMetrics;
830 [ # # ]: 0 : RecalcFormatterFontMetrics( aTempFormatterMetrics, aTmpFont );
831 : 0 : sal_uInt16 nLineHeight = aTempFormatterMetrics.GetHeight();
832 [ # # ]: 0 : if ( nLineHeight > nTextLineHeight )
833 : 0 : nTextLineHeight = nLineHeight;
834 : : }
835 : : else
836 : 0 : nTextLineHeight = pLine->GetHeight();
837 : :
838 : 0 : nXWidth = 0;
839 [ # # ]: 0 : while ( !nXWidth )
840 : : {
841 : 0 : long nYOff = nTextY + nTextExtraYOffset;
842 : 0 : long nYDiff = nTextLineHeight;
843 [ # # ]: 0 : if ( IsVertical() )
844 : : {
845 [ # # ]: 0 : long nMaxPolygonX = GetTextRanger()->GetBoundRect().Right();
846 : 0 : nYOff = nMaxPolygonX-nYOff;
847 : 0 : nYDiff = -nTextLineHeight;
848 : : }
849 [ # # ]: 0 : pTextRanges = GetTextRanger()->GetTextRanges( Range( nYOff, nYOff + nYDiff ) );
850 : : DBG_ASSERT( pTextRanges, "GetTextRanges?!" );
851 : 0 : long nMaxRangeWidth = 0;
852 : : // Use the widest range ...
853 : : // The widest range could be a bit confusing, so normally it
854 : : // is the first one. Best with gaps.
855 [ # # ]: 0 : if ( pTextRanges->size() )
856 : : {
857 : 0 : sal_uInt16 n = 0;
858 [ # # ]: 0 : long nA = pTextRanges->at(n++);
859 [ # # ]: 0 : long nB = pTextRanges->at(n++);
860 : : DBG_ASSERT( nA <= nB, "TextRange distorted?" );
861 : 0 : long nW = nB - nA;
862 [ # # ]: 0 : if ( nW > nMaxRangeWidth )
863 : : {
864 : 0 : nMaxRangeWidth = nW;
865 : 0 : nTextXOffset = nA;
866 : : }
867 : : }
868 : 0 : nXWidth = nMaxRangeWidth;
869 [ # # ]: 0 : if ( nXWidth )
870 : 0 : nMaxLineWidth = nXWidth - nStartX - GetXValue( rLRItem.GetRight() );
871 : : else
872 : : {
873 : : // Try further down in the polygon.
874 : : // Below the polygon use the Paper Width.
875 : 0 : nTextExtraYOffset += Max( (long)(nTextLineHeight / 10), (long)1 );
876 [ # # ][ # # ]: 0 : if ( ( nTextY + nTextExtraYOffset ) > GetTextRanger()->GetBoundRect().Bottom() )
877 : : {
878 [ # # ]: 0 : nXWidth = !IsVertical() ? GetPaperSize().Width() : GetPaperSize().Height();
879 [ # # ]: 0 : if ( !nXWidth ) // AutoPaperSize
880 : 0 : nXWidth = 0x7FFFFFFF;
881 : : }
882 : : }
883 : : }
884 : : }
885 : :
886 : : // search for Portion that no longer fits in line ....
887 : 208554 : TextPortion* pPortion = 0;
888 : 208554 : sal_Bool bBrokenLine = sal_False;
889 : 208554 : bLineBreak = sal_False;
890 [ + - ]: 208554 : const EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( pLine->GetStart() );
891 [ + + ][ + + ]: 418793 : while ( ( nTmpWidth < nXWidth ) && !bEOL && ( nTmpPortion < pParaPortion->GetTextPortions().Count() ) )
[ + - ][ + + ]
[ + + ]
892 : : {
893 : 210239 : nPortionStart = nTmpPos;
894 [ + - ]: 210239 : pPortion = pParaPortion->GetTextPortions()[nTmpPortion];
895 [ - + ]: 210239 : if ( pPortion->GetKind() == PORTIONKIND_HYPHENATOR )
896 : : {
897 : : // Throw away a Portion, if necessary correct the one before,
898 : : // if the Hyph portion has swallowed a character ...
899 : 0 : sal_uInt16 nTmpLen = pPortion->GetLen();
900 [ # # ]: 0 : pParaPortion->GetTextPortions().Remove( nTmpPortion );
901 [ # # ][ # # ]: 0 : if (nTmpPortion && nTmpLen)
902 : : {
903 : 0 : nTmpPortion--;
904 [ # # ]: 0 : TextPortion* pPrev = pParaPortion->GetTextPortions()[nTmpPortion];
905 : : DBG_ASSERT( pPrev->GetKind() == PORTIONKIND_TEXT, "Portion?!" );
906 : 0 : nTmpWidth -= pPrev->GetSize().Width();
907 : 0 : nTmpPos = nTmpPos - pPrev->GetLen();
908 : 0 : pPrev->SetLen(pPrev->GetLen() + nTmpLen);
909 : 0 : pPrev->GetSize().Width() = (-1);
910 : : }
911 : :
912 : : DBG_ASSERT( nTmpPortion < pParaPortion->GetTextPortions().Count(), "No more Portions left!" );
913 [ # # ]: 0 : pPortion = pParaPortion->GetTextPortions()[nTmpPortion];
914 : : }
915 : : DBG_ASSERT( pPortion->GetKind() != PORTIONKIND_HYPHENATOR, "CreateLines: Hyphenator-Portion!" );
916 : : DBG_ASSERT( pPortion->GetLen() || bProcessingEmptyLine, "Empty Portion in CreateLines ?!" );
917 : : (void)bProcessingEmptyLine;
918 [ + + ][ + + ]: 210239 : if ( pNextFeature && ( pNextFeature->GetStart() == nTmpPos ) )
[ + + ]
919 : : {
920 : 3366 : sal_uInt16 nWhich = pNextFeature->GetItem()->Which();
921 [ - + + - ]: 3366 : switch ( nWhich )
922 : : {
923 : : case EE_FEATURE_TAB:
924 : : {
925 : 0 : long nOldTmpWidth = nTmpWidth;
926 : :
927 : : // Search for Tab-Pos...
928 : 0 : long nCurPos = nTmpWidth+nStartX;
929 : : // consider scaling
930 [ # # ][ # # ]: 0 : if ( aStatus.DoStretch() && ( nStretchX != 100 ) )
[ # # ]
931 [ # # ]: 0 : nCurPos = nCurPos*100/std::max(static_cast<sal_Int32>(nStretchX), static_cast<sal_Int32>(1));
932 : :
933 : 0 : short nAllSpaceBeforeText = static_cast< short >(rLRItem.GetTxtLeft()/* + rLRItem.GetTxtLeft()*/ + nSpaceBeforeAndMinLabelWidth);
934 [ # # ]: 0 : aCurrentTab.aTabStop = pNode->GetContentAttribs().FindTabStop( nCurPos - nAllSpaceBeforeText /*rLRItem.GetTxtLeft()*/, aEditDoc.GetDefTab() );
935 : 0 : aCurrentTab.nTabPos = GetXValue( (long) ( aCurrentTab.aTabStop.GetTabPos() + nAllSpaceBeforeText /*rLRItem.GetTxtLeft()*/ ) );
936 : 0 : aCurrentTab.bValid = sal_False;
937 : :
938 : : // Switch direction in R2L para...
939 [ # # ]: 0 : if ( bRightToLeftPara )
940 : : {
941 [ # # ]: 0 : if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_RIGHT )
942 : 0 : aCurrentTab.aTabStop.GetAdjustment() = SVX_TAB_ADJUST_LEFT;
943 [ # # ]: 0 : else if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_LEFT )
944 : 0 : aCurrentTab.aTabStop.GetAdjustment() = SVX_TAB_ADJUST_RIGHT;
945 : : }
946 : :
947 [ # # # # : 0 : if ( ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_RIGHT ) ||
# # ][ # # ]
948 : 0 : ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_CENTER ) ||
949 : 0 : ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_DECIMAL ) )
950 : : {
951 : : // For LEFT / DEFAULT this tab is not considered.
952 : 0 : aCurrentTab.bValid = sal_True;
953 : 0 : aCurrentTab.nStartPosX = nTmpWidth;
954 : 0 : aCurrentTab.nCharPos = nTmpPos;
955 : 0 : aCurrentTab.nTabPortion = nTmpPortion;
956 : : }
957 : :
958 : 0 : pPortion->GetKind() = PORTIONKIND_TAB;
959 : 0 : pPortion->SetExtraValue( aCurrentTab.aTabStop.GetFill() );
960 : 0 : pPortion->GetSize().Width() = aCurrentTab.nTabPos - (nTmpWidth+nStartX);
961 : :
962 : : // Height needed...
963 [ # # ]: 0 : SeekCursor( pNode, nTmpPos+1, aTmpFont );
964 [ # # ][ # # ]: 0 : pPortion->GetSize().Height() = aTmpFont.QuickGetTextSize( GetRefDevice(), String(), 0, 0, NULL ).Height();
[ # # ]
965 : :
966 : : DBG_ASSERT( pPortion->GetSize().Width() >= 0, "Tab incorrectly calculated!" );
967 : :
968 : 0 : nTmpWidth = aCurrentTab.nTabPos-nStartX;
969 : :
970 : : // If this is the first token on the line,
971 : : // and nTmpWidth > aPaperSize.Width, => infinite loop!
972 [ # # ][ # # ]: 0 : if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) )
[ # # ]
973 : : {
974 : : // What now?
975 : : // make the tab fitting
976 : 0 : pPortion->GetSize().Width() = nXWidth-nOldTmpWidth;
977 : 0 : nTmpWidth = nXWidth-1;
978 : 0 : bEOL = sal_True;
979 : 0 : bBrokenLine = sal_True;
980 : : }
981 [ # # ]: 0 : EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
982 : 0 : size_t nPos = nTmpPos - pLine->GetStart();
983 [ # # ][ # # ]: 0 : rArray.insert(rArray.begin()+nPos, pPortion->GetSize().Width());
984 : 0 : bCompressedChars = sal_False;
985 : : }
986 : 0 : break;
987 : : case EE_FEATURE_LINEBR:
988 : : {
989 : : DBG_ASSERT( pPortion, "?!" );
990 : 31 : pPortion->GetSize().Width() = 0;
991 : 31 : bEOL = sal_True;
992 : 31 : bLineBreak = sal_True;
993 : 31 : pPortion->GetKind() = PORTIONKIND_LINEBREAK;
994 : 31 : bCompressedChars = sal_False;
995 [ + - ]: 31 : EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
996 : 31 : size_t nPos = nTmpPos - pLine->GetStart();
997 [ + - ][ + - ]: 31 : rArray.insert(rArray.begin()+nPos, pPortion->GetSize().Width());
998 : : }
999 : 31 : break;
1000 : : case EE_FEATURE_FIELD:
1001 : : {
1002 [ + - ]: 3335 : SeekCursor( pNode, nTmpPos+1, aTmpFont );
1003 : 3335 : sal_Unicode cChar = 0; // later: NBS?
1004 [ + - ]: 3335 : aTmpFont.SetPhysFont( GetRefDevice() );
1005 [ + - ]: 3335 : ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() );
1006 : :
1007 [ - + ][ + - ]: 3335 : rtl::OUString aFieldValue = cChar ? rtl::OUString(cChar) : ((EditCharAttribField*)pNextFeature)->GetFieldValue();
1008 [ - + ][ # # ]: 3335 : if ( bCalcCharPositions || !pPortion->HasValidSize() )
[ + - ]
1009 : : {
1010 [ + - ][ + - ]: 3335 : pPortion->GetSize() = aTmpFont.QuickGetTextSize( GetRefDevice(), aFieldValue, 0, aFieldValue.getLength(), 0 );
[ + - ]
1011 : : // So no scrolling for oversized fields
1012 [ - + ]: 3335 : if ( pPortion->GetSize().Width() > nXWidth )
1013 : : {
1014 : 0 : sal_Int32 nWidthOrg = pPortion->GetSize().Width();
1015 : 0 : sal_Int32 nChars = aFieldValue.getLength();
1016 : 0 : sal_Int32 nApproxWC = nXWidth / ( nWidthOrg / nChars );
1017 : 0 : ExtraPortionInfo *pExtraInfo= pPortion->GetExtraInfos();
1018 [ # # ]: 0 : if( !nApproxWC ) nApproxWC++;
1019 [ # # ]: 0 : if( pExtraInfo == NULL )
1020 : : {
1021 [ # # ][ # # ]: 0 : pExtraInfo = new ExtraPortionInfo();
1022 : 0 : pExtraInfo->nOrgWidth = nXWidth;
1023 [ # # ]: 0 : pPortion->SetExtraInfos( pExtraInfo );
1024 : : }
1025 : : else
1026 : : {
1027 : 0 : pExtraInfo->lineBreaksList.clear();
1028 : : }
1029 : :
1030 : 0 : pPortion->GetSize().Width() = nXWidth;
1031 : :
1032 [ # # ]: 0 : while( nChars > 0 )
1033 : : {
1034 [ # # ]: 0 : pExtraInfo->lineBreaksList.push_back( aFieldValue.getLength() - nChars );
1035 : 0 : nChars -= nApproxWC;
1036 : : }
1037 : : }
1038 : : }
1039 : 3335 : nTmpWidth += pPortion->GetSize().Width();
1040 [ + - ]: 3335 : EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
1041 : 3335 : size_t nPos = nTmpPos - pLine->GetStart();
1042 [ + - ][ + - ]: 3335 : rArray.insert(rArray.begin()+nPos, pPortion->GetSize().Width());
1043 [ - + ]: 3335 : pPortion->GetKind() = cChar ? PORTIONKIND_TEXT : PORTIONKIND_FIELD;
1044 : : // If this is the first token on the line,
1045 : : // and nTmpWidth > aPaperSize.Width, => infinite loop!
1046 [ + + ][ - + ]: 3335 : if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) )
[ - + ]
1047 : : {
1048 : 0 : nTmpWidth = nXWidth-1;
1049 : 0 : bEOL = sal_True;
1050 : 0 : bBrokenLine = sal_True;
1051 : : }
1052 : : // Compression in Fields????
1053 : : // I think this could be a little bit difficult and is not very usefull
1054 : 3335 : bCompressedChars = sal_False;
1055 : : }
1056 : 3335 : break;
1057 : : default: OSL_FAIL( "What feature?" );
1058 : : }
1059 [ + - ]: 3366 : pNextFeature = pNode->GetCharAttribs().FindFeature( pNextFeature->GetStart() + 1 );
1060 : : }
1061 : : else
1062 : : {
1063 : : DBG_ASSERT( pPortion->GetLen() || bProcessingEmptyLine, "Empty Portion - Extra Space?!" );
1064 : : (void)bProcessingEmptyLine;
1065 [ + - ]: 206873 : SeekCursor( pNode, nTmpPos+1, aTmpFont );
1066 [ + - ]: 206873 : aTmpFont.SetPhysFont( GetRefDevice() );
1067 [ + - ]: 206873 : ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() );
1068 : :
1069 [ - + ][ # # ]: 206873 : if ( bCalcCharPositions || !pPortion->HasValidSize() )
[ + - ]
1070 : : {
1071 [ + - ][ + - ]: 206873 : pPortion->GetSize() = aTmpFont.QuickGetTextSize( GetRefDevice(), pParaPortion->GetNode()->GetString(), nTmpPos, pPortion->GetLen(), pBuf );
1072 : :
1073 : : // #i9050# Do Kerning also behind portions...
1074 [ + + ][ + - ]: 206873 : if ( ( aTmpFont.GetFixKerning() > 0 ) && ( ( nTmpPos + pPortion->GetLen() ) < pNode->Len() ) )
[ - + ][ - + ]
1075 : 0 : pPortion->GetSize().Width() += aTmpFont.GetFixKerning();
1076 [ + + ]: 206873 : if ( IsFixedCellHeight() )
1077 [ + - ]: 351 : pPortion->GetSize().Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() );
1078 : : }
1079 [ + - ]: 206873 : if ( bCalcCharPositions )
1080 : : {
1081 : 206873 : sal_uInt16 nLen = pPortion->GetLen();
1082 : : // The array is generally flattened at the beginning
1083 : : // => Always simply quick inserts.
1084 : 206873 : size_t nPos = nTmpPos - pLine->GetStart();
1085 [ + - ]: 206873 : EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
1086 [ + - ][ + - ]: 206873 : rArray.insert(rArray.begin()+nPos, pBuf, pBuf+nLen);
1087 : : }
1088 : :
1089 : : // And now check for Compression:
1090 [ + - ][ - + ]: 206873 : if ( pPortion->GetLen() && GetAsianCompressionMode() )
[ - + ]
1091 : : {
1092 [ # # ]: 0 : EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
1093 [ # # ]: 0 : sal_Int32* pDXArray = &rArray[0] + nTmpPos - pLine->GetStart();
1094 : : bCompressedChars |= ImplCalcAsianCompression(
1095 [ # # ]: 0 : pNode, pPortion, nTmpPos, pDXArray, 10000, false);
1096 : : }
1097 : :
1098 : 206873 : nTmpWidth += pPortion->GetSize().Width();
1099 : :
1100 [ + - ]: 206873 : pPortion->SetRightToLeft( GetRightToLeft( nPara, nTmpPos+1 ) );
1101 : :
1102 : 206873 : sal_uInt16 _nPortionEnd = nTmpPos + pPortion->GetLen();
1103 [ + - ][ + + ]: 206873 : if( bScriptSpace && ( _nPortionEnd < pNode->Len() ) && ( nTmpWidth < nXWidth ) && IsScriptChange( EditPaM( pNode, _nPortionEnd ) ) )
[ + + ][ + - ]
[ + - ][ + + ]
[ + + ]
[ + + # # ]
[ + + ]
1104 : : {
1105 : 16 : sal_Bool bAllow = sal_False;
1106 [ + - ][ + - ]: 16 : sal_uInt16 nScriptTypeLeft = GetScriptType( EditPaM( pNode, _nPortionEnd ) );
1107 [ + - ][ + - ]: 16 : sal_uInt16 nScriptTypeRight = GetScriptType( EditPaM( pNode, _nPortionEnd+1 ) );
1108 [ + - ][ - + ]: 16 : if ( ( nScriptTypeLeft == i18n::ScriptType::ASIAN ) || ( nScriptTypeRight == i18n::ScriptType::ASIAN ) )
1109 : 0 : bAllow = sal_True;
1110 : :
1111 : : // No spacing within L2R/R2L nesting
1112 [ - + ]: 16 : if ( bAllow )
1113 : : {
1114 : 0 : long nExtraSpace = pPortion->GetSize().Height()/5;
1115 : 0 : nExtraSpace = GetXValue( nExtraSpace );
1116 : 0 : pPortion->GetSize().Width() += nExtraSpace;
1117 : 0 : nTmpWidth += nExtraSpace;
1118 : : }
1119 : : }
1120 : : }
1121 : :
1122 [ - + ][ # # ]: 210239 : if ( aCurrentTab.bValid && ( nTmpPortion != aCurrentTab.nTabPortion ) )
1123 : : {
1124 : 0 : long nWidthAfterTab = 0;
1125 [ # # ]: 0 : for ( sal_uInt16 n = aCurrentTab.nTabPortion+1; n <= nTmpPortion; n++ )
1126 : : {
1127 [ # # ]: 0 : const TextPortion* pTP = pParaPortion->GetTextPortions()[n];
1128 : 0 : nWidthAfterTab += pTP->GetSize().Width();
1129 : : }
1130 : 0 : long nW = nWidthAfterTab; // Length before tab position
1131 [ # # ]: 0 : if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_RIGHT )
1132 : : {
1133 : : }
1134 [ # # ]: 0 : else if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_CENTER )
1135 : : {
1136 : 0 : nW = nWidthAfterTab/2;
1137 : : }
1138 [ # # ]: 0 : else if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_DECIMAL )
1139 : : {
1140 : : String aText = GetSelected( EditSelection( EditPaM( pParaPortion->GetNode(), nTmpPos ),
1141 [ # # ][ # # ]: 0 : EditPaM( pParaPortion->GetNode(), nTmpPos + pPortion->GetLen() ) ) );
[ # # ][ # # ]
1142 [ # # ][ # # ]: 0 : sal_uInt16 nDecPos = aText.Search( aCurrentTab.aTabStop.GetDecimal() );
1143 [ # # ]: 0 : if ( nDecPos != STRING_NOTFOUND )
1144 : : {
1145 [ # # ]: 0 : nW -= pParaPortion->GetTextPortions()[nTmpPortion]->GetSize().Width();
1146 [ # # ][ # # ]: 0 : nW += aTmpFont.QuickGetTextSize( GetRefDevice(), pParaPortion->GetNode()->GetString(), nTmpPos, nDecPos, NULL ).Width();
1147 : 0 : aCurrentTab.bValid = sal_False;
1148 [ # # ]: 0 : }
1149 : : }
1150 : : else
1151 : : {
1152 : : OSL_FAIL( "CreateLines: Tab not handled!" );
1153 : : }
1154 : 0 : long nMaxW = aCurrentTab.nTabPos - aCurrentTab.nStartPosX - nStartX;
1155 [ # # ]: 0 : if ( nW >= nMaxW )
1156 : : {
1157 : 0 : nW = nMaxW;
1158 : 0 : aCurrentTab.bValid = sal_False;
1159 : : }
1160 [ # # ]: 0 : const TextPortion* pTabPortion = pParaPortion->GetTextPortions()[aCurrentTab.nTabPortion];
1161 : 0 : pTabPortion->GetSize().Width() = aCurrentTab.nTabPos - aCurrentTab.nStartPosX - nW - nStartX;
1162 : 0 : nTmpWidth = aCurrentTab.nStartPosX + pTabPortion->GetSize().Width() + nWidthAfterTab;
1163 : : }
1164 : :
1165 : 210239 : nTmpPos = nTmpPos + pPortion->GetLen();
1166 : 210239 : nPortionEnd = nTmpPos;
1167 : 210239 : nTmpPortion++;
1168 [ - + ]: 210239 : if ( aStatus.OneCharPerLine() )
1169 : 0 : bEOL = sal_True;
1170 : : }
1171 : :
1172 : : DBG_ASSERT( pPortion, "no portion!?" );
1173 : :
1174 : 208554 : aCurrentTab.bValid = sal_False;
1175 : :
1176 : : // this was possibly a portion too far:
1177 : 208554 : sal_Bool bFixedEnd = sal_False;
1178 [ - + ]: 208554 : if ( aStatus.OneCharPerLine() )
1179 : : {
1180 : : // State before Portion (apart from nTmpWidth):
1181 : 0 : nPortionEnd = nTmpPos;
1182 [ # # ]: 0 : nTmpPos -= pPortion ? pPortion->GetLen() : 0;
1183 : 0 : nPortionStart = nTmpPos;
1184 : 0 : nTmpPortion--;
1185 : :
1186 : 0 : bEOL = sal_True;
1187 : 0 : bEOC = sal_False;
1188 : :
1189 : : // And now just one character:
1190 : 0 : nTmpPos++;
1191 : 0 : nTmpPortion++;
1192 : 0 : nPortionEnd = nTmpPortion;
1193 : : // one Non-Feature-Portion has to be wrapped
1194 [ # # ]: 0 : if ( pPortion->GetLen() > 1 )
1195 : : {
1196 : : DBG_ASSERT( pPortion && (pPortion->GetKind() == PORTIONKIND_TEXT), "Len>1, but no TextPortion?" );
1197 [ # # ]: 0 : nTmpWidth -= pPortion ? pPortion->GetSize().Width() : 0;
1198 [ # # ]: 0 : sal_uInt16 nP = SplitTextPortion( pParaPortion, nTmpPos, pLine );
1199 [ # # ]: 0 : const TextPortion* p = pParaPortion->GetTextPortions()[nP];
1200 : : DBG_ASSERT( p, "Portion ?!" );
1201 : 0 : nTmpWidth += p->GetSize().Width();
1202 : : }
1203 : : }
1204 [ + + ]: 208554 : else if ( nTmpWidth >= nXWidth )
1205 : : {
1206 : 115873 : nPortionEnd = nTmpPos;
1207 [ + - ]: 115873 : nTmpPos -= pPortion ? pPortion->GetLen() : 0;
1208 : 115873 : nPortionStart = nTmpPos;
1209 : 115873 : nTmpPortion--;
1210 : 115873 : bEOL = sal_False;
1211 : 115873 : bEOC = sal_False;
1212 [ + - ]: 115873 : if( pPortion ) switch ( pPortion->GetKind() )
[ + + - ]
1213 : : {
1214 : : case PORTIONKIND_TEXT:
1215 : : {
1216 : 115869 : nTmpWidth -= pPortion->GetSize().Width();
1217 : : }
1218 : 115869 : break;
1219 : : case PORTIONKIND_FIELD:
1220 : : case PORTIONKIND_TAB:
1221 : : {
1222 : 4 : nTmpWidth -= pPortion->GetSize().Width();
1223 : 4 : bEOL = sal_True;
1224 : 4 : bFixedEnd = sal_True;
1225 : : }
1226 : 4 : break;
1227 : : default:
1228 : : {
1229 : : // A feature is not wrapped:
1230 : : DBG_ASSERT( ( pPortion->GetKind() == PORTIONKIND_LINEBREAK ), "What Feature ?" );
1231 : 0 : bEOL = sal_True;
1232 : 115873 : bFixedEnd = sal_True;
1233 : : }
1234 : : }
1235 : : }
1236 : : else
1237 : : {
1238 : 92681 : bEOL = sal_True;
1239 : 92681 : bEOC = sal_True;
1240 : 92681 : pLine->SetEnd( nPortionEnd );
1241 : : DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "No TextPortions?" );
1242 [ + - ]: 92681 : pLine->SetEndPortion( (sal_uInt16)pParaPortion->GetTextPortions().Count() - 1 );
1243 : : }
1244 : :
1245 [ - + ]: 208554 : if ( aStatus.OneCharPerLine() )
1246 : : {
1247 : 0 : pLine->SetEnd( nPortionEnd );
1248 : 0 : pLine->SetEndPortion( nTmpPortion-1 );
1249 : : }
1250 [ + + ]: 208554 : else if ( bFixedEnd )
1251 : : {
1252 : 4 : pLine->SetEnd( nPortionStart );
1253 : 4 : pLine->SetEndPortion( nTmpPortion-1 );
1254 : : }
1255 [ + + ][ - + ]: 208550 : else if ( bLineBreak || bBrokenLine )
1256 : : {
1257 : 31 : pLine->SetEnd( nPortionStart+1 );
1258 : 31 : pLine->SetEndPortion( nTmpPortion-1 );
1259 : 31 : bEOC = sal_False; // was set above, maybe change the sequence of the if's?
1260 : : }
1261 [ + + ]: 208519 : else if ( !bEOL )
1262 : : {
1263 : : DBG_ASSERT( pPortion && ((nPortionEnd-nPortionStart) == pPortion->GetLen()), "However, another portion?!" );
1264 : 115869 : long nRemainingWidth = nMaxLineWidth - nTmpWidth;
1265 [ + - ]: 115869 : sal_Bool bCanHyphenate = ( aTmpFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL );
1266 [ - + ][ # # ]: 115869 : if ( bCompressedChars && pPortion && ( pPortion->GetLen() > 1 ) && pPortion->GetExtraInfos() && pPortion->GetExtraInfos()->bCompressed )
[ # # ][ # # ]
[ # # ][ - + ]
1267 : : {
1268 : : // I need the manipulated DXArray for determining the break postion...
1269 : 0 : sal_Int32* pDXArray = NULL;
1270 [ # # ][ # # ]: 0 : if (!pLine->GetCharPosArray().empty())
1271 [ # # ][ # # ]: 0 : pDXArray = &pLine->GetCharPosArray()[0] + (nPortionStart - pLine->GetStart());
1272 : : ImplCalcAsianCompression(
1273 [ # # ]: 0 : pNode, pPortion, nPortionStart, pDXArray, 10000, true);
1274 : : }
1275 [ + - ]: 115869 : if( pPortion )
1276 : : ImpBreakLine( pParaPortion, pLine, pPortion, nPortionStart,
1277 [ + - ][ + + ]: 115869 : nRemainingWidth, bCanHyphenate && bHyphenatePara );
[ + - ]
1278 : : }
1279 : :
1280 : : // ------------------------------------------------------------------
1281 : : // Line finished => adjust
1282 : : // ------------------------------------------------------------------
1283 : :
1284 : : // CalcTextSize should be replaced by a continuous registering!
1285 [ + - ]: 208554 : Size aTextSize = pLine->CalcTextSize( *pParaPortion );
1286 : :
1287 [ + + ]: 208554 : if ( aTextSize.Height() == 0 )
1288 : : {
1289 [ + - ]: 17 : SeekCursor( pNode, pLine->GetStart()+1, aTmpFont );
1290 [ + - ]: 17 : aTmpFont.SetPhysFont( pRefDev );
1291 [ + - ]: 17 : ImplInitDigitMode( pRefDev, 0, 0, 0, aTmpFont.GetLanguage() );
1292 : :
1293 [ - + ]: 17 : if ( IsFixedCellHeight() )
1294 [ # # ]: 0 : aTextSize.Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() );
1295 : : else
1296 [ + - ][ + - ]: 17 : aTextSize.Height() = aTmpFont.GetPhysTxtSize( pRefDev, String() ).Height();
[ + - ]
1297 : 17 : pLine->SetHeight( (sal_uInt16)aTextSize.Height() );
1298 : : }
1299 : :
1300 : : // The font metrics can not be calculated continuously, if the font is
1301 : : // set anyway, because a large font only after wrapping suddenly ends
1302 : : // up in the next line => Font metrics too big.
1303 : 208554 : FormatterFontMetric aFormatterMetrics;
1304 : 208554 : sal_uInt16 nTPos = pLine->GetStart();
1305 [ + + ]: 419068 : for ( sal_uInt16 nP = pLine->GetStartPortion(); nP <= pLine->GetEndPortion(); nP++ )
1306 : : {
1307 [ + - ]: 210514 : const TextPortion* pTP = pParaPortion->GetTextPortions()[nP];
1308 : : // problem with hard font height attribute, when everthing but the line break has this attribute
1309 [ + + ]: 210514 : if ( pTP->GetKind() != PORTIONKIND_LINEBREAK )
1310 : : {
1311 [ + - ]: 210483 : SeekCursor( pNode, nTPos+1, aTmpFont );
1312 [ + - ]: 210483 : aTmpFont.SetPhysFont( GetRefDevice() );
1313 [ + - ]: 210483 : ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() );
1314 [ + - ]: 210483 : RecalcFormatterFontMetrics( aFormatterMetrics, aTmpFont );
1315 : : }
1316 : 210514 : nTPos = nTPos + pTP->GetLen();
1317 : : }
1318 : 208554 : sal_uInt16 nLineHeight = aFormatterMetrics.GetHeight();
1319 [ + + ]: 208554 : if ( nLineHeight > pLine->GetHeight() )
1320 : 6187 : pLine->SetHeight( nLineHeight );
1321 : 208554 : pLine->SetMaxAscent( aFormatterMetrics.nMaxAscent );
1322 : :
1323 : 208554 : bSameLineAgain = sal_False;
1324 [ # # ][ - + ]: 208554 : if ( GetTextRanger() && ( pLine->GetHeight() > nTextLineHeight ) )
[ - + ]
1325 : : {
1326 : : // put down with the other size!
1327 : 0 : bSameLineAgain = sal_True;
1328 : : }
1329 : :
1330 : :
1331 [ + - ][ + - ]: 208554 : if ( !bSameLineAgain && !aStatus.IsOutliner() )
[ + - ]
1332 : : {
1333 [ + + ]: 208554 : if ( rLSItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN )
1334 : : {
1335 : 2658 : sal_uInt16 nMinHeight = GetYValue( rLSItem.GetLineHeight() );
1336 : 2658 : sal_uInt16 nTxtHeight = pLine->GetHeight();
1337 [ - + ]: 2658 : if ( nTxtHeight < nMinHeight )
1338 : : {
1339 : : // The Ascent has to be adjusted for the difference:
1340 : 0 : long nDiff = nMinHeight - nTxtHeight;
1341 : 0 : pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() + nDiff) );
1342 : 0 : pLine->SetHeight( nMinHeight, nTxtHeight );
1343 : : }
1344 : : }
1345 [ - + ]: 205896 : else if ( rLSItem.GetLineSpaceRule() == SVX_LINE_SPACE_FIX )
1346 : : {
1347 : 0 : sal_uInt16 nFixHeight = GetYValue( rLSItem.GetLineHeight() );
1348 : 0 : sal_uInt16 nTxtHeight = pLine->GetHeight();
1349 : 0 : pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() + ( nFixHeight - nTxtHeight ) ) );
1350 : 0 : pLine->SetHeight( nFixHeight, nTxtHeight );
1351 : : }
1352 [ + + ]: 205896 : else if ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP )
1353 : : {
1354 [ + + ][ + + ]: 588 : if ( nPara || IsFixedCellHeight() || pLine->GetStartPortion() ) // Not the very first line
[ + + ][ + + ]
1355 : : {
1356 : : // There are documents with PropLineSpace 0, why?
1357 : : // (cmc: re above question :-) such documents can be seen by importing a .ppt
1358 [ + - ][ + + ]: 510 : if ( rLSItem.GetPropLineSpace() && ( rLSItem.GetPropLineSpace() != 100 ) )
[ + + ]
1359 : : {
1360 : 372 : sal_uInt16 nTxtHeight = pLine->GetHeight();
1361 : 372 : sal_Int32 nH = nTxtHeight;
1362 : 372 : nH *= rLSItem.GetPropLineSpace();
1363 : 372 : nH /= 100;
1364 : : // The Ascent has to be adjusted for the difference:
1365 : 372 : long nDiff = pLine->GetHeight() - nH;
1366 [ - + ]: 372 : if ( nDiff > pLine->GetMaxAscent() )
1367 : 0 : nDiff = pLine->GetMaxAscent();
1368 : 372 : pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() - nDiff) );
1369 : 372 : pLine->SetHeight( (sal_uInt16)nH, nTxtHeight );
1370 : : }
1371 : : }
1372 : : }
1373 : : }
1374 : :
1375 [ + - ][ + + : 398841 : if ( ( !IsVertical() && aStatus.AutoPageWidth() ) ||
- + # # ]
[ + + ]
1376 : 190287 : ( IsVertical() && aStatus.AutoPageHeight() ) )
1377 : : {
1378 : : // If the row fits within the current paper width, then this width
1379 : : // has to be used for the Alignment. If it does not fit or if it
1380 : : // will change the paper width, it will be formatted again for
1381 : : // Justification! = LEFT anyway.
1382 : 36534 : long nMaxLineWidthFix = ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() )
1383 [ + - ]: 36534 : - GetXValue( rLRItem.GetRight() ) - nStartX;
1384 [ + + ]: 18267 : if ( aTextSize.Width() < nMaxLineWidthFix )
1385 : 5402 : nMaxLineWidth = nMaxLineWidthFix;
1386 : : }
1387 : :
1388 [ - + ]: 208554 : if ( bCompressedChars )
1389 : : {
1390 : 0 : long nRemainingWidth = nMaxLineWidth - aTextSize.Width();
1391 [ # # ]: 0 : if ( nRemainingWidth > 0 )
1392 : : {
1393 [ # # ]: 0 : ImplExpandCompressedPortions( pLine, pParaPortion, nRemainingWidth );
1394 [ # # ]: 0 : aTextSize = pLine->CalcTextSize( *pParaPortion );
1395 : : }
1396 : : }
1397 : :
1398 [ - + ]: 208554 : if ( pLine->IsHangingPunctuation() )
1399 : : {
1400 : : // Width from HangingPunctuation was set to 0 in ImpBreakLine,
1401 : : // check for rel width now, maybe create compression...
1402 : 0 : long n = nMaxLineWidth - aTextSize.Width();
1403 [ # # ]: 0 : const TextPortion* pTP = pParaPortion->GetTextPortions()[pLine->GetEndPortion()];
1404 : 0 : sal_uInt16 nPosInArray = pLine->GetEnd()-1-pLine->GetStart();
1405 [ # # ][ # # ]: 0 : long nNewValue = ( nPosInArray ? pLine->GetCharPosArray()[ nPosInArray-1 ] : 0 ) + n;
[ # # ]
1406 [ # # ][ # # ]: 0 : pLine->GetCharPosArray()[ nPosInArray ] = nNewValue;
1407 : 0 : pTP->GetSize().Width() += n;
1408 : : }
1409 : :
1410 : 208554 : pLine->SetTextWidth( aTextSize.Width() );
1411 [ + + + + ]: 208554 : switch ( eJustification )
1412 : : {
1413 : : case SVX_ADJUST_CENTER:
1414 : : {
1415 : 11754 : long n = ( nMaxLineWidth - aTextSize.Width() ) / 2;
1416 : 11754 : n += nStartX; // Indentation is kept.
1417 [ + + ]: 11754 : if ( n > 0 )
1418 : 11065 : pLine->SetStartPosX( (sal_uInt16)n );
1419 : : else
1420 : 689 : pLine->SetStartPosX( 0 );
1421 : :
1422 : : }
1423 : 11754 : break;
1424 : : case SVX_ADJUST_RIGHT:
1425 : : {
1426 : : // For automatically wrapped lines, which has a blank at the end
1427 : : // the blank must not be displayed!
1428 : 1892 : long n = nMaxLineWidth - aTextSize.Width();
1429 : 1892 : n += nStartX; // Indentation is kept.
1430 [ + + ]: 1892 : if ( n > 0 )
1431 : 1466 : pLine->SetStartPosX( (sal_uInt16)n );
1432 : : else
1433 : 426 : pLine->SetStartPosX( 0 );
1434 : : }
1435 : 1892 : break;
1436 : : case SVX_ADJUST_BLOCK:
1437 : : {
1438 [ + - ]: 325 : bool bDistLastLine = (GetJustifyMethod(nPara) == SVX_JUSTIFY_METHOD_DISTRIBUTE);
1439 : 325 : long nRemainingSpace = nMaxLineWidth - aTextSize.Width();
1440 : 325 : pLine->SetStartPosX( (sal_uInt16)nStartX );
1441 [ + + ][ - + ]: 325 : if ( nRemainingSpace > 0 && (!bEOC || bDistLastLine) )
[ + + ]
1442 [ + - ]: 116 : ImpAdjustBlocks( pParaPortion, pLine, nRemainingSpace );
1443 : : }
1444 : 325 : break;
1445 : : default:
1446 : : {
1447 : 194583 : pLine->SetStartPosX( (sal_uInt16)nStartX ); // FI, LI
1448 : : }
1449 : 194583 : break;
1450 : : }
1451 : :
1452 : : // -----------------------------------------------------------------
1453 : : // Check whether the line must be re-issued ...
1454 : : // -----------------------------------------------------------------
1455 : 208554 : pLine->SetInvalid();
1456 : :
1457 : : // If a portion was wrapped there may be far too many positions in
1458 : : // CharPosArray:
1459 [ + - ]: 208554 : if ( bCalcCharPositions )
1460 : : {
1461 [ + - ]: 208554 : EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
1462 : 208554 : size_t nLen = pLine->GetLen();
1463 [ + + ]: 208554 : if (rArray.size() > nLen)
1464 [ + - ][ + - ]: 94166 : rArray.erase(rArray.begin()+nLen, rArray.end());
1465 : : }
1466 : :
1467 [ - + ]: 208554 : if ( GetTextRanger() )
1468 : : {
1469 [ # # ]: 0 : if ( nTextXOffset )
1470 : 0 : pLine->SetStartPosX( (sal_uInt16) ( pLine->GetStartPosX() + nTextXOffset ) );
1471 [ # # ]: 0 : if ( nTextExtraYOffset )
1472 : : {
1473 : 0 : pLine->SetHeight( (sal_uInt16) ( pLine->GetHeight() + nTextExtraYOffset ), 0, pLine->GetHeight() );
1474 : 0 : pLine->SetMaxAscent( (sal_uInt16) ( pLine->GetMaxAscent() + nTextExtraYOffset ) );
1475 : : }
1476 : : }
1477 : :
1478 : : // for <0 think over !
1479 [ + + ]: 208554 : if ( pParaPortion->IsSimpleInvalid() )
1480 : : {
1481 : : // Change through simple Text changes ...
1482 : : // Do mot cancel formatting since Portions possibly have to be split
1483 : : // again! If at some point cancelable, then validate the following
1484 : : // line! But if applicable, mark as valid, so there is less output...
1485 [ - + ]: 68 : if ( pLine->GetEnd() < nInvalidStart )
1486 : : {
1487 [ # # ][ # # ]: 0 : if ( *pLine == aSaveLine )
1488 : : {
1489 : 0 : pLine->SetValid();
1490 : : }
1491 : : }
1492 : : else
1493 : : {
1494 : 68 : sal_uInt16 nStart = pLine->GetStart();
1495 : 68 : sal_uInt16 nEnd = pLine->GetEnd();
1496 : :
1497 [ - + ]: 68 : if ( nStart > nInvalidEnd )
1498 : : {
1499 [ # # # # ]: 0 : if ( ( ( nStart-nInvalidDiff ) == aSaveLine.GetStart() ) &&
[ # # ]
1500 : 0 : ( ( nEnd-nInvalidDiff ) == aSaveLine.GetEnd() ) )
1501 : : {
1502 : 0 : pLine->SetValid();
1503 [ # # ][ # # ]: 0 : if ( bCalcCharPositions && bQuickFormat )
1504 : : {
1505 : 0 : bCalcCharPositions = sal_False;
1506 : 0 : bLineBreak = sal_False;
1507 [ # # ]: 0 : pParaPortion->CorrectValuesBehindLastFormattedLine( nLine );
1508 : : break;
1509 : : }
1510 : : }
1511 : : }
1512 [ + - ][ + + ]: 68 : else if ( bCalcCharPositions && bQuickFormat && ( nEnd > nInvalidEnd) )
[ - + ]
1513 : : {
1514 : : // If the invalid line ends so that the next begins on the
1515 : : // 'same' passage as before, i.e. not wrapped differently,
1516 : : // then the text width does not have to be determined anew:
1517 [ # # ]: 0 : if ( nEnd == ( aSaveLine.GetEnd() + nInvalidDiff ) )
1518 : : {
1519 : 0 : bCalcCharPositions = sal_False;
1520 : 0 : bLineBreak = sal_False;
1521 [ # # ]: 0 : pParaPortion->CorrectValuesBehindLastFormattedLine( nLine );
1522 : : break;
1523 : : }
1524 : : }
1525 : : }
1526 : : }
1527 : :
1528 [ + - ]: 208554 : if ( !bSameLineAgain )
1529 : : {
1530 : 208554 : nIndex = pLine->GetEnd(); // next line start = last line end
1531 : : // as nEnd points to the last charecter!
1532 : :
1533 : 208554 : sal_uInt16 nEndPortion = pLine->GetEndPortion();
1534 : :
1535 : : // Next line or maybe a new line....
1536 : 208554 : pLine = 0;
1537 [ + + ][ + - ]: 208554 : if ( nLine < pParaPortion->GetLines().Count()-1 )
1538 [ + - ]: 34 : pLine = pParaPortion->GetLines()[++nLine];
1539 [ + + ][ + - ]: 208554 : if ( pLine && ( nIndex >= pNode->Len() ) )
[ + + ][ + + ]
1540 : : {
1541 : 2 : nDelFromLine = nLine;
1542 : : break;
1543 : : }
1544 [ + + ]: 208552 : if ( !pLine )
1545 : : {
1546 [ + - ][ + + ]: 208520 : if ( nIndex < pNode->Len() )
1547 : : {
1548 [ + - ][ + - ]: 94179 : pLine = new EditLine;
1549 [ + - ]: 94179 : pParaPortion->GetLines().Insert(++nLine, pLine);
1550 : : }
1551 [ + - ][ + + ]: 114341 : else if ( nIndex && bLineBreak && GetTextRanger() )
[ - + ][ - + ]
1552 : : {
1553 : : // normaly CreateAndInsertEmptyLine would be called, but I want to use
1554 : : // CreateLines, so I need Polygon code only here...
1555 [ # # ]: 0 : TextPortion* pDummyPortion = new TextPortion( 0 );
1556 [ # # ]: 0 : pParaPortion->GetTextPortions().Append(pDummyPortion);
1557 [ # # ][ # # ]: 0 : pLine = new EditLine;
1558 [ # # ]: 0 : pParaPortion->GetLines().Insert(++nLine, pLine);
1559 : 0 : bForceOneRun = sal_True;
1560 : 0 : bProcessingEmptyLine = sal_True;
1561 : : }
1562 : : }
1563 [ + + ]: 208552 : if ( pLine )
1564 : : {
1565 [ + - ]: 94211 : aSaveLine = *pLine;
1566 : 94211 : pLine->SetStart( nIndex );
1567 : 94211 : pLine->SetEnd( nIndex );
1568 : 94211 : pLine->SetStartPortion( nEndPortion+1 );
1569 : 208554 : pLine->SetEndPortion( nEndPortion+1 );
1570 : : }
1571 : : }
1572 : : } // while ( Index < Len )
1573 : :
1574 [ + + ]: 114343 : if ( nDelFromLine != 0xFFFF )
1575 [ + - ]: 2 : pParaPortion->GetLines().DeleteFromLine( nDelFromLine );
1576 : :
1577 : : DBG_ASSERT( pParaPortion->GetLines().Count(), "No line after CreateLines!" );
1578 : :
1579 [ + + ]: 114343 : if ( bLineBreak == sal_True )
1580 [ + - ]: 19 : CreateAndInsertEmptyLine( pParaPortion, nStartPosY );
1581 : :
1582 [ + - ]: 114343 : delete[] pBuf;
1583 : :
1584 [ + - ]: 114343 : sal_Bool bHeightChanged = FinishCreateLines( pParaPortion );
1585 : :
1586 [ - + ]: 114343 : if ( bMapChanged )
1587 [ # # ]: 0 : GetRefDevice()->Pop();
1588 : :
1589 [ + - ]: 114343 : GetRefDevice()->Pop();
1590 : :
1591 [ + - ][ + - ]: 324581 : return bHeightChanged;
1592 : : }
1593 : :
1594 : 210257 : void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion* pParaPortion, sal_uInt32 )
1595 : : {
1596 : : DBG_ASSERT( !GetTextRanger(), "Don't use CreateAndInsertEmptyLine with a polygon!" );
1597 : :
1598 [ + - ][ + - ]: 210257 : EditLine* pTmpLine = new EditLine;
1599 [ + - ]: 210257 : pTmpLine->SetStart( pParaPortion->GetNode()->Len() );
1600 [ + - ]: 210257 : pTmpLine->SetEnd( pParaPortion->GetNode()->Len() );
1601 [ + - ]: 210257 : pParaPortion->GetLines().Append(pTmpLine);
1602 : :
1603 [ + - ][ + + ]: 210257 : sal_Bool bLineBreak = pParaPortion->GetNode()->Len() ? sal_True : sal_False;
1604 : 210257 : sal_Int32 nSpaceBefore = 0;
1605 [ + - ]: 210257 : sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pParaPortion->GetNode(), &nSpaceBefore );
1606 [ + - ]: 210257 : const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pParaPortion->GetNode() );
1607 [ + - ]: 210257 : const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pParaPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
1608 : 210257 : short nStartX = GetXValue( (short)(rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst() + nSpaceBefore));
1609 : :
1610 [ + - ]: 210257 : Rectangle aBulletArea = Rectangle( Point(), Point() );
1611 [ + + ]: 210257 : if ( bLineBreak == sal_True )
1612 : : {
1613 : 19 : nStartX = (short)GetXValue( rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst() + nSpaceBeforeAndMinLabelWidth );
1614 : : }
1615 : : else
1616 : : {
1617 [ + - ][ + - ]: 210238 : aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion ) );
1618 [ - + ]: 210238 : if ( aBulletArea.Right() > 0 )
1619 : 0 : pParaPortion->SetBulletX( (sal_uInt16) GetXValue( aBulletArea.Right() ) );
1620 : : else
1621 : 210238 : pParaPortion->SetBulletX( 0 ); // If Bullet set incorrectly.
1622 [ - + ]: 210238 : if ( pParaPortion->GetBulletX() > nStartX )
1623 : : {
1624 : 0 : nStartX = (short)GetXValue( rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst() + nSpaceBeforeAndMinLabelWidth );
1625 [ # # ]: 0 : if ( pParaPortion->GetBulletX() > nStartX )
1626 : 0 : nStartX = pParaPortion->GetBulletX();
1627 : : }
1628 : : }
1629 : :
1630 [ + - ]: 210257 : SvxFont aTmpFont;
1631 [ + + ][ + - ]: 210257 : SeekCursor( pParaPortion->GetNode(), bLineBreak ? pParaPortion->GetNode()->Len() : 0, aTmpFont );
[ + - ]
1632 [ + - ]: 210257 : aTmpFont.SetPhysFont( pRefDev );
1633 : :
1634 [ + - ]: 210257 : TextPortion* pDummyPortion = new TextPortion( 0 );
1635 [ + - ][ + - ]: 210257 : pDummyPortion->GetSize() = aTmpFont.GetPhysTxtSize( pRefDev, String() );
[ + - ]
1636 [ + + ]: 210257 : if ( IsFixedCellHeight() )
1637 [ + - ]: 642 : pDummyPortion->GetSize().Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() );
1638 [ + - ]: 210257 : pParaPortion->GetTextPortions().Append(pDummyPortion);
1639 : 210257 : FormatterFontMetric aFormatterMetrics;
1640 [ + - ]: 210257 : RecalcFormatterFontMetrics( aFormatterMetrics, aTmpFont );
1641 : 210257 : pTmpLine->SetMaxAscent( aFormatterMetrics.nMaxAscent );
1642 : 210257 : pTmpLine->SetHeight( (sal_uInt16) pDummyPortion->GetSize().Height() );
1643 : 210257 : sal_uInt16 nLineHeight = aFormatterMetrics.GetHeight();
1644 [ + + ]: 210257 : if ( nLineHeight > pTmpLine->GetHeight() )
1645 : 609 : pTmpLine->SetHeight( nLineHeight );
1646 : :
1647 [ + - ]: 210257 : if ( !aStatus.IsOutliner() )
1648 : : {
1649 [ + - ]: 210257 : sal_uInt16 nPara = GetParaPortions().GetPos( pParaPortion );
1650 [ + - ]: 210257 : SvxAdjust eJustification = GetJustification( nPara );
1651 [ + - ]: 210257 : long nMaxLineWidth = !IsVertical() ? aPaperSize.Width() : aPaperSize.Height();
1652 : 210257 : nMaxLineWidth -= GetXValue( rLRItem.GetRight() );
1653 : 210257 : long nTextXOffset = 0;
1654 [ - + ]: 210257 : if ( nMaxLineWidth < 0 )
1655 : 0 : nMaxLineWidth = 1;
1656 [ + + ]: 210257 : if ( eJustification == SVX_ADJUST_CENTER )
1657 : 55 : nStartX = sal::static_int_cast< short >(nMaxLineWidth / 2);
1658 [ + + ]: 210202 : else if ( eJustification == SVX_ADJUST_RIGHT )
1659 : 324 : nStartX = sal::static_int_cast< short >(nMaxLineWidth);
1660 : :
1661 : 210257 : nStartX = sal::static_int_cast< short >(nStartX + nTextXOffset);
1662 : : }
1663 : :
1664 : 210257 : pTmpLine->SetStartPosX( nStartX );
1665 : :
1666 [ + - ]: 210257 : if ( !aStatus.IsOutliner() )
1667 : : {
1668 [ + + ]: 210257 : if ( rLSItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN )
1669 : : {
1670 : 213 : sal_uInt16 nMinHeight = rLSItem.GetLineHeight();
1671 : 213 : sal_uInt16 nTxtHeight = pTmpLine->GetHeight();
1672 [ - + ]: 213 : if ( nTxtHeight < nMinHeight )
1673 : : {
1674 : : // The Ascent has to be adjusted for the difference:
1675 : 0 : long nDiff = nMinHeight - nTxtHeight;
1676 : 0 : pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() + nDiff) );
1677 : 0 : pTmpLine->SetHeight( nMinHeight, nTxtHeight );
1678 : : }
1679 : : }
1680 [ - + ]: 210044 : else if ( rLSItem.GetLineSpaceRule() == SVX_LINE_SPACE_FIX )
1681 : : {
1682 : 0 : sal_uInt16 nFixHeight = rLSItem.GetLineHeight();
1683 : 0 : sal_uInt16 nTxtHeight = pTmpLine->GetHeight();
1684 : :
1685 : 0 : pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() + ( nFixHeight - nTxtHeight ) ) );
1686 : 0 : pTmpLine->SetHeight( nFixHeight, nTxtHeight );
1687 : : }
1688 [ + + ]: 210044 : else if ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP )
1689 : : {
1690 [ + - ]: 129 : sal_uInt16 nPara = GetParaPortions().GetPos( pParaPortion );
1691 [ + + ][ + - ]: 129 : if ( nPara || IsFixedCellHeight() || pTmpLine->GetStartPortion() ) // Not the very first line
[ - + ][ + + ]
1692 : : {
1693 : : // There are documents with PropLineSpace 0, why?
1694 : : // (cmc: re above question :-) such documents can be seen by importing a .ppt
1695 [ + - ][ + - ]: 9 : if ( rLSItem.GetPropLineSpace() && ( rLSItem.GetPropLineSpace() != 100 ) )
[ + - ]
1696 : : {
1697 : 9 : sal_uInt16 nTxtHeight = pTmpLine->GetHeight();
1698 : 9 : sal_Int32 nH = nTxtHeight;
1699 : 9 : nH *= rLSItem.GetPropLineSpace();
1700 : 9 : nH /= 100;
1701 : : // The Ascent has to be adjusted for the difference:
1702 : 9 : long nDiff = pTmpLine->GetHeight() - nH;
1703 [ - + ]: 9 : if ( nDiff > pTmpLine->GetMaxAscent() )
1704 : 0 : nDiff = pTmpLine->GetMaxAscent();
1705 : 9 : pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() - nDiff) );
1706 : 9 : pTmpLine->SetHeight( (sal_uInt16)nH, nTxtHeight );
1707 : : }
1708 : : }
1709 : : }
1710 : : }
1711 : :
1712 [ + + ]: 210257 : if ( !bLineBreak )
1713 : : {
1714 [ + - ]: 210238 : long nMinHeight = aBulletArea.GetHeight();
1715 [ - + ]: 210238 : if ( nMinHeight > (long)pTmpLine->GetHeight() )
1716 : : {
1717 : 0 : long nDiff = nMinHeight - (long)pTmpLine->GetHeight();
1718 : : // distribute nDiff upwards and downwards
1719 : 0 : pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() + nDiff/2) );
1720 : 0 : pTmpLine->SetHeight( (sal_uInt16)nMinHeight );
1721 : : }
1722 : : }
1723 : : else
1724 : : {
1725 : : // -2: The new one is already inserted.
1726 : : #ifdef DBG_UTIL
1727 : : EditLine* pLastLine = pParaPortion->GetLines()[pParaPortion->GetLines().Count()-2];
1728 : : DBG_ASSERT( pLastLine, "soft wrap no line?!" );
1729 : : DBG_ASSERT( pLastLine->GetEnd() == pParaPortion->GetNode()->Len(), "different anyway?" );
1730 : : #endif
1731 [ + - ]: 19 : sal_uInt16 nPos = (sal_uInt16) pParaPortion->GetTextPortions().Count() - 1 ;
1732 : 19 : pTmpLine->SetStartPortion( nPos );
1733 : 19 : pTmpLine->SetEndPortion( nPos );
1734 [ + - ]: 210257 : }
1735 : 210257 : }
1736 : :
1737 : 324581 : sal_Bool ImpEditEngine::FinishCreateLines( ParaPortion* pParaPortion )
1738 : : {
1739 : : // CalcCharPositions( pParaPortion );
1740 : 324581 : pParaPortion->SetValid();
1741 : 324581 : long nOldHeight = pParaPortion->GetHeight();
1742 : 324581 : CalcHeight( pParaPortion );
1743 : :
1744 : : DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "FinishCreateLines: No Text-Portion?" );
1745 : 324581 : sal_Bool bRet = ( pParaPortion->GetHeight() != nOldHeight );
1746 : 324581 : return bRet;
1747 : : }
1748 : :
1749 : 115869 : void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, TextPortion* pPortion, sal_uInt16 nPortionStart, long nRemainingWidth, sal_Bool bCanHyphenate )
1750 : : {
1751 : 115869 : ContentNode* const pNode = pParaPortion->GetNode();
1752 : :
1753 : 115869 : sal_uInt16 nBreakInLine = nPortionStart - pLine->GetStart();
1754 : 115869 : sal_uInt16 nMax = nBreakInLine + pPortion->GetLen();
1755 [ + - ][ + + ]: 161419 : while ( ( nBreakInLine < nMax ) && ( pLine->GetCharPosArray()[nBreakInLine] < nRemainingWidth ) )
[ + + ]
1756 : 45550 : nBreakInLine++;
1757 : :
1758 : 115869 : sal_uInt16 nMaxBreakPos = nBreakInLine + pLine->GetStart();
1759 : 115869 : sal_uInt16 nBreakPos = 0xFFFF;
1760 : :
1761 : 115869 : sal_Bool bCompressBlank = sal_False;
1762 : 115869 : sal_Bool bHyphenated = sal_False;
1763 : 115869 : sal_Bool bHangingPunctuation = sal_False;
1764 : 115869 : sal_Unicode cAlternateReplChar = 0;
1765 : 115869 : sal_Unicode cAlternateExtraChar = 0;
1766 : :
1767 [ + + ][ + + ]: 115869 : if ( ( nMaxBreakPos < ( nMax + pLine->GetStart() ) ) && ( pNode->GetChar( nMaxBreakPos ) == ' ' ) )
[ + - ]
1768 : : {
1769 : : // Break behind the blank, blank will be compressed...
1770 : 15099 : nBreakPos = nMaxBreakPos + 1;
1771 : 15099 : bCompressBlank = sal_True;
1772 : : }
1773 : : else
1774 : : {
1775 : 100770 : sal_uInt16 nMinBreakPos = pLine->GetStart();
1776 [ + - ]: 100770 : const CharAttribList::AttribsType& rAttrs = pNode->GetCharAttribs().GetAttribs();
1777 [ + + ]: 141824 : for (size_t nAttr = rAttrs.size(); nAttr; )
1778 : : {
1779 [ + - ]: 41057 : const EditCharAttrib& rAttr = rAttrs[--nAttr];
1780 [ + + ][ + + ]: 41057 : if (rAttr.IsFeature() && rAttr.GetEnd() > nMinBreakPos && rAttr.GetEnd() <= nMaxBreakPos)
[ + + ][ + + ]
1781 : : {
1782 : 3 : nMinBreakPos = rAttr.GetEnd();
1783 : 3 : break;
1784 : : }
1785 : : }
1786 : :
1787 [ + - ][ + - ]: 100770 : lang::Locale aLocale = GetLocale( EditPaM( pNode, nMaxBreakPos ) );
1788 : :
1789 [ + - ]: 100770 : Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
1790 [ + - ][ + - ]: 100770 : OUString aText = pNode->GetString();
1791 : 100770 : Reference< XHyphenator > xHyph;
1792 [ + + ]: 100770 : if ( bCanHyphenate )
1793 [ + - ][ + - ]: 98080 : xHyph = GetHyphenator();
1794 [ + - ][ + - ]: 100770 : i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, Sequence< PropertyValue >(), 1 );
[ + - ]
1795 : 100770 : i18n::LineBreakUserOptions aUserOptions;
1796 : :
1797 [ + - ][ + - ]: 100770 : const i18n::ForbiddenCharacters* pForbidden = GetForbiddenCharsTable()->GetForbiddenCharacters( SvxLocaleToLanguage( aLocale ), sal_True );
[ + - ][ + - ]
1798 : 100770 : aUserOptions.forbiddenBeginCharacters = pForbidden->beginLine;
1799 : 100770 : aUserOptions.forbiddenEndCharacters = pForbidden->endLine;
1800 [ + - ]: 100770 : aUserOptions.applyForbiddenRules = ((const SfxBoolItem&)pNode->GetContentAttribs().GetItem( EE_PARA_FORBIDDENRULES )).GetValue();
1801 [ + - ]: 100770 : aUserOptions.allowPunctuationOutsideMargin = ((const SfxBoolItem&)pNode->GetContentAttribs().GetItem( EE_PARA_HANGINGPUNCTUATION )).GetValue();
1802 : 100770 : aUserOptions.allowHyphenateEnglish = sal_False;
1803 : :
1804 [ + - ]: 100770 : i18n::LineBreakResults aLBR = _xBI->getLineBreak(
1805 [ + - ][ + - ]: 100770 : pNode->GetString(), nMaxBreakPos, aLocale, nMinBreakPos, aHyphOptions, aUserOptions );
[ + - ]
1806 : 100770 : nBreakPos = (sal_uInt16)aLBR.breakIndex;
1807 : :
1808 : : // BUG in I18N - under special condition (break behind field, #87327#) breakIndex is < nMinBreakPos
1809 [ + + ]: 100770 : if ( nBreakPos < nMinBreakPos )
1810 : : {
1811 : 64369 : nBreakPos = nMinBreakPos;
1812 : : }
1813 [ - + ][ # # ]: 36401 : else if ( ( nBreakPos > nMaxBreakPos ) && !aUserOptions.allowPunctuationOutsideMargin )
1814 : : {
1815 : : OSL_FAIL( "I18N: XBreakIterator::getLineBreak returns position > Max" );
1816 : 0 : nBreakPos = nMaxBreakPos;
1817 : : }
1818 : :
1819 : : // nBreakPos can never be outside the portion, even not with hangig punctuation
1820 [ - + ]: 100770 : if ( nBreakPos > nMaxBreakPos )
1821 : 0 : nBreakPos = nMaxBreakPos;
1822 : :
1823 : : // BUG in I18N - the japanese dot is in the next line!
1824 : : // !!! Test!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1825 [ + + ]: 100770 : if ( (nBreakPos + ( aUserOptions.allowPunctuationOutsideMargin ? 0 : 1 ) ) <= nMaxBreakPos )
1826 : : {
1827 [ + - ][ + + ]: 7115 : sal_Unicode cFirstInNextLine = ( (nBreakPos+1) < pNode->Len() ) ? pNode->GetChar( nBreakPos ) : 0;
[ + - ]
1828 [ - + ]: 7115 : if ( cFirstInNextLine == 12290 )
1829 : 0 : nBreakPos++;
1830 : : }
1831 : :
1832 [ - + ]: 100770 : bHangingPunctuation = ( nBreakPos > nMaxBreakPos ) ? sal_True : sal_False;
1833 : 100770 : pLine->SetHangingPunctuation( bHangingPunctuation );
1834 : :
1835 : : // Whether a separator or not, push the word after the separator through
1836 : : // hyphenation ... NMaxBreakPos is the last character that fits into
1837 : : // the line, nBreakPos is the beginning of the word.
1838 : : // There is a problem if the Doc is so narrow that a word is broken
1839 : : // into more than two lines ...
1840 [ + + ][ + - ]: 100770 : if ( !bHangingPunctuation && bCanHyphenate && GetHyphenator().is() )
[ + - ][ + + ]
[ + + # # ]
[ + - ]
1841 : : {
1842 [ + - ]: 98080 : i18n::Boundary aBoundary = _xBI->getWordBoundary(
1843 [ + - ][ + - ]: 98080 : pNode->GetString(), nBreakPos, GetLocale( EditPaM( pNode, nBreakPos ) ), ::com::sun::star::i18n::WordType::DICTIONARY_WORD, true);
[ + - ][ + - ]
[ + - ]
1844 : 98080 : sal_uInt16 nWordStart = nBreakPos;
1845 : 98080 : sal_uInt16 nWordEnd = (sal_uInt16) aBoundary.endPos;
1846 : : DBG_ASSERT( nWordEnd > nWordStart, "ImpBreakLine: Start >= End?" );
1847 : :
1848 : 98080 : sal_uInt16 nWordLen = nWordEnd - nWordStart;
1849 [ + + ][ + - ]: 98080 : if ( ( nWordEnd >= nMaxBreakPos ) && ( nWordLen > 3 ) )
1850 : : {
1851 : : // May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
1852 [ + - ][ + - ]: 26445 : String aWord(pNode->GetString(), nWordStart, nWordLen);
1853 : 26445 : sal_uInt16 nMinTrail = nWordEnd-nMaxBreakPos+1; //+1: Before the dickey letter
1854 : 26445 : Reference< XHyphenatedWord > xHyphWord;
1855 [ + - ]: 26445 : if (xHyphenator.is())
1856 [ + - ][ + - ]: 26445 : xHyphWord = xHyphenator->hyphenate( aWord, aLocale, aWord.Len() - nMinTrail, Sequence< PropertyValue >() );
[ + - ][ + - ]
[ + - ][ + - ]
1857 [ + + ]: 26445 : if (xHyphWord.is())
1858 : : {
1859 [ + - ][ + - ]: 282 : sal_Bool bAlternate = xHyphWord->isAlternativeSpelling();
1860 [ + - ][ + - ]: 282 : sal_uInt16 _nWordLen = 1 + xHyphWord->getHyphenPos();
1861 : :
1862 [ + - ][ + - ]: 282 : if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= (pLine->GetStart() + 2 ) ) )
[ + - ]
1863 : : {
1864 [ + - ]: 282 : if ( !bAlternate )
1865 : : {
1866 : 282 : bHyphenated = sal_True;
1867 : 282 : nBreakPos = nWordStart + _nWordLen;
1868 : : }
1869 : : else
1870 : : {
1871 [ # # ][ # # ]: 0 : String aAlt( xHyphWord->getHyphenatedWord() );
[ # # ]
1872 : :
1873 : : // We expect the two cases, which might exist now:
1874 : : // 1) packen becomes pak-ken
1875 : : // 2) Schiffahrt becomes Schiff-fahrt
1876 : : // In case 1, a character has to be replaced
1877 : : // in case 2 a character is added.
1878 : : // The identification is complicated by long
1879 : : // compound words because the Hyphenator separates
1880 : : // all position of the word.
1881 : : // "Schiffahrtsbrennesseln" -> "Schifffahrtsbrennnesseln"
1882 : : // We can thus actually not directly connect the index of the
1883 : : // AlternativeWord to aWord. The whole issue will be simplified
1884 : : // by a function in the Hyphenator as soon as AMA builds this in...
1885 : 0 : sal_uInt16 nAltStart = _nWordLen - 1;
1886 : 0 : sal_uInt16 nTxtStart = nAltStart - (aAlt.Len() - aWord.Len());
1887 : 0 : sal_uInt16 nTxtEnd = nTxtStart;
1888 : 0 : sal_uInt16 nAltEnd = nAltStart;
1889 : :
1890 : : // The regions between the nStart and nEnd is the
1891 : : // difference between alternative and original string.
1892 [ # # ]: 0 : while( nTxtEnd < aWord.Len() && nAltEnd < aAlt.Len() &&
[ # # # # ]
[ # # ]
1893 : 0 : aWord.GetChar(nTxtEnd) != aAlt.GetChar(nAltEnd) )
1894 : : {
1895 : 0 : ++nTxtEnd;
1896 : 0 : ++nAltEnd;
1897 : : }
1898 : :
1899 : : // If a character is added, then we notice it now:
1900 [ # # ]: 0 : if( nAltEnd > nTxtEnd && nAltStart == nAltEnd &&
[ # # # # ]
[ # # ]
1901 : 0 : aWord.GetChar( nTxtEnd ) == aAlt.GetChar(nAltEnd) )
1902 : : {
1903 : 0 : ++nAltEnd;
1904 : 0 : ++nTxtStart;
1905 : 0 : ++nTxtEnd;
1906 : : }
1907 : :
1908 : : DBG_ASSERT( ( nAltEnd - nAltStart ) == 1, "Alternate: Wrong assumption!" );
1909 : :
1910 [ # # ]: 0 : if ( nTxtEnd > nTxtStart )
1911 : 0 : cAlternateReplChar = aAlt.GetChar( nAltStart );
1912 : : else
1913 : 0 : cAlternateExtraChar = aAlt.GetChar( nAltStart );
1914 : :
1915 : 0 : bHyphenated = sal_True;
1916 : 0 : nBreakPos = nWordStart + nTxtStart;
1917 [ # # ]: 0 : if ( cAlternateReplChar )
1918 [ # # ]: 0 : nBreakPos++;
1919 : : }
1920 : : }
1921 [ + - ]: 98080 : }
1922 : : }
1923 : : }
1924 : :
1925 [ + + ]: 100770 : if ( nBreakPos <= pLine->GetStart() )
1926 : : {
1927 : : // No separator in line => Chop!
1928 : 100213 : nBreakPos = nMaxBreakPos;
1929 : : // I18N nextCharacters !
1930 [ + + ]: 100213 : if ( nBreakPos <= pLine->GetStart() )
1931 : 93552 : nBreakPos = pLine->GetStart() + 1; // Otherwise infinite loop!
1932 [ + - ][ + - ]: 100770 : }
1933 : : }
1934 : :
1935 : : // the dickey portion is the end portion
1936 : 115869 : pLine->SetEnd( nBreakPos );
1937 : :
1938 : 115869 : sal_uInt16 nEndPortion = SplitTextPortion( pParaPortion, nBreakPos, pLine );
1939 : :
1940 [ + - ][ + + ]: 115869 : if ( !bCompressBlank && !bHangingPunctuation )
1941 : : {
1942 : : // When justification is not SVX_ADJUST_LEFT, it's important to compress
1943 : : // the trailing space even if there is enough room for the space...
1944 : : // Don't check for SVX_ADJUST_LEFT, doesn't matter to compress in this case too...
1945 : : DBG_ASSERT( nBreakPos > pLine->GetStart(), "ImpBreakLines - BreakPos not expected!" );
1946 [ + + ]: 100770 : if ( pNode->GetChar( nBreakPos-1 ) == ' ' )
1947 : 272 : bCompressBlank = sal_True;
1948 : : }
1949 : :
1950 [ + + ][ - + ]: 115869 : if ( bCompressBlank || bHangingPunctuation )
1951 : : {
1952 : 15371 : const TextPortion* pTP = pParaPortion->GetTextPortions()[nEndPortion];
1953 : : DBG_ASSERT( pTP->GetKind() == PORTIONKIND_TEXT, "BlankRubber: No TextPortion!" );
1954 : : DBG_ASSERT( nBreakPos > pLine->GetStart(), "SplitTextPortion at the beginning of the line?" );
1955 : 15371 : sal_uInt16 nPosInArray = nBreakPos - 1 - pLine->GetStart();
1956 [ + - ][ + - ]: 15371 : pTP->GetSize().Width() = ( nPosInArray && ( pTP->GetLen() > 1 ) ) ? pLine->GetCharPosArray()[ nPosInArray-1 ] : 0;
[ + - ][ + + ]
1957 : 15371 : pLine->GetCharPosArray()[ nPosInArray ] = pTP->GetSize().Width();
1958 : : }
1959 [ + + ]: 100498 : else if ( bHyphenated )
1960 : : {
1961 : : // A portion for inserting the separator ...
1962 [ + - ]: 282 : TextPortion* pHyphPortion = new TextPortion( 0 );
1963 : 282 : pHyphPortion->GetKind() = PORTIONKIND_HYPHENATOR;
1964 [ + - ]: 282 : String aHyphText(rtl::OUString(CH_HYPH));
1965 [ - + ]: 282 : if ( cAlternateReplChar )
1966 : : {
1967 [ # # ]: 0 : TextPortion* pPrev = pParaPortion->GetTextPortions()[nEndPortion];
1968 : : DBG_ASSERT( pPrev && pPrev->GetLen(), "Hyphenate: Prev portion?!" );
1969 : 0 : pPrev->SetLen( pPrev->GetLen() - 1 );
1970 : 0 : pHyphPortion->SetLen( 1 );
1971 : 0 : pHyphPortion->SetExtraValue( cAlternateReplChar );
1972 : : // Correct width of the portion above:
1973 : 0 : pPrev->GetSize().Width() =
1974 [ # # ][ # # ]: 0 : pLine->GetCharPosArray()[ nBreakPos-1 - pLine->GetStart() - 1 ];
1975 : : }
1976 [ - + ]: 282 : else if ( cAlternateExtraChar )
1977 : : {
1978 : 0 : pHyphPortion->SetExtraValue( cAlternateExtraChar );
1979 [ # # ][ # # ]: 0 : aHyphText.Insert( rtl::OUString(cAlternateExtraChar), 0 );
[ # # ]
1980 : : }
1981 : :
1982 : : // Determine the width of the Hyph-Portion:
1983 [ + - ]: 282 : SvxFont aFont;
1984 [ + - ]: 282 : SeekCursor( pParaPortion->GetNode(), nBreakPos, aFont );
1985 [ + - ]: 282 : aFont.SetPhysFont( GetRefDevice() );
1986 [ + - ]: 282 : pHyphPortion->GetSize().Height() = GetRefDevice()->GetTextHeight();
1987 [ + - ]: 282 : pHyphPortion->GetSize().Width() = GetRefDevice()->GetTextWidth( aHyphText );
1988 : :
1989 [ + - ][ + - ]: 282 : pParaPortion->GetTextPortions().Insert(++nEndPortion, pHyphPortion);
[ + - ]
1990 : : }
1991 : 115869 : pLine->SetEndPortion( nEndPortion );
1992 : 115869 : }
1993 : :
1994 : 116 : void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine, long nRemainingSpace )
1995 : : {
1996 : : DBG_ASSERT( nRemainingSpace > 0, "AdjustBlocks: Somewhat too little..." );
1997 : : DBG_ASSERT( pLine, "AdjustBlocks: Line ?!" );
1998 [ + - ][ - + ]: 116 : if ( ( nRemainingSpace < 0 ) || pLine->IsEmpty() )
[ + - ]
1999 : : return ;
2000 : :
2001 : 116 : const sal_uInt16 nFirstChar = pLine->GetStart();
2002 : 116 : const sal_uInt16 nLastChar = pLine->GetEnd() -1; // Last points behind
2003 : 116 : ContentNode* pNode = pParaPortion->GetNode();
2004 : :
2005 : : DBG_ASSERT( nLastChar < pNode->Len(), "AdjustBlocks: Out of range!" );
2006 : :
2007 : : // Search blanks or Kashidas...
2008 [ + - ]: 116 : std::vector<sal_uInt16> aPositions;
2009 : 116 : sal_uInt16 nLastScript = i18n::ScriptType::LATIN;
2010 [ + + ]: 448 : for ( sal_uInt16 nChar = nFirstChar; nChar <= nLastChar; nChar++ )
2011 : : {
2012 [ + - ]: 332 : EditPaM aPaM( pNode, nChar+1 );
2013 [ + - ]: 332 : LanguageType eLang = GetLanguage(aPaM);
2014 [ + - ]: 332 : sal_uInt16 nScript = GetScriptType(aPaM);
2015 [ - + ]: 332 : if ( MsLangId::getPrimaryLanguage( eLang) == LANGUAGE_ARABIC_PRIMARY_ONLY )
2016 : : // Arabic script is handled later.
2017 : 0 : continue;
2018 : :
2019 [ + - ][ + + ]: 332 : if ( pNode->GetChar(nChar) == ' ' )
2020 : : {
2021 : : // Normal latin script.
2022 [ + - ]: 8 : aPositions.push_back( nChar );
2023 : : }
2024 [ + + ]: 324 : else if (nChar > nFirstChar)
2025 : : {
2026 [ - + ]: 208 : if (nLastScript == i18n::ScriptType::ASIAN)
2027 : : {
2028 : : // Set break position between this and the last character if
2029 : : // the last character is asian script.
2030 [ # # ]: 0 : aPositions.push_back( nChar-1 );
2031 : : }
2032 [ - + ]: 208 : else if (nScript == i18n::ScriptType::ASIAN)
2033 : : {
2034 : : // Set break position between a latin script and asian script.
2035 [ # # ]: 0 : aPositions.push_back( nChar-1 );
2036 : : }
2037 : : }
2038 : :
2039 : 332 : nLastScript = nScript;
2040 : : }
2041 : :
2042 : : // Kashidas ?
2043 [ + - ]: 116 : ImpFindKashidas( pNode, nFirstChar, nLastChar, aPositions );
2044 : :
2045 [ + + ]: 116 : if ( aPositions.empty() )
2046 : : return;
2047 : :
2048 : : // If the last character is a blank, it is rejected!
2049 : : // The width must be distributed to the blockers in front...
2050 : : // But not if it is the only one.
2051 [ + - ][ + - ]: 16 : if ( ( pNode->GetChar( nLastChar ) == ' ' ) && ( aPositions.size() > 1 ) &&
[ - + # # ]
[ - + ]
2052 [ # # ][ # # ]: 8 : ( MsLangId::getPrimaryLanguage( GetLanguage( EditPaM( pNode, nLastChar ) ) ) != LANGUAGE_ARABIC_PRIMARY_ONLY ) )
[ - + ][ # # ]
2053 : : {
2054 [ # # ]: 0 : aPositions.pop_back();
2055 : : sal_uInt16 nPortionStart, nPortion;
2056 [ # # ]: 0 : nPortion = pParaPortion->GetTextPortions().FindPortion( nLastChar+1, nPortionStart );
2057 [ # # ]: 0 : TextPortion* pLastPortion = pParaPortion->GetTextPortions()[ nPortion ];
2058 [ # # ][ # # ]: 0 : long nRealWidth = pLine->GetCharPosArray()[nLastChar-nFirstChar];
2059 : 0 : long nBlankWidth = nRealWidth;
2060 [ # # ]: 0 : if ( nLastChar > nPortionStart )
2061 [ # # ][ # # ]: 0 : nBlankWidth -= pLine->GetCharPosArray()[nLastChar-nFirstChar-1];
2062 : : // Possibly the blank has already been deducted in ImpBreakLine:
2063 [ # # ]: 0 : if ( nRealWidth == pLastPortion->GetSize().Width() )
2064 : : {
2065 : : // For the last character the portion must stop behind the blank
2066 : : // => Simplify correction:
2067 : : DBG_ASSERT( ( nPortionStart + pLastPortion->GetLen() ) == ( nLastChar+1 ), "Blank actually not at the end of the portion!?");
2068 : 0 : pLastPortion->GetSize().Width() -= nBlankWidth;
2069 : 0 : nRemainingSpace += nBlankWidth;
2070 : : }
2071 [ # # ][ # # ]: 0 : pLine->GetCharPosArray()[nLastChar-nFirstChar] -= nBlankWidth;
2072 : : }
2073 : :
2074 : 8 : size_t nGaps = aPositions.size();
2075 : 8 : const long nMore4Everyone = nRemainingSpace / nGaps;
2076 : 8 : long nSomeExtraSpace = nRemainingSpace - nMore4Everyone*nGaps;
2077 : :
2078 : : DBG_ASSERT( nSomeExtraSpace < (long)nGaps, "AdjustBlocks: ExtraSpace too large" );
2079 : : DBG_ASSERT( nSomeExtraSpace >= 0, "AdjustBlocks: ExtraSpace < 0 " );
2080 : :
2081 : : // Correct the positions in the Array and the portion widths:
2082 : : // Last character won't be considered ...
2083 [ + - ][ + - ]: 16 : for ( std::vector<sal_uInt16>::const_iterator it(aPositions.begin()); it != aPositions.end(); ++it )
[ + + ][ + - ]
2084 : : {
2085 [ + - ]: 8 : sal_uInt16 nChar = *it;
2086 [ - + ]: 8 : if ( nChar < nLastChar )
2087 : : {
2088 : : sal_uInt16 nPortionStart, nPortion;
2089 [ # # ]: 0 : nPortion = pParaPortion->GetTextPortions().FindPortion( nChar, nPortionStart, true );
2090 [ # # ]: 0 : TextPortion* pLastPortion = pParaPortion->GetTextPortions()[ nPortion ];
2091 : :
2092 : : // The width of the portion:
2093 : 0 : pLastPortion->GetSize().Width() += nMore4Everyone;
2094 [ # # ]: 0 : if ( nSomeExtraSpace )
2095 : 0 : pLastPortion->GetSize().Width()++;
2096 : :
2097 : : // Correct positions in array
2098 : : // Even for kashidas just change positions, VCL will then draw the kashida automaticly
2099 : 0 : sal_uInt16 nPortionEnd = nPortionStart + pLastPortion->GetLen();
2100 [ # # ]: 0 : for ( sal_uInt16 _n = nChar; _n < nPortionEnd; _n++ )
2101 : : {
2102 [ # # ][ # # ]: 0 : pLine->GetCharPosArray()[_n-nFirstChar] += nMore4Everyone;
2103 [ # # ]: 0 : if ( nSomeExtraSpace )
2104 [ # # ][ # # ]: 0 : pLine->GetCharPosArray()[_n-nFirstChar]++;
2105 : : }
2106 : :
2107 [ # # ]: 0 : if ( nSomeExtraSpace )
2108 : 0 : nSomeExtraSpace--;
2109 : : }
2110 : : }
2111 : :
2112 : : // Now the text width contains the extra width...
2113 [ + + ]: 116 : pLine->SetTextWidth( pLine->GetTextWidth() + nRemainingSpace );
2114 : : }
2115 : :
2116 : 116 : void ImpEditEngine::ImpFindKashidas( ContentNode* pNode, sal_uInt16 nStart, sal_uInt16 nEnd, std::vector<sal_uInt16>& rArray )
2117 : : {
2118 : : // the search has to be performed on a per word base
2119 : :
2120 [ + - ][ + - ]: 116 : EditSelection aWordSel( EditPaM( pNode, nStart ) );
2121 [ + - ][ + - ]: 116 : aWordSel = SelectWord( aWordSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD );
2122 [ + + ]: 116 : if ( aWordSel.Min().GetIndex() < nStart )
2123 : 70 : aWordSel.Min().GetIndex() = nStart;
2124 : :
2125 [ + - ][ + - ]: 232 : while ( ( aWordSel.Min().GetNode() == pNode ) && ( aWordSel.Min().GetIndex() < nEnd ) )
[ + + ][ + + ]
2126 : : {
2127 : 116 : sal_uInt16 nSavPos = aWordSel.Max().GetIndex();
2128 [ + + ]: 116 : if ( aWordSel.Max().GetIndex() > nEnd )
2129 : 108 : aWordSel.Max().GetIndex() = nEnd;
2130 : :
2131 [ + - ]: 116 : String aWord = GetSelected( aWordSel );
2132 : :
2133 : : // restore selection for proper iteration at the end of the function
2134 : 116 : aWordSel.Max().GetIndex() = nSavPos;
2135 : :
2136 : 116 : xub_StrLen nIdx = 0;
2137 : 116 : xub_StrLen nKashidaPos = STRING_LEN;
2138 : : xub_Unicode cCh;
2139 : 116 : xub_Unicode cPrevCh = 0;
2140 : :
2141 [ + + ]: 332 : while ( nIdx < aWord.Len() )
2142 : : {
2143 : 216 : cCh = aWord.GetChar( nIdx );
2144 : :
2145 : : // 1. Priority:
2146 : : // after user inserted kashida
2147 [ - + ]: 216 : if ( 0x640 == cCh )
2148 : : {
2149 : 0 : nKashidaPos = aWordSel.Min().GetIndex() + nIdx;
2150 : 0 : break;
2151 : : }
2152 : :
2153 : : // 2. Priority:
2154 : : // after a Seen or Sad
2155 [ + + ][ + - ]: 216 : if ( nIdx + 1 < aWord.Len() &&
[ - + ][ - + ]
2156 : : ( 0x633 == cCh || 0x635 == cCh ) )
2157 : : {
2158 : 0 : nKashidaPos = aWordSel.Min().GetIndex() + nIdx;
2159 : 0 : break;
2160 : : }
2161 : :
2162 : : // 3. Priority:
2163 : : // before final form of Teh Marbuta, Hah, Dal
2164 : : // 4. Priority:
2165 : : // before final form of Alef, Lam or Kaf
2166 [ + + ][ + + ]: 216 : if ( nIdx && nIdx + 1 == aWord.Len() &&
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ - + ]
[ - + ]
2167 : : ( 0x629 == cCh || 0x62D == cCh || 0x62F == cCh ||
2168 : : 0x627 == cCh || 0x644 == cCh || 0x643 == cCh ) )
2169 : : {
2170 : : DBG_ASSERT( 0 != cPrevCh, "No previous character" );
2171 : :
2172 : : // check if character is connectable to previous character,
2173 [ # # ]: 0 : if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
2174 : : {
2175 : 0 : nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1;
2176 : 0 : break;
2177 : : }
2178 : : }
2179 : :
2180 : : // 5. Priority:
2181 : : // before media Bah
2182 [ + + ][ + + ]: 216 : if ( nIdx && nIdx + 1 < aWord.Len() && 0x628 == cCh )
[ - + ][ - + ]
2183 : : {
2184 : : DBG_ASSERT( 0 != cPrevCh, "No previous character" );
2185 : :
2186 : : // check if next character is Reh, Yeh or Alef Maksura
2187 : 0 : xub_Unicode cNextCh = aWord.GetChar( nIdx + 1 );
2188 : :
2189 [ # # ][ # # ]: 0 : if ( 0x631 == cNextCh || 0x64A == cNextCh ||
[ # # ]
2190 : : 0x649 == cNextCh )
2191 : : {
2192 : : // check if character is connectable to previous character,
2193 [ # # ]: 0 : if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
2194 : 0 : nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1;
2195 : : }
2196 : : }
2197 : :
2198 : : // 6. Priority:
2199 : : // other connecting possibilities
2200 [ + + ][ + + ]: 216 : if ( nIdx && nIdx + 1 == aWord.Len() &&
[ - + ][ # # ]
[ - + ]
2201 : : 0x60C <= cCh && 0x6FE >= cCh )
2202 : : {
2203 : : DBG_ASSERT( 0 != cPrevCh, "No previous character" );
2204 : :
2205 : : // check if character is connectable to previous character,
2206 [ # # ]: 0 : if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
2207 : : {
2208 : : // only choose this position if we did not find
2209 : : // a better one:
2210 [ # # ]: 0 : if ( STRING_LEN == nKashidaPos )
2211 : 0 : nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1;
2212 : 0 : break;
2213 : : }
2214 : : }
2215 : :
2216 : : // Do not consider Fathatan, Dammatan, Kasratan, Fatha,
2217 : : // Damma, Kasra, Shadda and Sukun when checking if
2218 : : // a character can be connected to previous character.
2219 [ - + ][ # # ]: 216 : if ( cCh < 0x64B || cCh > 0x652 )
2220 : 216 : cPrevCh = cCh;
2221 : :
2222 : 216 : ++nIdx;
2223 : : } // end of current word
2224 : :
2225 [ - + ]: 116 : if ( STRING_LEN != nKashidaPos )
2226 [ # # ]: 0 : rArray.push_back( nKashidaPos );
2227 : :
2228 [ + - ][ + - ]: 116 : aWordSel = WordRight( aWordSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD );
2229 [ + - ][ + - ]: 116 : aWordSel = SelectWord( aWordSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD );
2230 [ + - ]: 116 : }
2231 : 116 : }
2232 : :
2233 : 115869 : sal_uInt16 ImpEditEngine::SplitTextPortion( ParaPortion* pPortion, sal_uInt16 nPos, EditLine* pCurLine )
2234 : : {
2235 : : DBG_ASSERT( pPortion, "SplitTextPortion: Which ?" );
2236 : :
2237 : : // The portion at nPos is split, if there is not a transition at nPos anyway
2238 [ - + ]: 115869 : if ( nPos == 0 )
2239 : 0 : return 0;
2240 : :
2241 : : sal_uInt16 nSplitPortion;
2242 : 115869 : sal_uInt16 nTmpPos = 0;
2243 : 115869 : TextPortion* pTextPortion = NULL;
2244 : 115869 : sal_uInt16 nPortions = pPortion->GetTextPortions().Count();
2245 [ + - ]: 519732 : for ( nSplitPortion = 0; nSplitPortion < nPortions; nSplitPortion++ )
2246 : : {
2247 : 519732 : TextPortion* pTP = pPortion->GetTextPortions()[nSplitPortion];
2248 : 519732 : nTmpPos = nTmpPos + pTP->GetLen();
2249 [ + + ]: 519732 : if ( nTmpPos >= nPos )
2250 : : {
2251 [ + + ]: 115869 : if ( nTmpPos == nPos ) // then nothing needs to be split
2252 : : {
2253 : 21710 : return nSplitPortion;
2254 : : }
2255 : 94159 : pTextPortion = pTP;
2256 : 94159 : break;
2257 : : }
2258 : : }
2259 : :
2260 : : DBG_ASSERT( pTextPortion, "Position outside the area!" );
2261 : : DBG_ASSERT( pTextPortion->GetKind() == PORTIONKIND_TEXT, "SplitTextPortion: No TextPortion!" );
2262 : :
2263 : 94159 : sal_uInt16 nOverlapp = nTmpPos - nPos;
2264 : 94159 : pTextPortion->GetLen() = pTextPortion->GetLen() - nOverlapp;
2265 : 94159 : TextPortion* pNewPortion = new TextPortion( nOverlapp );
2266 : 94159 : pPortion->GetTextPortions().Insert(nSplitPortion+1, pNewPortion);
2267 : : // Set sizes
2268 [ + - ]: 94159 : if ( pCurLine )
2269 : : {
2270 : : // No new GetTextSize, instead use values from the Array:
2271 : : DBG_ASSERT( nPos > pCurLine->GetStart(), "SplitTextPortion at the beginning of the line?" );
2272 : 94159 : pTextPortion->GetSize().Width() = pCurLine->GetCharPosArray()[ nPos-pCurLine->GetStart()-1 ];
2273 : :
2274 [ # # ][ - + ]: 94159 : if ( pTextPortion->GetExtraInfos() && pTextPortion->GetExtraInfos()->bCompressed )
[ - + ]
2275 : : {
2276 : : // We need the original size from the portion
2277 [ # # ]: 0 : sal_uInt16 nTxtPortionStart = pPortion->GetTextPortions().GetStartPos( nSplitPortion );
2278 [ # # ]: 0 : SvxFont aTmpFont( pPortion->GetNode()->GetCharAttribs().GetDefFont() );
2279 [ # # ]: 0 : SeekCursor( pPortion->GetNode(), nTxtPortionStart+1, aTmpFont );
2280 [ # # ]: 0 : aTmpFont.SetPhysFont( GetRefDevice() );
2281 [ # # ]: 0 : GetRefDevice()->Push( PUSH_TEXTLANGUAGE );
2282 [ # # ]: 0 : ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() );
2283 [ # # ][ # # ]: 0 : Size aSz = aTmpFont.QuickGetTextSize( GetRefDevice(), pPortion->GetNode()->GetString(), nTxtPortionStart, pTextPortion->GetLen(), NULL );
2284 [ # # ]: 0 : GetRefDevice()->Pop();
2285 [ # # ]: 0 : pTextPortion->GetExtraInfos()->nOrgWidth = aSz.Width();
2286 : : }
2287 : : }
2288 : : else
2289 : 0 : pTextPortion->GetSize().Width() = (-1);
2290 : :
2291 : 115869 : return nSplitPortion;
2292 : : }
2293 : :
2294 : 114287 : void ImpEditEngine::CreateTextPortions( ParaPortion* pParaPortion, sal_uInt16& rStart )
2295 : : {
2296 : 114287 : sal_uInt16 nStartPos = rStart;
2297 : 114287 : ContentNode* pNode = pParaPortion->GetNode();
2298 : : DBG_ASSERT( pNode->Len(), "CreateTextPortions should not be used for empty paragraphs!" );
2299 : :
2300 [ + - ]: 114287 : ::std::set< sal_uInt32 > aPositions;
2301 [ + - ]: 114287 : aPositions.insert( 0 );
2302 : :
2303 : 114287 : sal_uInt16 nAttr = 0;
2304 [ + - ][ + - ]: 114287 : EditCharAttrib* pAttrib = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
2305 [ + + ]: 180603 : while ( pAttrib )
2306 : : {
2307 : : // Insert Start and End into the Array...
2308 : : // The Insert method does not allow for duplicate values....
2309 [ + - ]: 66316 : aPositions.insert( pAttrib->GetStart() );
2310 [ + - ]: 66316 : aPositions.insert( pAttrib->GetEnd() );
2311 : 66316 : nAttr++;
2312 [ + - ][ + - ]: 66316 : pAttrib = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
2313 : : }
2314 [ + - ][ + - ]: 114287 : aPositions.insert( pNode->Len() );
2315 : :
2316 [ - + ]: 114287 : if ( pParaPortion->aScriptInfos.empty() )
2317 [ # # ][ # # ]: 0 : ((ImpEditEngine*)this)->InitScriptTypes( GetParaPortions().GetPos( pParaPortion ) );
2318 : :
2319 : 114287 : const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
2320 [ + + ]: 228847 : for ( size_t nT = 0; nT < rTypes.size(); nT++ )
2321 [ + - ][ + - ]: 114560 : aPositions.insert( rTypes[nT].nStartPos );
2322 : :
2323 : 114287 : const WritingDirectionInfos& rWritingDirections = pParaPortion->aWritingDirectionInfos;
2324 [ + + ]: 228574 : for ( size_t nD = 0; nD < rWritingDirections.size(); nD++ )
2325 [ + - ][ + - ]: 114287 : aPositions.insert( rWritingDirections[nD].nStartPos );
2326 : :
2327 [ - + ][ # # ]: 114287 : if ( mpIMEInfos && mpIMEInfos->nLen && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetNode() == pNode ) )
[ # # ][ # # ]
[ # # ][ - + ]
2328 : : {
2329 : 0 : sal_uInt16 nLastAttr = 0xFFFF;
2330 [ # # ]: 0 : for( sal_uInt16 n = 0; n < mpIMEInfos->nLen; n++ )
2331 : : {
2332 [ # # ]: 0 : if ( mpIMEInfos->pAttribs[n] != nLastAttr )
2333 : : {
2334 [ # # ]: 0 : aPositions.insert( mpIMEInfos->aPos.GetIndex() + n );
2335 : 0 : nLastAttr = mpIMEInfos->pAttribs[n];
2336 : : }
2337 : : }
2338 [ # # ]: 0 : aPositions.insert( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen );
2339 : : }
2340 : :
2341 : : // From ... Delete:
2342 : : // Unfortunately, the number of text portions does not have to match
2343 : : // aPositions.Count(), since there might be line breaks...
2344 : 114287 : sal_uInt16 nPortionStart = 0;
2345 : 114287 : sal_uInt16 nInvPortion = 0;
2346 : : sal_uInt16 nP;
2347 [ + - ][ + + ]: 114287 : for ( nP = 0; nP < pParaPortion->GetTextPortions().Count(); nP++ )
2348 : : {
2349 [ + - ]: 3728 : const TextPortion* pTmpPortion = pParaPortion->GetTextPortions()[nP];
2350 : 3728 : nPortionStart = nPortionStart + pTmpPortion->GetLen();
2351 [ + - ]: 3728 : if ( nPortionStart >= nStartPos )
2352 : : {
2353 : 3728 : nPortionStart = nPortionStart - pTmpPortion->GetLen();
2354 : 3728 : rStart = nPortionStart;
2355 : 3728 : nInvPortion = nP;
2356 : 3728 : break;
2357 : : }
2358 : : }
2359 : : DBG_ASSERT( nP < pParaPortion->GetTextPortions().Count() || !pParaPortion->GetTextPortions().Count(), "Nothing to delete: CreateTextPortions" );
2360 [ - + ][ # # ]: 114287 : if ( nInvPortion && ( nPortionStart+pParaPortion->GetTextPortions()[nInvPortion]->GetLen() > nStartPos ) )
[ # # ][ - + ]
2361 : : {
2362 : : // prefer one in front ...
2363 : : // But only if it was in the middle of the portion of, otherwise it
2364 : : // might be the only one in the row in front!
2365 : 0 : nInvPortion--;
2366 [ # # ]: 0 : nPortionStart = nPortionStart - pParaPortion->GetTextPortions()[nInvPortion]->GetLen();
2367 : : }
2368 [ + - ]: 114287 : pParaPortion->GetTextPortions().DeleteFromPortion( nInvPortion );
2369 : :
2370 : : // A portion may also have been formed by a line break:
2371 [ + - ]: 114287 : aPositions.insert( nPortionStart );
2372 : :
2373 [ + - ]: 114287 : ::std::set< sal_uInt32 >::iterator nInvPos = aPositions.find( nPortionStart );
2374 : : DBG_ASSERT( (nInvPos != aPositions.end()), "InvPos ?!" );
2375 : :
2376 : 114287 : ::std::set< sal_uInt32 >::iterator i = nInvPos;
2377 [ + - ]: 114287 : ++i;
2378 [ + - ][ + + ]: 230304 : while ( i != aPositions.end() )
2379 : : {
2380 [ + - ][ + - ]: 116017 : TextPortion* pNew = new TextPortion( static_cast<sal_uInt16>(*i++) - static_cast<sal_uInt16>(*nInvPos++) );
[ + - ][ + - ]
[ + - ]
2381 [ + - ]: 116017 : pParaPortion->GetTextPortions().Append(pNew);
2382 : : }
2383 : :
2384 : 114287 : DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "No Portions?!" );
2385 : : #if OSL_DEBUG_LEVEL > 2
2386 : : OSL_ENSURE( pParaPortion->DbgCheckTextPortions(), "Portion is broken?" );
2387 : : #endif
2388 : 114287 : }
2389 : :
2390 : 56 : void ImpEditEngine::RecalcTextPortion( ParaPortion* pParaPortion, sal_uInt16 nStartPos, short nNewChars )
2391 : : {
2392 : : DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "No Portions!" );
2393 : : DBG_ASSERT( nNewChars, "RecalcTextPortion with Diff == 0" );
2394 : :
2395 : 56 : ContentNode* const pNode = pParaPortion->GetNode();
2396 [ + - ]: 56 : if ( nNewChars > 0 )
2397 : : {
2398 : : // If an Attribute begins/ends at nStartPos, then a new portion starts
2399 : : // otherwise the portion is extended at nStartPos.
2400 [ + - ][ + + ]: 56 : if ( pNode->GetCharAttribs().HasBoundingAttrib( nStartPos ) || IsScriptChange( EditPaM( pNode, nStartPos ) ) )
[ + - ][ + - ]
[ + - ][ + + ]
[ + - # # ]
2401 : : {
2402 : 56 : sal_uInt16 nNewPortionPos = 0;
2403 [ - + ]: 56 : if ( nStartPos )
2404 : 0 : nNewPortionPos = SplitTextPortion( pParaPortion, nStartPos ) + 1;
2405 : :
2406 : : // A blank portion may be here, if the paragraph was empty,
2407 : : // or if a line was created by a hard line break.
2408 [ + - + - ]: 112 : if ( ( nNewPortionPos < pParaPortion->GetTextPortions().Count() ) &&
[ + - ]
2409 : 56 : !pParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() )
2410 : : {
2411 : : DBG_ASSERT( pParaPortion->GetTextPortions()[nNewPortionPos]->GetKind() == PORTIONKIND_TEXT, "the empty portion was no TextPortion!" );
2412 : : sal_uInt16 & r =
2413 : 56 : pParaPortion->GetTextPortions()[nNewPortionPos]->GetLen();
2414 : 56 : r = r + nNewChars;
2415 : : }
2416 : : else
2417 : : {
2418 : 0 : TextPortion* pNewPortion = new TextPortion( nNewChars );
2419 : 0 : pParaPortion->GetTextPortions().Insert(nNewPortionPos, pNewPortion);
2420 : : }
2421 : : }
2422 : : else
2423 : : {
2424 : : sal_uInt16 nPortionStart;
2425 : 0 : const sal_uInt16 nTP = pParaPortion->GetTextPortions().
2426 [ # # ]: 0 : FindPortion( nStartPos, nPortionStart );
2427 [ # # ]: 0 : TextPortion* const pTP = pParaPortion->GetTextPortions()[ nTP ];
2428 : : DBG_ASSERT( pTP, "RecalcTextPortion: Portion not found" );
2429 : 0 : pTP->GetLen() = pTP->GetLen() + nNewChars;
2430 : 0 : pTP->GetSize().Width() = (-1);
2431 : : }
2432 : : }
2433 : : else
2434 : : {
2435 : : // Shrink or remove portion if necessary.
2436 : : // Before calling this method it must be ensured that no portions were
2437 : : // in the deleted area!
2438 : :
2439 : : // There must be no portions extending into the area or portions starting in
2440 : : // the area, so it must be:
2441 : : // nStartPos <= nPos <= nStartPos - nNewChars(neg.)
2442 : 0 : sal_uInt16 nPortion = 0;
2443 : 0 : sal_uInt16 nPos = 0;
2444 : 0 : sal_uInt16 nEnd = nStartPos-nNewChars;
2445 : 0 : sal_uInt16 nPortions = pParaPortion->GetTextPortions().Count();
2446 : 0 : TextPortion* pTP = 0;
2447 [ # # ]: 0 : for ( nPortion = 0; nPortion < nPortions; nPortion++ )
2448 : : {
2449 : 0 : pTP = pParaPortion->GetTextPortions()[ nPortion ];
2450 [ # # ]: 0 : if ( ( nPos+pTP->GetLen() ) > nStartPos )
2451 : : {
2452 : : DBG_ASSERT( nPos <= nStartPos, "Wrong Start!" );
2453 : : DBG_ASSERT( nPos+pTP->GetLen() >= nEnd, "Wrong End!" );
2454 : 0 : break;
2455 : : }
2456 : 0 : nPos = nPos + pTP->GetLen();
2457 : : }
2458 : : DBG_ASSERT( pTP, "RecalcTextPortion: Portion not found" );
2459 [ # # ][ # # ]: 0 : if ( ( nPos == nStartPos ) && ( (nPos+pTP->GetLen()) == nEnd ) )
[ # # ]
2460 : : {
2461 : : // Remove portion;
2462 : 0 : sal_uInt8 nType = pTP->GetKind();
2463 : 0 : pParaPortion->GetTextPortions().Remove( nPortion );
2464 [ # # ]: 0 : if ( nType == PORTIONKIND_LINEBREAK )
2465 : : {
2466 : 0 : TextPortion* pNext = pParaPortion->GetTextPortions()[ nPortion ];
2467 [ # # ][ # # ]: 0 : if ( pNext && !pNext->GetLen() )
[ # # ]
2468 : : {
2469 : : // Remove dummy portion
2470 : 0 : pParaPortion->GetTextPortions().Remove( nPortion );
2471 : : }
2472 : : }
2473 : : }
2474 : : else
2475 : : {
2476 : : DBG_ASSERT( pTP->GetLen() > (-nNewChars), "Portion too small to shrink! ");
2477 : 0 : pTP->GetLen() = pTP->GetLen() + nNewChars;
2478 : : }
2479 : :
2480 : 0 : sal_uInt16 nPortionCount = pParaPortion->GetTextPortions().Count();
2481 : : assert( nPortionCount );
2482 [ # # ]: 0 : if (nPortionCount)
2483 : : {
2484 : : // No HYPHENATOR portion is allowed to get stuck right at the end...
2485 : 0 : sal_uInt16 nLastPortion = nPortionCount - 1;
2486 : 0 : pTP = pParaPortion->GetTextPortions()[nLastPortion];
2487 [ # # ]: 0 : if ( pTP->GetKind() == PORTIONKIND_HYPHENATOR )
2488 : : {
2489 : : // Discard portion; if possible, correct the ones before,
2490 : : // if the Hyphenator portion has swallowed one character...
2491 [ # # ][ # # ]: 0 : if ( nLastPortion && pTP->GetLen() )
[ # # ]
2492 : : {
2493 : 0 : TextPortion* pPrev = pParaPortion->GetTextPortions()[nLastPortion - 1];
2494 : : DBG_ASSERT( pPrev->GetKind() == PORTIONKIND_TEXT, "Portion?!" );
2495 : 0 : pPrev->SetLen( pPrev->GetLen() + pTP->GetLen() );
2496 : 0 : pPrev->GetSize().Width() = (-1);
2497 : : }
2498 : 0 : pParaPortion->GetTextPortions().Remove( nLastPortion );
2499 : : }
2500 : : }
2501 : : }
2502 : : #if OSL_DEBUG_LEVEL > 2
2503 : : OSL_ENSURE( pParaPortion->DbgCheckTextPortions(), "Portions are broken?" );
2504 : : #endif
2505 : 56 : }
2506 : :
2507 : 353510 : void ImpEditEngine::SetTextRanger( TextRanger* pRanger )
2508 : : {
2509 [ - + ]: 353510 : if ( pTextRanger != pRanger )
2510 : : {
2511 [ # # ]: 0 : delete pTextRanger;
2512 : 0 : pTextRanger = pRanger;
2513 : :
2514 [ # # ]: 0 : for ( sal_uInt16 nPara = 0; nPara < GetParaPortions().Count(); nPara++ )
2515 : : {
2516 : 0 : ParaPortion* pParaPortion = GetParaPortions()[nPara];
2517 : 0 : pParaPortion->MarkSelectionInvalid( 0, pParaPortion->GetNode()->Len() );
2518 : 0 : pParaPortion->GetLines().Reset();
2519 : : }
2520 : :
2521 : 0 : FormatFullDoc();
2522 : 0 : UpdateViews( GetActiveView() );
2523 [ # # ][ # # ]: 0 : if ( GetUpdateMode() && GetActiveView() )
[ # # ]
2524 : 0 : pActiveView->ShowCursor(false, false);
2525 : : }
2526 : 353510 : }
2527 : :
2528 : 143220 : void ImpEditEngine::SetVertical( sal_Bool bVertical )
2529 : : {
2530 [ - + ]: 143220 : if ( IsVertical() != bVertical )
2531 : : {
2532 : 0 : GetEditDoc().SetVertical( bVertical );
2533 : 0 : sal_Bool bUseCharAttribs = ( aStatus.GetControlWord() & EE_CNTRL_USECHARATTRIBS ) ? sal_True : sal_False;
2534 : 0 : GetEditDoc().CreateDefFont( bUseCharAttribs );
2535 [ # # ]: 0 : if ( IsFormatted() )
2536 : : {
2537 : 0 : FormatFullDoc();
2538 : 0 : UpdateViews( GetActiveView() );
2539 : : }
2540 : : }
2541 : 143220 : }
2542 : :
2543 : 96755 : void ImpEditEngine::SetFixedCellHeight( sal_Bool bUseFixedCellHeight )
2544 : : {
2545 [ + + ]: 96755 : if ( IsFixedCellHeight() != bUseFixedCellHeight )
2546 : : {
2547 : 12 : GetEditDoc().SetFixedCellHeight( bUseFixedCellHeight );
2548 [ + - ]: 12 : if ( IsFormatted() )
2549 : : {
2550 : 12 : FormatFullDoc();
2551 : 12 : UpdateViews( GetActiveView() );
2552 : : }
2553 : : }
2554 : 96755 : }
2555 : :
2556 : 653796 : void ImpEditEngine::SeekCursor( ContentNode* pNode, sal_uInt16 nPos, SvxFont& rFont, OutputDevice* pOut, sal_uInt16 nIgnoreWhich )
2557 : : {
2558 : : // It was planned, SeekCursor( nStartPos, nEndPos, ... ), so that it would
2559 : : // only be searched anew at the StartPosition.
2560 : : // Problem: There would be two lists to consider/handle:
2561 : : // OrderedByStart,OrderedByEnd.
2562 : :
2563 [ + + ]: 653796 : if ( nPos > pNode->Len() )
2564 : 2603 : nPos = pNode->Len();
2565 : :
2566 : 653796 : rFont = pNode->GetCharAttribs().GetDefFont();
2567 : :
2568 [ + - ]: 653796 : short nScriptType = GetScriptType( EditPaM( pNode, nPos ) );
2569 [ + + ][ - + ]: 653796 : if ( ( nScriptType == i18n::ScriptType::ASIAN ) || ( nScriptType == i18n::ScriptType::COMPLEX ) )
2570 : : {
2571 [ + - ][ + - ]: 42 : const SvxFontItem& rFontItem = (const SvxFontItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ) );
2572 [ + - ][ + - ]: 42 : rFont.SetName( rFontItem.GetFamilyName() );
2573 [ + - ]: 42 : rFont.SetFamily( rFontItem.GetFamily() );
2574 [ + - ]: 42 : rFont.SetPitch( rFontItem.GetPitch() );
2575 [ + - ]: 42 : rFont.SetCharSet( rFontItem.GetCharSet() );
2576 [ + - ]: 42 : Size aSz( rFont.GetSize() );
2577 [ + - ][ + - ]: 42 : aSz.Height() = ((const SvxFontHeightItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ) ) ).GetHeight();
2578 [ + - ]: 42 : rFont.SetSize( aSz );
2579 [ + - ][ + - ]: 42 : rFont.SetWeight( ((const SvxWeightItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ))).GetWeight() );
[ + - ]
2580 [ + - ][ + - ]: 42 : rFont.SetItalic( ((const SvxPostureItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_ITALIC, nScriptType ))).GetPosture() );
[ + - ]
2581 [ + - ][ + - ]: 42 : rFont.SetLanguage( ((const SvxLanguageItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ))).GetLanguage() );
[ + - ]
2582 : : }
2583 : :
2584 : 653796 : sal_uInt16 nRelWidth = ((const SvxCharScaleWidthItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_FONTWIDTH)).GetValue();
2585 : :
2586 [ + + ]: 653796 : if ( pOut )
2587 : : {
2588 : 21118 : const SvxUnderlineItem& rTextLineColor = (const SvxUnderlineItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_UNDERLINE );
2589 [ + + ]: 21118 : if ( rTextLineColor.GetColor() != COL_TRANSPARENT )
2590 : 2662 : pOut->SetTextLineColor( rTextLineColor.GetColor() );
2591 : : else
2592 : 18456 : pOut->SetTextLineColor();
2593 : : }
2594 : :
2595 [ + + ]: 653796 : if ( pOut )
2596 : : {
2597 : 21118 : const SvxOverlineItem& rOverlineColor = (const SvxOverlineItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_OVERLINE );
2598 [ + + ]: 21118 : if ( rOverlineColor.GetColor() != COL_TRANSPARENT )
2599 : 2429 : pOut->SetOverlineColor( rOverlineColor.GetColor() );
2600 : : else
2601 : 18689 : pOut->SetOverlineColor();
2602 : : }
2603 : :
2604 : 653796 : const SvxLanguageItem* pCJKLanguageItem = NULL;
2605 : :
2606 [ + - ]: 653796 : if ( aStatus.UseCharAttribs() )
2607 : : {
2608 : 653796 : CharAttribList::AttribsType& rAttribs = pNode->GetCharAttribs().GetAttribs();
2609 : 653796 : size_t nAttr = 0;
2610 : 653796 : EditCharAttrib* pAttrib = GetAttrib(rAttribs, nAttr);
2611 [ + + ][ + + ]: 941215 : while ( pAttrib && ( pAttrib->GetStart() <= nPos ) )
[ + + ]
2612 : : {
2613 : : // when seeking, ignore attributes which start there! Empty attributes
2614 : : // are considered (used) as these are just set. But do not use empty
2615 : : // attributes: When just set and empty => no effect on font
2616 : : // In a blank paragraph, set characters take effect immediately.
2617 [ + - + + : 867423 : if ( ( pAttrib->Which() != nIgnoreWhich ) &&
+ + + + ]
[ + + ]
2618 : 553011 : ( ( ( pAttrib->GetStart() < nPos ) && ( pAttrib->GetEnd() >= nPos ) )
2619 : 26993 : || ( !pNode->Len() ) ) )
2620 : : {
2621 : : DBG_ASSERT( ( pAttrib->Which() >= EE_CHAR_START ) && ( pAttrib->Which() <= EE_FEATURE_END ), "Invalid Attribute in Seek() " );
2622 [ + + ]: 281982 : if ( IsScriptItemValid( pAttrib->Which(), nScriptType ) )
2623 : : {
2624 : 197153 : pAttrib->SetFont( rFont, pOut );
2625 : : // #i1550# hard color attrib should win over text color from field
2626 [ + + ]: 197153 : if ( pAttrib->Which() == EE_FEATURE_FIELD )
2627 : : {
2628 : 7680 : EditCharAttrib* pColorAttr = pNode->GetCharAttribs().FindAttrib( EE_CHAR_COLOR, nPos );
2629 [ + + ]: 7680 : if ( pColorAttr )
2630 : 504 : pColorAttr->SetFont( rFont, pOut );
2631 : : }
2632 : : }
2633 [ + + ]: 281982 : if ( pAttrib->Which() == EE_CHAR_FONTWIDTH )
2634 : 8959 : nRelWidth = ((const SvxCharScaleWidthItem*)pAttrib->GetItem())->GetValue();
2635 [ + + ]: 281982 : if ( pAttrib->Which() == EE_CHAR_LANGUAGE_CJK )
2636 : 8473 : pCJKLanguageItem = (const SvxLanguageItem*) pAttrib->GetItem();
2637 : : }
2638 : 287419 : pAttrib = GetAttrib( rAttribs, ++nAttr );
2639 : : }
2640 : : }
2641 : :
2642 [ + + ]: 653796 : if ( !pCJKLanguageItem )
2643 : 645323 : pCJKLanguageItem = (const SvxLanguageItem*) &pNode->GetContentAttribs().GetItem( EE_CHAR_LANGUAGE_CJK );
2644 : :
2645 : 653796 : rFont.SetCJKContextLanguage( pCJKLanguageItem->GetLanguage() );
2646 : :
2647 [ - + ][ # # ]: 653796 : if ( rFont.GetKerning() && IsKernAsianPunctuation() && ( nScriptType == i18n::ScriptType::ASIAN ) )
[ - + ][ + + ]
2648 : 0 : rFont.SetKerning( rFont.GetKerning() | KERNING_ASIAN );
2649 : :
2650 [ - + ]: 653796 : if ( aStatus.DoNotUseColors() )
2651 : : {
2652 [ # # ]: 0 : rFont.SetColor( /* rColorItem.GetValue() */ COL_BLACK );
2653 : : }
2654 : :
2655 [ + + ][ + + ]: 653796 : if ( aStatus.DoStretch() || ( nRelWidth != 100 ) )
[ + + ]
2656 : : {
2657 : : // For the current Output device, because otherwise if RefDev=Printer its looks
2658 : : // ugly on the screen!
2659 [ + + ]: 12197 : OutputDevice* pDev = pOut ? pOut : GetRefDevice();
2660 [ + - ]: 12197 : rFont.SetPhysFont( pDev );
2661 [ + - ]: 12197 : FontMetric aMetric( pDev->GetFontMetric() );
2662 : : // For the height do not consider the metrics, because it will go
2663 : : // wrong at Superscript/Subscript.
2664 [ + - ][ + - ]: 12197 : Size aRealSz( aMetric.GetSize().Width(), rFont.GetSize().Height() );
2665 [ + + ]: 12197 : if ( aStatus.DoStretch() )
2666 : : {
2667 [ - + ]: 682 : if ( nStretchY != 100 )
2668 : : {
2669 : 0 : aRealSz.Height() *= nStretchY;
2670 : 0 : aRealSz.Height() /= 100;
2671 : : }
2672 [ - + ]: 682 : if ( nStretchX != 100 )
2673 : : {
2674 [ # # ][ # # ]: 0 : if ( nStretchX == nStretchY &&
2675 : : nRelWidth == 100 )
2676 : : {
2677 : 0 : aRealSz.Width() = 0;
2678 : : }
2679 : : else
2680 : : {
2681 : 0 : aRealSz.Width() *= nStretchX;
2682 : 0 : aRealSz.Width() /= 100;
2683 : :
2684 : : // Also the Kerning: (long due to handle Interim results)
2685 : 0 : long nKerning = rFont.GetFixKerning();
2686 : : /*
2687 : : The consideration was: If negative kerning, but StretchX = 200
2688 : : => Do not double the kerning, thus pull the letters closer together
2689 : : ---------------------------
2690 : : Kern StretchX =>Kern
2691 : : ---------------------------
2692 : : >0 <100 < (Proportional)
2693 : : <0 <100 < (Proportional)
2694 : : >0 >100 > (Proportional)
2695 : : <0 >100 < (The amount, thus disproportional)
2696 : : */
2697 [ # # ][ # # ]: 0 : if ( ( nKerning < 0 ) && ( nStretchX > 100 ) )
2698 : : {
2699 : : // disproportional
2700 : 0 : nKerning *= 100;
2701 : 0 : nKerning /= nStretchX;
2702 : : }
2703 [ # # ]: 0 : else if ( nKerning )
2704 : : {
2705 : : // Proportional
2706 : 0 : nKerning *= nStretchX;
2707 : 0 : nKerning /= 100;
2708 : : }
2709 : 0 : rFont.SetFixKerning( (short)nKerning );
2710 : : }
2711 : : }
2712 : : }
2713 [ + + ]: 12197 : if ( nRelWidth != 100 )
2714 : : {
2715 : 11515 : aRealSz.Width() *= nRelWidth;
2716 : 11515 : aRealSz.Width() /= 100;
2717 : : }
2718 [ + - ][ + - ]: 12197 : rFont.SetSize( aRealSz );
2719 : : // Font is not restored ...
2720 : : }
2721 : :
2722 [ + - ][ + + ]: 653796 : if ( ( ( rFont.GetColor() == COL_AUTO ) || ( IsForceAutoColor() ) ) && pOut )
[ - + ][ + + ]
[ + - ]
[ + + # # ]
2723 : : {
2724 : : // #i75566# Do not use AutoColor when printing OR Pdf export
2725 : 14481 : const bool bPrinting(OUTDEV_PRINTER == pOut->GetOutDevType());
2726 : 14481 : const bool bPDFExporting(0 != pOut->GetPDFWriter());
2727 : :
2728 [ + - ][ + - ]: 14481 : if ( IsAutoColorEnabled() && !bPrinting && !bPDFExporting)
[ + - ][ + - ]
2729 : : {
2730 : : // Never use WindowTextColor on the printer
2731 [ + - ]: 14481 : rFont.SetColor( GetAutoColor() );
2732 : : }
2733 : : else
2734 : : {
2735 [ # # ][ # # ]: 0 : if ( ( GetBackgroundColor() != COL_AUTO ) && GetBackgroundColor().IsDark() )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # # #
# # # # ]
2736 [ # # ]: 0 : rFont.SetColor( COL_WHITE );
2737 : : else
2738 [ # # ]: 0 : rFont.SetColor( COL_BLACK );
2739 : : }
2740 : : }
2741 : :
2742 [ - + ][ # # ]: 653796 : if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetNode() == pNode ) &&
[ # # # #
# # ][ - + ]
2743 : 0 : ( nPos > mpIMEInfos->aPos.GetIndex() ) && ( nPos <= ( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ) ) )
2744 : : {
2745 : 0 : sal_uInt16 nAttr = mpIMEInfos->pAttribs[ nPos - mpIMEInfos->aPos.GetIndex() - 1 ];
2746 [ # # ]: 0 : if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE )
2747 : 0 : rFont.SetUnderline( UNDERLINE_SINGLE );
2748 [ # # ]: 0 : else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE )
2749 : 0 : rFont.SetUnderline( UNDERLINE_BOLD );
2750 [ # # ]: 0 : else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE )
2751 : 0 : rFont.SetUnderline( UNDERLINE_DOTTED );
2752 [ # # ]: 0 : else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE )
2753 : 0 : rFont.SetUnderline( UNDERLINE_DOTTED );
2754 [ # # ]: 0 : else if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT )
2755 [ # # ]: 0 : rFont.SetColor( Color( COL_RED ) );
2756 [ # # ]: 0 : else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT )
2757 [ # # ]: 0 : rFont.SetColor( Color( COL_LIGHTGRAY ) );
2758 [ # # ]: 0 : if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT )
2759 : : {
2760 : 0 : const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2761 : 0 : rFont.SetColor( rStyleSettings.GetHighlightTextColor() );
2762 : 0 : rFont.SetFillColor( rStyleSettings.GetHighlightColor() );
2763 : 0 : rFont.SetTransparent( sal_False );
2764 : : }
2765 [ # # ]: 0 : else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE )
2766 : : {
2767 : 0 : rFont.SetUnderline( UNDERLINE_WAVE );
2768 [ # # ]: 0 : if( pOut )
2769 [ # # ]: 0 : pOut->SetTextLineColor( Color( COL_LIGHTGRAY ) );
2770 : : }
2771 : : }
2772 : 653796 : }
2773 : :
2774 : 420740 : void ImpEditEngine::RecalcFormatterFontMetrics( FormatterFontMetric& rCurMetrics, SvxFont& rFont )
2775 : : {
2776 : : // for line height at high / low first without Propr!
2777 : 420740 : sal_uInt16 nPropr = rFont.GetPropr();
2778 : : DBG_ASSERT( ( nPropr == 100 ) || rFont.GetEscapement(), "Propr without Escape?!" );
2779 [ + + ]: 420740 : if ( nPropr != 100 )
2780 : : {
2781 : 3901 : rFont.SetPropr( 100 );
2782 [ + - ]: 3901 : rFont.SetPhysFont( pRefDev );
2783 : : }
2784 : : sal_uInt16 nAscent, nDescent;
2785 : :
2786 [ + - ]: 420740 : FontMetric aMetric( pRefDev->GetFontMetric() );
2787 [ + - ]: 420740 : nAscent = (sal_uInt16)aMetric.GetAscent();
2788 [ + + ]: 420740 : if ( IsAddExtLeading() )
2789 : : nAscent = sal::static_int_cast< sal_uInt16 >(
2790 [ + - ]: 303 : nAscent + aMetric.GetExtLeading() );
2791 [ + - ]: 420740 : nDescent = (sal_uInt16)aMetric.GetDescent();
2792 : :
2793 [ + + ]: 420740 : if ( IsFixedCellHeight() )
2794 : : {
2795 [ + - ]: 1146 : nAscent = sal::static_int_cast< sal_uInt16 >( rFont.GetHeight() );
2796 [ + - ]: 1146 : nDescent= sal::static_int_cast< sal_uInt16 >( ImplCalculateFontIndependentLineSpacing( rFont.GetHeight() ) - nAscent );
2797 : : }
2798 : : else
2799 : : {
2800 [ + - ][ + - ]: 419594 : sal_uInt16 nIntLeading = ( aMetric.GetIntLeading() > 0 ) ? (sal_uInt16)aMetric.GetIntLeading() : 0;
[ + - ]
2801 : : // Fonts without leading cause problems
2802 [ - + ][ # # ]: 419594 : if ( ( nIntLeading == 0 ) && ( pRefDev->GetOutDevType() == OUTDEV_PRINTER ) )
[ - + ]
2803 : : {
2804 : : // Lets see what Leading one gets on the screen
2805 [ # # ]: 0 : VirtualDevice* pVDev = GetVirtualDevice( pRefDev->GetMapMode(), pRefDev->GetDrawMode() );
2806 [ # # ]: 0 : rFont.SetPhysFont( pVDev );
2807 [ # # ][ # # ]: 0 : aMetric = pVDev->GetFontMetric();
[ # # ]
2808 : :
2809 : : // This is so that the Leading does not count itself out again,
2810 : : // if the whole line has the font, nTmpLeading.
2811 [ # # ]: 0 : nAscent = (sal_uInt16)aMetric.GetAscent();
2812 [ # # ]: 0 : nDescent = (sal_uInt16)aMetric.GetDescent();
2813 : : }
2814 : : }
2815 [ + + ]: 420740 : if ( nAscent > rCurMetrics.nMaxAscent )
2816 : 418794 : rCurMetrics.nMaxAscent = nAscent;
2817 [ + + ]: 420740 : if ( nDescent > rCurMetrics.nMaxDescent )
2818 : 418794 : rCurMetrics.nMaxDescent= nDescent;
2819 : : // Special treatment of high/low:
2820 [ + + ]: 420740 : if ( rFont.GetEscapement() )
2821 : : {
2822 : : // Now in consideration of Escape/Propr
2823 : : // possibly enlarge Ascent or Descent
2824 [ + - ]: 6006 : short nDiff = (short)(rFont.GetSize().Height()*rFont.GetEscapement()/100L);
2825 [ + - ]: 6006 : if ( rFont.GetEscapement() > 0 )
2826 : : {
2827 : 6006 : nAscent = (sal_uInt16) (((long)nAscent)*nPropr/100 + nDiff);
2828 [ + + ]: 6006 : if ( nAscent > rCurMetrics.nMaxAscent )
2829 : 2018 : rCurMetrics.nMaxAscent = nAscent;
2830 : : }
2831 : : else // has to be < 0
2832 : : {
2833 : 0 : nDescent = (sal_uInt16) (((long)nDescent)*nPropr/100 - nDiff);
2834 [ # # ]: 0 : if ( nDescent > rCurMetrics.nMaxDescent )
2835 : 0 : rCurMetrics.nMaxDescent= nDescent;
2836 : : }
2837 [ + - ]: 420740 : }
2838 : 420740 : }
2839 : :
2840 : 16003 : void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRec, Point aStartPos, sal_Bool bStripOnly, short nOrientation )
2841 : : {
2842 [ - + ][ # # ]: 16003 : if ( !GetUpdateMode() && !bStripOnly )
[ + - ]
2843 : : return;
2844 : :
2845 [ - + ]: 16003 : if ( !IsFormatted() )
2846 [ # # ]: 0 : FormatDoc();
2847 : :
2848 : 16003 : long nFirstVisXPos = - pOutDev->GetMapMode().GetOrigin().X();
2849 : 16003 : long nFirstVisYPos = - pOutDev->GetMapMode().GetOrigin().Y();
2850 : :
2851 : 16003 : const EditLine* pLine = NULL;
2852 : 16003 : Point aTmpPos;
2853 : 16003 : Point aRedLineTmpPos;
2854 : : DBG_ASSERT( GetParaPortions().Count(), "No ParaPortion?!" );
2855 [ + - ][ + - ]: 16003 : SvxFont aTmpFont( GetParaPortions()[0]->GetNode()->GetCharAttribs().GetDefFont() );
2856 [ + - ]: 16003 : Font aOldFont( pOutDev->GetFont() );
2857 [ - + ][ # # ]: 16003 : vcl::PDFExtOutDevData* pPDFExtOutDevData = PTR_CAST( vcl::PDFExtOutDevData, pOutDev->GetExtOutDevData() );
[ # # ][ # # ]
2858 : :
2859 : : // In the case of rotated text is aStartPos considered TopLeft because
2860 : : // other information is missing, and since the whole object is shown anyway
2861 : : // un-scrolled.
2862 : : // The rectangle is infinite.
2863 : 16003 : Point aOrigin( aStartPos );
2864 : 16003 : double nCos = 0.0, nSin = 0.0;
2865 [ + + ]: 16003 : if ( nOrientation )
2866 : : {
2867 : 659 : double nRealOrientation = nOrientation*F_PI1800;
2868 : 659 : nCos = cos( nRealOrientation );
2869 : 659 : nSin = sin( nRealOrientation );
2870 : : }
2871 : :
2872 : : // #110496# Added some more optional metafile comments. This
2873 : : // change: factored out some duplicated code.
2874 : 16003 : GDIMetaFile* pMtf = pOutDev->GetConnectMetaFile();
2875 : 16003 : const bool bMetafileValid( pMtf != NULL );
2876 : :
2877 [ + - ]: 16003 : long nVertLineSpacing = CalcVertLineSpacing(aStartPos);
2878 : :
2879 : : // --------------------------------------------------
2880 : : // Over all the paragraphs ...
2881 : : // --------------------------------------------------
2882 [ + - ][ + + ]: 33434 : for ( sal_uInt16 n = 0; n < GetParaPortions().Count(); n++ )
2883 : : {
2884 [ + - ]: 18187 : const ParaPortion* pPortion = GetParaPortions()[n];
2885 : : DBG_ASSERT( pPortion, "NULL-Pointer in TokenList in Paint" );
2886 : : // if when typing idle formatting, asynchronous Paint.
2887 : : // Invisible Portions may be invalid.
2888 [ + - ][ - + ]: 18187 : if ( pPortion->IsVisible() && pPortion->IsInvalid() )
[ - + ]
2889 : : return;
2890 : :
2891 [ - + ]: 18187 : if ( pPDFExtOutDevData )
2892 [ # # ]: 0 : pPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
2893 : :
2894 : 18187 : long nParaHeight = pPortion->GetHeight();
2895 [ + - ][ + - : 54561 : if ( pPortion->IsVisible() && (
+ - - + #
# # # ]
2896 : 36374 : ( !IsVertical() && ( ( aStartPos.Y() + nParaHeight ) > aClipRec.Top() ) ) ||
2897 : 0 : ( IsVertical() && ( ( aStartPos.X() - nParaHeight ) < aClipRec.Right() ) ) ) )
2898 : :
2899 : : {
2900 : : // --------------------------------------------------
2901 : : // Over the lines of the paragraph ...
2902 : : // --------------------------------------------------
2903 [ + - ]: 18187 : sal_uInt16 nLines = pPortion->GetLines().Count();
2904 : 18187 : sal_uInt16 nLastLine = nLines-1;
2905 : :
2906 [ + - ]: 18187 : if ( !IsVertical() )
2907 : 18187 : aStartPos.Y() += pPortion->GetFirstLineOffset();
2908 : : else
2909 : 0 : aStartPos.X() -= pPortion->GetFirstLineOffset();
2910 : :
2911 : 18187 : Point aParaStart( aStartPos );
2912 : :
2913 [ + - ]: 18187 : const SvxLineSpacingItem& rLSItem = ((const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ));
2914 : 18187 : sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX )
2915 [ + + ]: 18187 : ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
2916 [ + + ]: 38433 : for ( sal_uInt16 nLine = 0; nLine < nLines; nLine++ )
2917 : : {
2918 [ + - ]: 21002 : pLine = pPortion->GetLines()[nLine];
2919 : : DBG_ASSERT( pLine, "NULL-Pointer in the line iterator in UpdateViews" );
2920 : 21002 : aTmpPos = aStartPos;
2921 [ + - ]: 21002 : if ( !IsVertical() )
2922 : : {
2923 : 21002 : aTmpPos.X() += pLine->GetStartPosX();
2924 : 21002 : aTmpPos.Y() += pLine->GetMaxAscent();
2925 : 21002 : aStartPos.Y() += pLine->GetHeight();
2926 [ + + ]: 21002 : if (nLine != nLastLine)
2927 : 2815 : aStartPos.Y() += nVertLineSpacing;
2928 : : }
2929 : : else
2930 : : {
2931 : 0 : aTmpPos.Y() += pLine->GetStartPosX();
2932 : 0 : aTmpPos.X() -= pLine->GetMaxAscent();
2933 : 0 : aStartPos.X() -= pLine->GetHeight();
2934 [ # # ]: 0 : if (nLine != nLastLine)
2935 : 0 : aStartPos.X() -= nVertLineSpacing;
2936 : : }
2937 : :
2938 [ + - ][ - + : 21002 : if ( ( !IsVertical() && ( aStartPos.Y() > aClipRec.Top() ) )
# # # # ]
[ + - ]
2939 : 0 : || ( IsVertical() && aStartPos.X() < aClipRec.Right() ) )
2940 : : {
2941 : : // Why not just also call when stripping portions? This will give the correct values
2942 : : // and needs no position corrections in OutlinerEditEng::DrawingText which tries to call
2943 : : // PaintBullet correctly; exactly what GetEditEnginePtr()->PaintingFirstLine
2944 : : // does, too. No change for not-layouting (painting).
2945 [ + + ]: 21002 : if(0 == nLine) // && !bStripOnly)
2946 : : {
2947 [ + - ]: 18187 : GetEditEnginePtr()->PaintingFirstLine( n, aParaStart, aTmpPos.Y(), aOrigin, nOrientation, pOutDev );
2948 : : }
2949 : :
2950 : : // --------------------------------------------------
2951 : : // Over the Portions of the line ...
2952 : : // --------------------------------------------------
2953 : 21002 : sal_uInt16 nIndex = pLine->GetStart();
2954 : 21002 : bool bParsingFields = false;
2955 : 21002 : ::std::vector< sal_Int32 >::iterator itSubLines;
2956 [ + + ]: 42157 : for ( sal_uInt16 y = pLine->GetStartPortion(); y <= pLine->GetEndPortion(); y++ )
2957 : : {
2958 : : DBG_ASSERT( pPortion->GetTextPortions().Count(), "Line without Textportion in Paint!" );
2959 [ + - ]: 21155 : const TextPortion* pTextPortion = pPortion->GetTextPortions()[y];
2960 : : DBG_ASSERT( pTextPortion, "NULL-Pointer in Portion iterator in UpdateViews" );
2961 : :
2962 [ + - ]: 21155 : long nPortionXOffset = GetPortionXOffset( pPortion, pLine, y );
2963 [ + - ]: 21155 : if ( !IsVertical() )
2964 : : {
2965 : 21155 : aTmpPos.X() = aStartPos.X() + nPortionXOffset;
2966 [ + + ]: 21155 : if ( aTmpPos.X() > aClipRec.Right() )
2967 : 31 : break; // No further output in line necessary
2968 : : }
2969 : : else
2970 : : {
2971 : 0 : aTmpPos.Y() = aStartPos.Y() + nPortionXOffset;
2972 [ # # ]: 0 : if ( aTmpPos.Y() > aClipRec.Bottom() )
2973 : 0 : break; // No further output in line necessary
2974 : : }
2975 : :
2976 [ + - + ]: 21124 : switch ( pTextPortion->GetKind() )
2977 : : {
2978 : : case PORTIONKIND_TEXT:
2979 : : case PORTIONKIND_FIELD:
2980 : : case PORTIONKIND_HYPHENATOR:
2981 : : {
2982 [ + - ]: 21118 : SeekCursor( pPortion->GetNode(), nIndex+1, aTmpFont, pOutDev );
2983 : :
2984 : 21118 : sal_Bool bDrawFrame = sal_False;
2985 : :
2986 [ + + ][ + - ]: 42246 : if ( ( pTextPortion->GetKind() == PORTIONKIND_FIELD ) && !aTmpFont.IsTransparent() &&
[ + + + - ]
[ + + + -
+ - ][ + + ]
2987 [ + - ][ + + ]: 21126 : ( GetBackgroundColor() != COL_AUTO ) && GetBackgroundColor().IsDark() &&
[ + + ][ + + ]
[ # # # #
# # ]
2988 : 2 : ( IsAutoColorEnabled() && ( pOutDev->GetOutDevType() != OUTDEV_PRINTER ) ) )
2989 : : {
2990 [ + - ]: 1 : aTmpFont.SetTransparent( sal_True );
2991 [ + - ]: 1 : pOutDev->SetFillColor();
2992 [ + - ][ + - ]: 1 : pOutDev->SetLineColor( GetAutoColor() );
2993 : 1 : bDrawFrame = sal_True;
2994 : : }
2995 : :
2996 : : #if OSL_DEBUG_LEVEL > 2
2997 : : if ( pTextPortion->GetKind() == PORTIONKIND_HYPHENATOR )
2998 : : {
2999 : : aTmpFont.SetFillColor( COL_LIGHTGRAY );
3000 : : aTmpFont.SetTransparent( sal_False );
3001 : : }
3002 : : if ( pTextPortion->GetRightToLeft() )
3003 : : {
3004 : : aTmpFont.SetFillColor( COL_LIGHTGRAY );
3005 : : aTmpFont.SetTransparent( sal_False );
3006 : : }
3007 : : else if ( GetScriptType( EditPaM( pPortion->GetNode(), nIndex+1 ) ) == i18n::ScriptType::COMPLEX )
3008 : : {
3009 : : aTmpFont.SetFillColor( COL_LIGHTCYAN );
3010 : : aTmpFont.SetTransparent( sal_False );
3011 : : }
3012 : : #endif
3013 [ + - ]: 21118 : aTmpFont.SetPhysFont( pOutDev );
3014 : :
3015 : : // #114278# Saving both layout mode and language (since I'm
3016 : : // potentially changing both)
3017 [ + - ]: 21118 : pOutDev->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE );
3018 [ + - ]: 21118 : ImplInitLayoutMode( pOutDev, n, nIndex );
3019 [ + - ]: 21118 : ImplInitDigitMode( pOutDev, 0, 0, 0, aTmpFont.GetLanguage() );
3020 : :
3021 [ + - ]: 21118 : XubString aText;
3022 : 21118 : sal_uInt16 nTextStart = 0;
3023 : 21118 : sal_uInt16 nTextLen = 0;
3024 : 21118 : const sal_Int32* pDXArray = 0;
3025 : 21118 : sal_Int32* pTmpDXArray = 0;
3026 : :
3027 [ + + ]: 21118 : if ( pTextPortion->GetKind() == PORTIONKIND_TEXT )
3028 : : {
3029 [ + - ][ + - ]: 20016 : aText = pPortion->GetNode()->GetString();
3030 : 20016 : nTextStart = nIndex;
3031 : 20016 : nTextLen = pTextPortion->GetLen();
3032 [ + + ][ + - ]: 20016 : if (!pLine->GetCharPosArray().empty())
3033 [ + - ][ + - ]: 18588 : pDXArray = &pLine->GetCharPosArray()[0]+( nIndex-pLine->GetStart() );
3034 : :
3035 : : // Paint control characters (#i55716#)
3036 [ + + ]: 20016 : if ( aStatus.MarkFields() )
3037 : : {
3038 : : xub_StrLen nTmpIdx;
3039 : 2487 : const xub_StrLen nTmpEnd = nTextStart + pTextPortion->GetLen();
3040 : :
3041 [ + + ]: 11795 : for ( nTmpIdx = nTextStart; nTmpIdx <= nTmpEnd ; ++nTmpIdx )
3042 : : {
3043 : 9308 : const sal_Unicode cChar = ( nTmpIdx != aText.Len() && ( nTmpIdx != nTextStart || 0 == nTextStart ) ) ?
3044 : 6821 : aText.GetChar( nTmpIdx ) :
3045 [ + + ][ + + ]: 9308 : 0;
[ + + ]
3046 : :
3047 [ + - ][ - + ]: 9308 : if ( 0x200B == cChar || 0x2060 == cChar )
3048 : : {
3049 : 0 : const rtl::OUString aBlank( ' ' );
3050 [ # # ][ # # ]: 0 : long nHalfBlankWidth = aTmpFont.QuickGetTextSize( pOutDev, aBlank, 0, 1, 0 ).Width() / 2;
[ # # ]
3051 : :
3052 : : const long nAdvanceX = ( nTmpIdx == nTmpEnd ?
3053 [ # # ]: 0 : pTextPortion->GetSize().Width() :
3054 [ # # ]: 0 : pDXArray[ nTmpIdx - nTextStart ] ) - nHalfBlankWidth;
3055 : 0 : const long nAdvanceY = -pLine->GetMaxAscent();
3056 : :
3057 : 0 : Point aTopLeftRectPos( aTmpPos );
3058 [ # # ]: 0 : if ( !IsVertical() )
3059 : : {
3060 : 0 : aTopLeftRectPos.X() += nAdvanceX;
3061 : 0 : aTopLeftRectPos.Y() += nAdvanceY;
3062 : : }
3063 : : else
3064 : : {
3065 : 0 : aTopLeftRectPos.Y() += nAdvanceX;
3066 : 0 : aTopLeftRectPos.X() -= nAdvanceY;
3067 : : }
3068 : :
3069 : 0 : Point aBottomRightRectPos( aTopLeftRectPos );
3070 [ # # ]: 0 : if ( !IsVertical() )
3071 : : {
3072 : 0 : aBottomRightRectPos.X() += 2 * nHalfBlankWidth;
3073 : 0 : aBottomRightRectPos.Y() += pLine->GetHeight();
3074 : : }
3075 : : else
3076 : : {
3077 : 0 : aBottomRightRectPos.X() -= pLine->GetHeight();
3078 : 0 : aBottomRightRectPos.Y() += 2 * nHalfBlankWidth;
3079 : : }
3080 : :
3081 [ # # ]: 0 : pOutDev->Push( PUSH_FILLCOLOR );
3082 [ # # ]: 0 : pOutDev->Push( PUSH_LINECOLOR );
3083 [ # # ]: 0 : pOutDev->SetFillColor( COL_LIGHTGRAY );
3084 [ # # ]: 0 : pOutDev->SetLineColor( COL_LIGHTGRAY );
3085 : :
3086 [ # # ]: 0 : const Rectangle aBackRect( aTopLeftRectPos, aBottomRightRectPos );
3087 [ # # ]: 0 : pOutDev->DrawRect( aBackRect );
3088 : :
3089 [ # # ]: 0 : pOutDev->Pop();
3090 [ # # ]: 0 : pOutDev->Pop();
3091 : :
3092 [ # # ]: 0 : if ( 0x200B == cChar )
3093 : : {
3094 : 0 : const rtl::OUString aSlash( '/' );
3095 : 0 : const short nOldEscapement = aTmpFont.GetEscapement();
3096 : 0 : const sal_uInt8 nOldPropr = aTmpFont.GetPropr();
3097 : :
3098 : 0 : aTmpFont.SetEscapement( -20 );
3099 : 0 : aTmpFont.SetPropr( 25 );
3100 [ # # ]: 0 : aTmpFont.SetPhysFont( pOutDev );
3101 : :
3102 [ # # ][ # # ]: 0 : const Size aSlashSize = aTmpFont.QuickGetTextSize( pOutDev, aSlash, 0, 1, 0 );
[ # # ]
3103 : 0 : Point aSlashPos( aTmpPos );
3104 : 0 : const long nAddX = nHalfBlankWidth - aSlashSize.Width() / 2;
3105 [ # # ]: 0 : if ( !IsVertical() )
3106 : : {
3107 : 0 : aSlashPos.X() = aTopLeftRectPos.X() + nAddX;
3108 : : }
3109 : : else
3110 : : {
3111 : 0 : aSlashPos.Y() = aTopLeftRectPos.Y() + nAddX;
3112 : : }
3113 : :
3114 [ # # ][ # # ]: 0 : aTmpFont.QuickDrawText( pOutDev, aSlashPos, aSlash, 0, 1, 0 );
[ # # ]
3115 : :
3116 : 0 : aTmpFont.SetEscapement( nOldEscapement );
3117 : 0 : aTmpFont.SetPropr( nOldPropr );
3118 [ # # ]: 0 : aTmpFont.SetPhysFont( pOutDev );
3119 : 0 : }
3120 : : }
3121 : : }
3122 : : }
3123 : : }
3124 [ + + ]: 1102 : else if ( pTextPortion->GetKind() == PORTIONKIND_FIELD )
3125 : : {
3126 [ + - ]: 1014 : const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
3127 : : DBG_ASSERT( pAttr, "Field not found");
3128 : : DBG_ASSERT( pAttr && pAttr->GetItem()->ISA( SvxFieldItem ), "Field of the wrong type! ");
3129 [ + - ][ + - ]: 1014 : aText = ((EditCharAttribField*)pAttr)->GetFieldValue();
3130 : 1014 : nTextStart = 0;
3131 : 1014 : nTextLen = aText.Len();
3132 : 1014 : ExtraPortionInfo *pExtraInfo = pTextPortion->GetExtraInfos();
3133 : : // Do not split the Fields into different lines while editing
3134 [ + - ][ - + ]: 1014 : if( bStripOnly && !bParsingFields && pExtraInfo && pExtraInfo->lineBreaksList.size() )
[ # # ][ - + ]
[ + + ]
3135 : : {
3136 : 0 : bParsingFields = true;
3137 : 0 : itSubLines = pExtraInfo->lineBreaksList.begin();
3138 : : }
3139 [ - + ]: 1014 : if( bParsingFields )
3140 : : {
3141 [ # # ][ # # ]: 0 : if( itSubLines != pExtraInfo->lineBreaksList.begin() )
3142 : : {
3143 [ # # ]: 0 : if ( !IsVertical() )
3144 : : {
3145 : 0 : aStartPos.Y() += pLine->GetMaxAscent();
3146 : 0 : aTmpPos.Y() += pLine->GetHeight();
3147 : : }
3148 : : else
3149 : : {
3150 : 0 : aTmpPos.X() -= pLine->GetMaxAscent();
3151 : 0 : aStartPos.X() -= pLine->GetHeight();
3152 : : }
3153 : : }
3154 : 0 : ::std::vector< sal_Int32 >::iterator curIt = itSubLines;
3155 [ # # ]: 0 : ++itSubLines;
3156 [ # # ][ # # ]: 0 : if( itSubLines != pExtraInfo->lineBreaksList.end() )
3157 : : {
3158 [ # # ]: 0 : nTextStart = *curIt;
3159 [ # # ]: 0 : nTextLen = *itSubLines - nTextStart;
3160 : : }
3161 : : else
3162 : : {
3163 [ # # ]: 0 : nTextStart = *curIt;
3164 : 0 : nTextLen = nTextLen - nTextStart;
3165 : 0 : bParsingFields = false;
3166 : : }
3167 : : }
3168 : :
3169 [ + - ]: 1014 : pTmpDXArray = new sal_Int32[ aText.Len() ];
3170 : 1014 : pDXArray = pTmpDXArray;
3171 [ + - ]: 1014 : Font _aOldFont( GetRefDevice()->GetFont() );
3172 [ + - ]: 1014 : aTmpFont.SetPhysFont( GetRefDevice() );
3173 [ + - ]: 1014 : aTmpFont.QuickGetTextSize( GetRefDevice(), aText, nTextStart, nTextLen, pTmpDXArray );
3174 [ - + ]: 1014 : if ( aStatus.DoRestoreFont() )
3175 [ # # ]: 0 : GetRefDevice()->SetFont( _aOldFont );
3176 : :
3177 : : // add a meta file comment if we record to a metafile
3178 [ - + ]: 1014 : if( bMetafileValid )
3179 : : {
3180 [ # # ]: 0 : const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
3181 [ # # ]: 0 : if( pFieldItem )
3182 : : {
3183 : 0 : const SvxFieldData* pFieldData = pFieldItem->GetField();
3184 [ # # ]: 0 : if( pFieldData )
3185 [ # # ][ # # ]: 0 : pMtf->AddAction( pFieldData->createBeginComment() );
3186 : : }
3187 [ + - ]: 1014 : }
3188 : :
3189 : : }
3190 [ + - ]: 88 : else if ( pTextPortion->GetKind() == PORTIONKIND_HYPHENATOR )
3191 : : {
3192 [ - + ]: 88 : if ( pTextPortion->GetExtraValue() )
3193 [ # # ]: 0 : aText = pTextPortion->GetExtraValue();
3194 [ + - ]: 88 : aText += CH_HYPH;
3195 : 88 : nTextStart = 0;
3196 : 88 : nTextLen = aText.Len();
3197 : :
3198 : : // crash when accessing 0 pointer in pDXArray
3199 [ + - ]: 88 : pTmpDXArray = new sal_Int32[ aText.Len() ];
3200 : 88 : pDXArray = pTmpDXArray;
3201 [ + - ]: 88 : Font _aOldFont( GetRefDevice()->GetFont() );
3202 [ + - ]: 88 : aTmpFont.SetPhysFont( GetRefDevice() );
3203 [ + - ]: 88 : aTmpFont.QuickGetTextSize( GetRefDevice(), aText, 0, aText.Len(), pTmpDXArray );
3204 [ - + ]: 88 : if ( aStatus.DoRestoreFont() )
3205 [ # # ][ + - ]: 88 : GetRefDevice()->SetFont( _aOldFont );
3206 : : }
3207 : :
3208 : 21118 : long nTxtWidth = pTextPortion->GetSize().Width();
3209 : :
3210 : 21118 : Point aOutPos( aTmpPos );
3211 : 21118 : aRedLineTmpPos = aTmpPos;
3212 : : // In RTL portions spell markup pos should be at the start of the
3213 : : // first chara as well. That is on the right end of the portion
3214 [ - + ]: 21118 : if (pTextPortion->IsRightToLeft())
3215 : 0 : aRedLineTmpPos.X() += pTextPortion->GetSize().Width();
3216 : :
3217 [ + + ]: 21118 : if ( bStripOnly )
3218 : : {
3219 [ + - ]: 18034 : EEngineData::WrongSpellVector aWrongSpellVector;
3220 : :
3221 [ + + ][ + + ]: 18034 : if(GetStatus().DoOnlineSpelling() && pTextPortion->GetLen())
[ + + ]
3222 : : {
3223 : 5406 : WrongList* pWrongs = pPortion->GetNode()->GetWrongList();
3224 : :
3225 [ + - ][ - + ]: 5406 : if(pWrongs && !pWrongs->empty())
[ - + ][ + - ]
3226 : : {
3227 : 0 : sal_uInt16 nStart(nIndex);
3228 : 0 : sal_uInt16 nEnd(0);
3229 [ # # ]: 0 : sal_Bool bWrong(pWrongs->NextWrong(nStart, nEnd));
3230 : 0 : const sal_uInt16 nMaxEnd(nIndex + pTextPortion->GetLen());
3231 : :
3232 [ # # ]: 0 : while(bWrong)
3233 : : {
3234 [ # # ]: 0 : if(nStart >= nMaxEnd)
3235 : : {
3236 : 0 : break;
3237 : : }
3238 : :
3239 [ # # ]: 0 : if(nStart < nIndex)
3240 : : {
3241 : 0 : nStart = nIndex;
3242 : : }
3243 : :
3244 [ # # ]: 0 : if(nEnd > nMaxEnd)
3245 : : {
3246 : 0 : nEnd = nMaxEnd;
3247 : : }
3248 : :
3249 : : // add to vector
3250 [ # # ]: 0 : aWrongSpellVector.push_back(EEngineData::WrongSpellClass(nStart, nEnd));
3251 : :
3252 : : // goto next index
3253 : 0 : nStart = nEnd + 1;
3254 : :
3255 [ # # ]: 0 : if(nEnd < nMaxEnd)
3256 : : {
3257 [ # # ]: 0 : bWrong = pWrongs->NextWrong(nStart, nEnd);
3258 : : }
3259 : : else
3260 : : {
3261 : 0 : bWrong = sal_False;
3262 : : }
3263 : : }
3264 : : }
3265 : : }
3266 : :
3267 : 18034 : const SvxFieldData* pFieldData = 0;
3268 : :
3269 [ + + ]: 18034 : if(PORTIONKIND_FIELD == pTextPortion->GetKind())
3270 : : {
3271 [ + - ]: 888 : const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
3272 [ - + ]: 888 : const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
3273 : :
3274 [ + - ]: 888 : if(pFieldItem)
3275 : : {
3276 : 888 : pFieldData = pFieldItem->GetField();
3277 : : }
3278 : : }
3279 : :
3280 : : // support for EOC, EOW, EOS TEXT comments. To support that,
3281 : : // the locale is needed. With the locale and a XBreakIterator it is
3282 : : // possible to re-create the text marking info on primitive level
3283 [ + - ][ + - ]: 18034 : const lang::Locale aLocale(GetLocale(EditPaM(pPortion->GetNode(), nIndex + 1)));
3284 : :
3285 : : // create EOL and EOP bools
3286 : 18034 : const bool bEndOfLine(y == pLine->GetEndPortion());
3287 [ + + ][ + + ]: 18034 : const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines);
3288 : :
3289 : : // get Overline color (from ((const SvxOverlineItem*)GetItem())->GetColor() in
3290 : : // consequence, but also already set at pOutDev)
3291 : 18034 : const Color aOverlineColor(pOutDev->GetOverlineColor());
3292 : :
3293 : : // get TextLine color (from ((const SvxUnderlineItem*)GetItem())->GetColor() in
3294 : : // consequence, but also already set at pOutDev)
3295 : 18034 : const Color aTextLineColor(pOutDev->GetTextLineColor());
3296 : :
3297 : : // Unicode code points conversion according to ctl text numeral setting
3298 [ + - ]: 18034 : ImplInitDigitMode( 0, &aText, nTextStart, nTextLen, aTmpFont.GetLanguage() );
3299 : :
3300 : : // StripPortions() data callback
3301 : 18034 : GetEditEnginePtr()->DrawingText( aOutPos, aText, nTextStart, nTextLen, pDXArray,
3302 : 18034 : aTmpFont, n, nIndex, pTextPortion->GetRightToLeft(),
3303 : 18034 : aWrongSpellVector.size() ? &aWrongSpellVector : 0,
3304 : : pFieldData,
3305 : : bEndOfLine, bEndOfParagraph, false, // support for EOL/EOP TEXT comments
3306 : : &aLocale,
3307 : : aOverlineColor,
3308 [ + - ][ - + ]: 36068 : aTextLineColor);
3309 : : }
3310 : : else
3311 : : {
3312 : 3084 : short nEsc = aTmpFont.GetEscapement();
3313 [ + + ]: 3084 : if ( nOrientation )
3314 : : {
3315 : : // In case of high/low do it yourself:
3316 [ - + ]: 1390 : if ( aTmpFont.GetEscapement() )
3317 : : {
3318 [ # # ]: 0 : long nDiff = aTmpFont.GetSize().Height() * aTmpFont.GetEscapement() / 100L;
3319 [ # # ]: 0 : if ( !IsVertical() )
3320 : 0 : aOutPos.Y() -= nDiff;
3321 : : else
3322 : 0 : aOutPos.X() += nDiff;
3323 : 0 : aRedLineTmpPos = aOutPos;
3324 : 0 : aTmpFont.SetEscapement( 0 );
3325 : : }
3326 : :
3327 : 1390 : aOutPos = lcl_ImplCalcRotatedPos( aOutPos, aOrigin, nSin, nCos );
3328 [ + - ][ + - ]: 1390 : aTmpFont.SetOrientation( aTmpFont.GetOrientation()+nOrientation );
3329 [ + - ]: 1390 : aTmpFont.SetPhysFont( pOutDev );
3330 : :
3331 : : }
3332 : :
3333 : : // Take only what begins in the visible range:
3334 : : // Important, because of a bug in some graphic cards
3335 : : // when transparent font, output when negative
3336 [ + + ][ + - ]: 3084 : if ( nOrientation || ( !IsVertical() && ( ( aTmpPos.X() + nTxtWidth ) >= nFirstVisXPos ) )
[ - + # #
# # ][ + - ]
3337 : 0 : || ( IsVertical() && ( ( aTmpPos.Y() + nTxtWidth ) >= nFirstVisYPos ) ) )
3338 : : {
3339 [ + + ][ + - ]: 3084 : if ( nEsc && ( ( aTmpFont.GetUnderline() != UNDERLINE_NONE ) ) )
[ + + ][ + + ]
3340 : : {
3341 : : // Paint the high/low without underline,
3342 : : // Display the Underline on the
3343 : : // base line of the original font height ...
3344 : : // But only if there was something underlined before!
3345 : 69 : sal_Bool bSpecialUnderline = sal_False;
3346 [ + - ]: 69 : EditCharAttrib* pPrev = pPortion->GetNode()->GetCharAttribs().FindAttrib( EE_CHAR_ESCAPEMENT, nIndex );
3347 [ + - ]: 69 : if ( pPrev )
3348 : : {
3349 [ + - ]: 69 : SvxFont aDummy;
3350 : : // Underscore in front?
3351 [ - + ]: 69 : if ( pPrev->GetStart() )
3352 : : {
3353 [ # # ]: 0 : SeekCursor( pPortion->GetNode(), pPrev->GetStart(), aDummy );
3354 [ # # ][ # # ]: 0 : if ( aDummy.GetUnderline() != UNDERLINE_NONE )
3355 : 0 : bSpecialUnderline = sal_True;
3356 : : }
3357 [ + - ][ + - ]: 69 : if ( !bSpecialUnderline && ( pPrev->GetEnd() < pPortion->GetNode()->Len() ) )
[ - + ][ - + ]
3358 : : {
3359 [ # # ]: 0 : SeekCursor( pPortion->GetNode(), pPrev->GetEnd()+1, aDummy );
3360 [ # # ][ # # ]: 0 : if ( aDummy.GetUnderline() != UNDERLINE_NONE )
3361 : 0 : bSpecialUnderline = sal_True;
3362 [ + - ]: 69 : }
3363 : : }
3364 [ - + ]: 69 : if ( bSpecialUnderline )
3365 : : {
3366 [ # # ]: 0 : Size aSz = aTmpFont.GetPhysTxtSize( pOutDev, aText, nTextStart, nTextLen );
3367 : 0 : sal_uInt8 nProp = aTmpFont.GetPropr();
3368 : 0 : aTmpFont.SetEscapement( 0 );
3369 : 0 : aTmpFont.SetPropr( 100 );
3370 [ # # ]: 0 : aTmpFont.SetPhysFont( pOutDev );
3371 : 0 : rtl::OUStringBuffer aBlanks;
3372 [ # # ]: 0 : comphelper::string::padToLength( aBlanks, (sal_Int32) nTextLen, ' ' );
3373 : 0 : Point aUnderlinePos( aOutPos );
3374 [ # # ]: 0 : if ( nOrientation )
3375 : 0 : aUnderlinePos = lcl_ImplCalcRotatedPos( aTmpPos, aOrigin, nSin, nCos );
3376 [ # # ][ # # ]: 0 : pOutDev->DrawStretchText( aUnderlinePos, aSz.Width(), aBlanks.makeStringAndClear(), 0, nTextLen );
[ # # ][ # # ]
3377 : :
3378 [ # # ]: 0 : aTmpFont.SetUnderline( UNDERLINE_NONE );
3379 [ # # ]: 0 : if ( !nOrientation )
3380 : 0 : aTmpFont.SetEscapement( nEsc );
3381 : 0 : aTmpFont.SetPropr( nProp );
3382 [ # # ]: 0 : aTmpFont.SetPhysFont( pOutDev );
3383 : : }
3384 : : }
3385 : 3084 : Point aRealOutPos( aOutPos );
3386 [ + + - + : 6035 : if ( ( pTextPortion->GetKind() == PORTIONKIND_TEXT )
# # # # ]
[ - + ]
3387 : 2951 : && pTextPortion->GetExtraInfos() && pTextPortion->GetExtraInfos()->bCompressed
3388 : 0 : && pTextPortion->GetExtraInfos()->bFirstCharIsRightPunktuation )
3389 : : {
3390 : 0 : aRealOutPos.X() += pTextPortion->GetExtraInfos()->nPortionOffsetX;
3391 : : }
3392 : :
3393 : : // RTL portions with (#i37132#)
3394 : : // compressed blank should not paint this blank:
3395 [ - + ][ # # ]: 3084 : if ( pTextPortion->IsRightToLeft() && nTextLen >= 2 &&
[ # # # # ]
[ - + ]
3396 : 0 : pDXArray[ nTextLen - 1 ] ==
3397 : 0 : pDXArray[ nTextLen - 2 ] &&
3398 : 0 : ' ' == aText.GetChar( nTextStart + nTextLen - 1 ) )
3399 : 0 : --nTextLen;
3400 : :
3401 : : // output directly
3402 [ + - ]: 3084 : aTmpFont.QuickDrawText( pOutDev, aRealOutPos, aText, nTextStart, nTextLen, pDXArray );
3403 : :
3404 [ + + ]: 3084 : if ( bDrawFrame )
3405 : : {
3406 : 1 : Point aTopLeft( aTmpPos );
3407 : 1 : aTopLeft.Y() -= pLine->GetMaxAscent();
3408 [ - + ]: 1 : if ( nOrientation )
3409 : 0 : aTopLeft = lcl_ImplCalcRotatedPos( aTopLeft, aOrigin, nSin, nCos );
3410 [ + - ]: 1 : Rectangle aRect( aTopLeft, pTextPortion->GetSize() );
3411 [ + - ]: 1 : pOutDev->DrawRect( aRect );
3412 : : }
3413 : :
3414 : : // PDF export:
3415 [ - + ]: 3084 : if ( pPDFExtOutDevData )
3416 : : {
3417 [ # # ]: 0 : if ( pTextPortion->GetKind() == PORTIONKIND_FIELD )
3418 : : {
3419 [ # # ]: 0 : const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
3420 [ # # ]: 0 : const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
3421 [ # # ]: 0 : if( pFieldItem )
3422 : : {
3423 : 0 : const SvxFieldData* pFieldData = pFieldItem->GetField();
3424 [ # # ][ # # ]: 0 : if ( pFieldData->ISA( SvxURLField ) )
[ # # ]
3425 : : {
3426 : 0 : Point aTopLeft( aTmpPos );
3427 : 0 : aTopLeft.Y() -= pLine->GetMaxAscent();
3428 : :
3429 [ # # ]: 0 : Rectangle aRect( aTopLeft, pTextPortion->GetSize() );
3430 : 0 : vcl::PDFExtOutDevBookmarkEntry aBookmark;
3431 [ # # ]: 0 : aBookmark.nLinkId = pPDFExtOutDevData->CreateLink( aRect );
3432 : 0 : aBookmark.aBookmark = ((SvxURLField*)pFieldData)->GetURL();
3433 [ # # ]: 0 : std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks();
3434 [ # # ]: 3084 : rBookmarks.push_back( aBookmark );
3435 : : }
3436 : : }
3437 : : }
3438 : : }
3439 : : }
3440 : :
3441 [ + + ][ + - ]: 3084 : if ( GetStatus().DoOnlineSpelling() && !pPortion->GetNode()->GetWrongList()->empty() && pTextPortion->GetLen() )
[ + + ][ + + ]
[ + + ]
3442 : : {
3443 : : {//#105750# adjust LinePos for superscript or subscript text
3444 : 517 : short _nEsc = aTmpFont.GetEscapement();
3445 [ + + ]: 517 : if( _nEsc )
3446 : : {
3447 [ + - ]: 60 : long nShift = ((_nEsc*long(aTmpFont.GetSize().Height()))/ 100L);
3448 [ + - ]: 60 : if( !IsVertical() )
3449 : 60 : aRedLineTmpPos.Y() -= nShift;
3450 : : else
3451 : 0 : aRedLineTmpPos.X() += nShift;
3452 : : }
3453 : : }
3454 : 517 : Color aOldColor( pOutDev->GetLineColor() );
3455 [ + - ][ + - ]: 517 : pOutDev->SetLineColor( Color( GetColorConfig().GetColorValue( svtools::SPELL ).nColor ) );
[ + - ]
3456 [ + - ][ + - ]: 517 : lcl_DrawRedLines( pOutDev, aTmpFont.GetSize().Height(), aRedLineTmpPos, nIndex, nIndex + pTextPortion->GetLen(), pDXArray, pPortion->GetNode()->GetWrongList(), nOrientation, aOrigin, IsVertical(), pTextPortion->IsRightToLeft() );
3457 [ + - ]: 517 : pOutDev->SetLineColor( aOldColor );
3458 : : }
3459 : : }
3460 : :
3461 [ + - ]: 21118 : pOutDev->Pop();
3462 : :
3463 : : //The C++ language guarantees that delete p will do nothing if p is equal to NULL.
3464 [ + + ]: 21118 : delete[] pTmpDXArray;
3465 : :
3466 [ + + ]: 21118 : if ( pTextPortion->GetKind() == PORTIONKIND_FIELD )
3467 : : {
3468 [ + - ]: 1014 : const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
3469 : : DBG_ASSERT( pAttr, "Field not found" );
3470 : : DBG_ASSERT( pAttr && pAttr->GetItem()->ISA( SvxFieldItem ), "Wrong type of field!" );
3471 : :
3472 : : // add a meta file comment if we record to a metafile
3473 [ - + ]: 1014 : if( bMetafileValid )
3474 : : {
3475 [ # # ]: 0 : const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
3476 : :
3477 [ # # ]: 0 : if( pFieldItem )
3478 : : {
3479 : 0 : const SvxFieldData* pFieldData = pFieldItem->GetField();
3480 [ # # ]: 0 : if( pFieldData )
3481 [ # # ][ # # ]: 0 : pMtf->AddAction( pFieldData->createEndComment() );
3482 : : }
3483 : : }
3484 : :
3485 [ + - ]: 21118 : }
3486 : :
3487 : : }
3488 : 21118 : break;
3489 : : case PORTIONKIND_TAB:
3490 : : {
3491 [ # # ][ # # ]: 0 : if ( pTextPortion->GetExtraValue() && ( pTextPortion->GetExtraValue() != ' ' ) )
[ # # ]
3492 : : {
3493 [ # # ]: 0 : SeekCursor( pPortion->GetNode(), nIndex+1, aTmpFont, pOutDev );
3494 [ # # ]: 0 : aTmpFont.SetTransparent( sal_False );
3495 : 0 : aTmpFont.SetEscapement( 0 );
3496 [ # # ]: 0 : aTmpFont.SetPhysFont( pOutDev );
3497 : : long nCharWidth = aTmpFont.QuickGetTextSize( pOutDev,
3498 [ # # ][ # # ]: 0 : rtl::OUString(pTextPortion->GetExtraValue()), 0, 1, NULL ).Width();
[ # # ]
3499 : 0 : long nChars = 2;
3500 [ # # ]: 0 : if( nCharWidth )
3501 : 0 : nChars = pTextPortion->GetSize().Width() / nCharWidth;
3502 [ # # ]: 0 : if ( nChars < 2 )
3503 : 0 : nChars = 2; // is compressed by DrawStretchText.
3504 [ # # ]: 0 : else if ( nChars == 2 )
3505 : 0 : nChars = 3; // looks better
3506 : :
3507 [ # # ]: 0 : String aText;
3508 [ # # ]: 0 : aText.Fill( (sal_uInt16)nChars, pTextPortion->GetExtraValue() );
3509 [ # # ]: 0 : aTmpFont.QuickDrawText( pOutDev, aTmpPos, aText, 0, aText.Len(), NULL );
3510 [ # # ]: 0 : pOutDev->DrawStretchText( aTmpPos, pTextPortion->GetSize().Width(), aText );
3511 : :
3512 [ # # ]: 0 : if ( bStripOnly )
3513 : : {
3514 : : // create EOL and EOP bools
3515 : 0 : const bool bEndOfLine(y == pLine->GetEndPortion());
3516 [ # # ][ # # ]: 0 : const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines);
3517 : :
3518 : 0 : const Color aOverlineColor(pOutDev->GetOverlineColor());
3519 : 0 : const Color aTextLineColor(pOutDev->GetTextLineColor());
3520 : :
3521 : : // StripPortions() data callback
3522 : 0 : GetEditEnginePtr()->DrawingTab( aTmpPos,
3523 : 0 : pTextPortion->GetSize().Width(),
3524 : 0 : rtl::OUString(pTextPortion->GetExtraValue()),
3525 : 0 : aTmpFont, n, nIndex, pTextPortion->GetRightToLeft(),
3526 : : bEndOfLine, bEndOfParagraph,
3527 [ # # ]: 0 : aOverlineColor, aTextLineColor);
[ # # # # ]
3528 [ # # ]: 0 : }
3529 : : }
3530 [ # # ]: 0 : else if ( bStripOnly )
3531 : : {
3532 : : // #i108052# When stripping, a callback for _empty_ paragraphs is also needed.
3533 : : // This was optimized away (by not rendering the space-only tab portion), so do
3534 : : // it manually here.
3535 : 0 : const bool bEndOfLine(y == pLine->GetEndPortion());
3536 [ # # ][ # # ]: 0 : const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines);
3537 : :
3538 : 0 : const Color aOverlineColor(pOutDev->GetOverlineColor());
3539 : 0 : const Color aTextLineColor(pOutDev->GetTextLineColor());
3540 : :
3541 : 0 : GetEditEnginePtr()->DrawingText(
3542 : : aTmpPos, String(), 0, 0, 0,
3543 : : aTmpFont, n, nIndex, 0,
3544 : : 0,
3545 : : 0,
3546 : : bEndOfLine, bEndOfParagraph, false,
3547 : : 0,
3548 : : aOverlineColor,
3549 [ # # ][ # # ]: 0 : aTextLineColor);
[ # # ]
3550 : : }
3551 : : }
3552 : 0 : break;
3553 : : }
3554 [ - + ]: 21124 : if( bParsingFields )
3555 : 0 : y--;
3556 : : else
3557 : 21124 : nIndex = nIndex + pTextPortion->GetLen();
3558 : :
3559 : : }
3560 : : }
3561 : :
3562 [ + + ][ + - ]: 21002 : if ( ( nLine != nLastLine ) && !aStatus.IsOutliner() )
[ + + ]
3563 : : {
3564 [ + - ]: 2815 : if ( !IsVertical() )
3565 : 2815 : aStartPos.Y() += nSBL;
3566 : : else
3567 : 0 : aStartPos.X() -= nSBL;
3568 : : }
3569 : :
3570 : : // no more visible actions?
3571 [ + - ][ + + ]: 21002 : if ( !IsVertical() && ( aStartPos.Y() >= aClipRec.Bottom() ) )
[ + + ]
3572 : 756 : break;
3573 [ - + ][ # # ]: 20246 : else if ( IsVertical() && ( aStartPos.X() <= aClipRec.Left() ) )
[ - + ]
3574 : 0 : break;
3575 : : }
3576 : :
3577 [ + - ]: 18187 : if ( !aStatus.IsOutliner() )
3578 : : {
3579 [ + - ]: 18187 : const SvxULSpaceItem& rULItem = (const SvxULSpaceItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
3580 : 18187 : long nUL = GetYValue( rULItem.GetLower() );
3581 [ + - ]: 18187 : if ( !IsVertical() )
3582 : 18187 : aStartPos.Y() += nUL;
3583 : : else
3584 : 18187 : aStartPos.X() -= nUL;
3585 : : }
3586 : : }
3587 : : else
3588 : : {
3589 [ # # ]: 0 : if ( !IsVertical() )
3590 : 0 : aStartPos.Y() += nParaHeight;
3591 : : else
3592 : 0 : aStartPos.X() -= nParaHeight;
3593 : : }
3594 : :
3595 [ - + ]: 18187 : if ( pPDFExtOutDevData )
3596 [ # # ]: 0 : pPDFExtOutDevData->EndStructureElement();
3597 : :
3598 : : // no more visible actions?
3599 [ + - ][ + + ]: 18187 : if ( !IsVertical() && ( aStartPos.Y() > aClipRec.Bottom() ) )
[ + + ]
3600 : 756 : break;
3601 [ - + ][ # # ]: 17431 : if ( IsVertical() && ( aStartPos.X() < aClipRec.Left() ) )
[ - + ]
3602 : 0 : break;
3603 : : }
3604 [ - + ]: 16003 : if ( aStatus.DoRestoreFont() )
3605 [ # # ][ + - ]: 16003 : pOutDev->SetFont( aOldFont );
[ - + ][ + - ]
[ + - ]
3606 : : }
3607 : :
3608 : 791 : void ImpEditEngine::Paint( ImpEditView* pView, const Rectangle& rRec, sal_Bool bUseVirtDev )
3609 : : {
3610 : : DBG_ASSERT( pView, "No View - No Paint!" );
3611 : : DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 );
3612 : :
3613 [ + - ][ - + ]: 791 : if ( !GetUpdateMode() || IsInUndo() )
[ + - ]
3614 : : return;
3615 : :
3616 : : // Intersection of paint area and output area.
3617 : 791 : Rectangle aClipRec( pView->GetOutputArea() );
3618 [ + - ]: 791 : aClipRec.Intersection( rRec );
3619 : :
3620 : 791 : Window* pOutWin = pView->GetWindow();
3621 : :
3622 [ + + ]: 791 : if ( bUseVirtDev )
3623 : : {
3624 [ + - ]: 271 : Rectangle aClipRecPixel( pOutWin->LogicToPixel( aClipRec ) );
3625 [ + - ]: 271 : if ( !IsVertical() )
3626 : : {
3627 : : // etwas mehr, falls abgerundet!
3628 : 271 : aClipRecPixel.Right() += 1;
3629 : 271 : aClipRecPixel.Bottom() += 1;
3630 : : }
3631 : : else
3632 : : {
3633 : 0 : aClipRecPixel.Left() -= 1;
3634 : 0 : aClipRecPixel.Bottom() += 1;
3635 : : }
3636 : :
3637 : : // If aClipRecPixel > XXXX, then invalidate?!
3638 : :
3639 [ + - ]: 271 : VirtualDevice* pVDev = GetVirtualDevice( pOutWin->GetMapMode(), pOutWin->GetDrawMode() );
3640 [ + - ]: 271 : pVDev->SetDigitLanguage( GetRefDevice()->GetDigitLanguage() );
3641 : :
3642 : : {
3643 [ + - ]: 271 : Color aBackgroundColor( pView->GetBackgroundColor() );
3644 : : // #i47161# Check if text is visible on background
3645 [ + - ]: 271 : SvxFont aTmpFont;
3646 [ + - ]: 271 : ContentNode* pNode = GetEditDoc().GetObject( 0 );
3647 [ + - ]: 271 : SeekCursor( pNode, 1, aTmpFont );
3648 [ + - ]: 271 : Color aFontColor( aTmpFont.GetColor() );
3649 [ + + ][ - + ]: 271 : if( (aFontColor == COL_AUTO) || IsForceAutoColor() )
[ + - ][ + + ]
3650 [ + - ]: 66 : aFontColor = GetAutoColor();
3651 : :
3652 : : // #i69346# check for reverse color of input method attribute
3653 [ - + ][ # # ]: 271 : if( mpIMEInfos && (mpIMEInfos->aPos.GetNode() == pNode &&
[ # # ][ # # ]
[ - + ]
3654 : : mpIMEInfos->pAttribs))
3655 : : {
3656 : 0 : sal_uInt16 nAttr = mpIMEInfos->pAttribs[ 0 ];
3657 [ # # ]: 0 : if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT )
3658 : : {
3659 [ # # ]: 0 : const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
3660 : 0 : aFontColor = rStyleSettings.GetHighlightColor() ;
3661 : : }
3662 : : }
3663 : :
3664 [ + - ]: 271 : sal_uInt8 nColorDiff = aFontColor.GetColorError( aBackgroundColor );
3665 [ - + ]: 271 : if( nColorDiff < 8 )
3666 [ # # ][ # # ]: 0 : aBackgroundColor = aFontColor.IsDark() ? COL_WHITE : COL_BLACK;
3667 [ + - ][ + - ]: 271 : pVDev->SetBackground( aBackgroundColor );
[ + - ][ + - ]
3668 : : }
3669 : :
3670 : 271 : sal_Bool bVDevValid = sal_True;
3671 : 271 : Size aOutSz( pVDev->GetOutputSizePixel() );
3672 [ + + ][ - + ]: 319 : if ( ( aOutSz.Width() < aClipRecPixel.GetWidth() ) ||
[ + + ][ + - ]
3673 [ + - ]: 48 : ( aOutSz.Height() < aClipRecPixel.GetHeight() ) )
3674 : : {
3675 [ + - ][ + - ]: 223 : bVDevValid = pVDev->SetOutputSizePixel( aClipRecPixel.GetSize() );
3676 : : }
3677 : : else
3678 : : {
3679 : : // The VirtDev can become very big during a Resize =>
3680 : : // eventually make it smaller!
3681 [ + - ][ + - ]: 96 : if ( ( aOutSz.Height() > ( aClipRecPixel.GetHeight() + RESDIFF ) ) ||
[ - + ][ - + ]
3682 [ + - ]: 48 : ( aOutSz.Width() > ( aClipRecPixel.GetWidth() + RESDIFF ) ) )
3683 : : {
3684 [ # # ][ # # ]: 0 : bVDevValid = pVDev->SetOutputSizePixel( aClipRecPixel.GetSize() );
3685 : : }
3686 : : else
3687 : : {
3688 [ + - ]: 48 : pVDev->Erase();
3689 : : }
3690 : : }
3691 : : DBG_ASSERT( bVDevValid, "VDef could not be enlarged!" );
3692 [ - + ]: 271 : if ( !bVDevValid )
3693 : : {
3694 [ # # ]: 0 : Paint( pView, rRec, sal_False /* ohne VDev */ );
3695 : : return;
3696 : : }
3697 : :
3698 : : // PaintRect for VDev not with aligned size,
3699 : : // Otherwise, the line below must also be printed out:
3700 [ + - ][ + - ]: 271 : Rectangle aTmpRec( Point( 0, 0 ), aClipRec.GetSize() );
3701 : :
3702 [ + - ]: 271 : aClipRec = pOutWin->PixelToLogic( aClipRecPixel );
3703 : 271 : Point aStartPos;
3704 [ + - ]: 271 : if ( !IsVertical() )
3705 : : {
3706 : 271 : aStartPos = aClipRec.TopLeft();
3707 [ + - ]: 271 : aStartPos = pView->GetDocPos( aStartPos );
3708 : 271 : aStartPos.X() *= (-1);
3709 : 271 : aStartPos.Y() *= (-1);
3710 : : }
3711 : : else
3712 : : {
3713 [ # # ]: 0 : aStartPos = aClipRec.TopRight();
3714 [ # # ]: 0 : Point aDocPos( pView->GetDocPos( aStartPos ) );
3715 [ # # ]: 0 : aStartPos.X() = aClipRec.GetSize().Width() + aDocPos.Y();
3716 : 0 : aStartPos.Y() = -aDocPos.X();
3717 : : }
3718 : :
3719 [ + - ]: 271 : Paint( pVDev, aTmpRec, aStartPos );
3720 : :
3721 : 271 : sal_Bool bClipRegion = sal_False;
3722 [ + - ]: 271 : Region aOldRegion;
3723 [ + - ]: 271 : MapMode aOldMapMode;
3724 [ - + ]: 271 : if ( GetTextRanger() )
3725 : : {
3726 : : // Some problems here with push/pop, why?!
3727 : 0 : bClipRegion = pOutWin->IsClipRegion();
3728 [ # # ][ # # ]: 0 : aOldRegion = pOutWin->GetClipRegion();
[ # # ]
3729 : : // How do I get the polygon to the right place??
3730 : : // The polygon is based on the view, not the Window
3731 : : // => reset origin...
3732 [ # # ]: 0 : aOldMapMode = pOutWin->GetMapMode();
3733 : 0 : Point aOrigin = aOldMapMode.GetOrigin();
3734 : 0 : Point aViewPos = pView->GetOutputArea().TopLeft();
3735 : 0 : aOrigin.Move( aViewPos.X(), aViewPos.Y() );
3736 [ # # ]: 0 : aClipRec.Move( -aViewPos.X(), -aViewPos.Y() );
3737 [ # # ]: 0 : MapMode aNewMapMode( aOldMapMode );
3738 [ # # ]: 0 : aNewMapMode.SetOrigin( aOrigin );
3739 [ # # ]: 0 : pOutWin->SetMapMode( aNewMapMode );
3740 [ # # ][ # # ]: 0 : pOutWin->SetClipRegion( Region( GetTextRanger()->GetPolyPolygon() ) );
[ # # ][ # # ]
3741 : : }
3742 : :
3743 : : pOutWin->DrawOutDev( aClipRec.TopLeft(), aClipRec.GetSize(),
3744 [ + - ][ + - ]: 271 : Point(0,0), aClipRec.GetSize(), *pVDev );
[ + - ]
3745 : :
3746 [ - + ]: 271 : if ( GetTextRanger() )
3747 : : {
3748 [ # # ]: 0 : if ( bClipRegion )
3749 [ # # ]: 0 : pOutWin->SetClipRegion( aOldRegion );
3750 : : else
3751 [ # # ]: 0 : pOutWin->SetClipRegion();
3752 [ # # ]: 0 : pOutWin->SetMapMode( aOldMapMode );
3753 : : }
3754 : :
3755 : :
3756 [ + - ][ + - ]: 271 : pView->DrawSelection();
[ + - ]
3757 : : }
3758 : : else
3759 : : {
3760 : 520 : Point aStartPos;
3761 [ + - ]: 520 : if ( !IsVertical() )
3762 : : {
3763 : 520 : aStartPos = pView->GetOutputArea().TopLeft();
3764 : 520 : aStartPos.X() -= pView->GetVisDocLeft();
3765 : 520 : aStartPos.Y() -= pView->GetVisDocTop();
3766 : : }
3767 : : else
3768 : : {
3769 [ # # ]: 0 : aStartPos = pView->GetOutputArea().TopRight();
3770 : 0 : aStartPos.X() += pView->GetVisDocTop();
3771 : 0 : aStartPos.Y() -= pView->GetVisDocLeft();
3772 : : }
3773 : :
3774 : : // If Doc-width < Output Area,Width and not wrapped fields,
3775 : : // the fields usually protrude if > line.
3776 : : // (Not at the top, since there the Doc-width from formatting is already
3777 : : // there)
3778 [ + - ][ + - ]: 520 : if ( !IsVertical() && ( pView->GetOutputArea().GetWidth() > GetPaperSize().Width() ) )
[ - + ][ - + ]
3779 : : {
3780 : 0 : long nMaxX = pView->GetOutputArea().Left() + GetPaperSize().Width();
3781 [ # # ]: 0 : if ( aClipRec.Left() > nMaxX )
3782 : : return;
3783 [ # # ]: 0 : if ( aClipRec.Right() > nMaxX )
3784 : 0 : aClipRec.Right() = nMaxX;
3785 : : }
3786 : :
3787 : 520 : sal_Bool bClipRegion = pOutWin->IsClipRegion();
3788 [ + - ]: 520 : Region aOldRegion = pOutWin->GetClipRegion();
3789 [ + - ]: 520 : pOutWin->IntersectClipRegion( aClipRec );
3790 : :
3791 [ + - ]: 520 : Paint( pOutWin, aClipRec, aStartPos );
3792 : :
3793 [ - + ]: 520 : if ( bClipRegion )
3794 [ # # ]: 0 : pOutWin->SetClipRegion( aOldRegion );
3795 : : else
3796 [ + - ]: 520 : pOutWin->SetClipRegion();
3797 : :
3798 [ + - ][ + - ]: 791 : pView->DrawSelection();
3799 : : }
3800 : :
3801 : : }
3802 : :
3803 : 0 : void ImpEditEngine::InsertContent( ContentNode* pNode, sal_uInt16 nPos )
3804 : : {
3805 : : DBG_ASSERT( pNode, "NULL-Pointer in InsertContent! " );
3806 : : DBG_ASSERT( IsInUndo(), "InsertContent only for Undo()!" );
3807 [ # # ]: 0 : ParaPortion* pNew = new ParaPortion( pNode );
3808 : 0 : GetParaPortions().Insert(nPos, pNew);
3809 : 0 : aEditDoc.Insert(nPos, pNode);
3810 [ # # ]: 0 : if ( IsCallParaInsertedOrDeleted() )
3811 : 0 : GetEditEnginePtr()->ParagraphInserted( nPos );
3812 : 0 : }
3813 : :
3814 : 0 : EditPaM ImpEditEngine::SplitContent( sal_uInt16 nNode, sal_uInt16 nSepPos )
3815 : : {
3816 [ # # ]: 0 : ContentNode* pNode = aEditDoc.GetObject( nNode );
3817 : : DBG_ASSERT( pNode, "Invalid Node in SplitContent" );
3818 : : DBG_ASSERT( IsInUndo(), "SplitContent only for Undo()!" );
3819 : : DBG_ASSERT( nSepPos <= pNode->Len(), "Index out of range: SplitContent" );
3820 [ # # ]: 0 : EditPaM aPaM( pNode, nSepPos );
3821 [ # # ]: 0 : return ImpInsertParaBreak( aPaM );
3822 : : }
3823 : :
3824 : 0 : EditPaM ImpEditEngine::ConnectContents( sal_uInt16 nLeftNode, sal_Bool bBackward )
3825 : : {
3826 : 0 : ContentNode* pLeftNode = aEditDoc.GetObject( nLeftNode );
3827 : 0 : ContentNode* pRightNode = aEditDoc.GetObject( nLeftNode+1 );
3828 : : DBG_ASSERT( pLeftNode, "Invalid left node in ConnectContents ");
3829 : : DBG_ASSERT( pRightNode, "Invalid right node in ConnectContents ");
3830 : : DBG_ASSERT( IsInUndo(), "ConnectContent only for Undo()!" );
3831 : 0 : return ImpConnectParagraphs( pLeftNode, pRightNode, bBackward );
3832 : : }
3833 : :
3834 : 2206307 : void ImpEditEngine::SetUpdateMode( bool bUp, EditView* pCurView, sal_Bool bForceUpdate )
3835 : : {
3836 : 2206307 : bool bChanged = ( GetUpdateMode() != bUp );
3837 : :
3838 : : // When switching from sal_True to sal_False, all selections were visible,
3839 : : // => paint over
3840 : : // the other hand, were all invisible => paint
3841 : : // If !bFormatted, e.g. after SetText, then if UpdateMode=sal_True
3842 : : // formatting is not needed immediately, probably because more text is coming.
3843 : : // At latest it is formatted at a Paint/CalcTextWidth.
3844 : 2206307 : bUpdate = bUp;
3845 [ + + ][ + + ]: 2206307 : if ( bUpdate && ( bChanged || bForceUpdate ) )
[ + + ]
3846 : 305577 : FormatAndUpdate( pCurView );
3847 : 2206307 : }
3848 : :
3849 : 0 : void ImpEditEngine::ShowParagraph( sal_uInt16 nParagraph, bool bShow )
3850 : : {
3851 : 0 : ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
3852 : : DBG_ASSERT( pPPortion, "ShowParagraph: Paragraph does not exist! ");
3853 [ # # ][ # # ]: 0 : if ( pPPortion && ( pPPortion->IsVisible() != bShow ) )
[ # # ]
3854 : : {
3855 : 0 : pPPortion->SetVisible( bShow );
3856 : :
3857 [ # # ]: 0 : if ( !bShow )
3858 : : {
3859 : : // Mark as deleted, so that no selection will end or begin at
3860 : : // this paragraph...
3861 : 0 : DeletedNodeInfo* pDelInfo = new DeletedNodeInfo( (sal_uIntPtr)pPPortion->GetNode(), nParagraph );
3862 : 0 : aDeletedNodes.push_back(pDelInfo);
3863 : 0 : UpdateSelections();
3864 : : // The region below will not be invalidated if UpdateMode = sal_False!
3865 : : // If anyway, then save as sal_False before SetVisible !
3866 : : }
3867 : :
3868 [ # # ][ # # ]: 0 : if ( bShow && ( pPPortion->IsInvalid() || !pPPortion->nHeight ) )
[ # # ][ # # ]
3869 : : {
3870 [ # # ]: 0 : if ( !GetTextRanger() )
3871 : : {
3872 [ # # ]: 0 : if ( pPPortion->IsInvalid() )
3873 : : {
3874 [ # # ]: 0 : Font aOldFont( GetRefDevice()->GetFont() );
3875 [ # # ]: 0 : CreateLines( nParagraph, 0 ); // 0: No TextRanger
3876 [ # # ]: 0 : if ( aStatus.DoRestoreFont() )
3877 [ # # ][ # # ]: 0 : GetRefDevice()->SetFont( aOldFont );
3878 : : }
3879 : : else
3880 : : {
3881 : 0 : CalcHeight( pPPortion );
3882 : : }
3883 : 0 : nCurTextHeight += pPPortion->GetHeight();
3884 : : }
3885 : : else
3886 : : {
3887 : 0 : nCurTextHeight = 0x7fffffff;
3888 : : }
3889 : : }
3890 : :
3891 : 0 : pPPortion->SetMustRepaint( sal_True );
3892 [ # # ][ # # ]: 0 : if ( GetUpdateMode() && !IsInUndo() && !GetTextRanger() )
[ # # ][ # # ]
3893 : : {
3894 : 0 : aInvalidRec = Rectangle( Point( 0, GetParaPortions().GetYOffset( pPPortion ) ),
3895 [ # # ][ # # ]: 0 : Point( GetPaperSize().Width(), nCurTextHeight ) );
3896 : 0 : UpdateViews( GetActiveView() );
3897 : : }
3898 : : }
3899 : 0 : }
3900 : :
3901 : 0 : EditSelection ImpEditEngine::MoveParagraphs( Range aOldPositions, sal_uInt16 nNewPos, EditView* pCurView )
3902 : : {
3903 : : DBG_ASSERT( GetParaPortions().Count() != 0, "No paragraphs found: MoveParagraphs" );
3904 [ # # ][ # # ]: 0 : if ( GetParaPortions().Count() == 0 )
3905 [ # # ]: 0 : return EditSelection();
3906 : 0 : aOldPositions.Justify();
3907 : :
3908 [ # # ]: 0 : EditSelection aSel( ImpMoveParagraphs( aOldPositions, nNewPos ) );
3909 : :
3910 [ # # ][ # # ]: 0 : if ( nNewPos >= GetParaPortions().Count() )
3911 [ # # ]: 0 : nNewPos = GetParaPortions().Count() - 1;
3912 : :
3913 : : // Where the paragraph was inserted it has to be properly redrawn:
3914 : : // Where the paragraph was removed it has to be properly redrawn:
3915 : : // ( and correspondingly in between as well...)
3916 [ # # ][ # # ]: 0 : if ( pCurView && ( GetUpdateMode() == sal_True ) )
[ # # ]
3917 : : {
3918 : : // in this case one can redraw directly whithout invalidating the
3919 : : // Portions
3920 : 0 : sal_uInt16 nFirstPortion = Min( (sal_uInt16)aOldPositions.Min(), nNewPos );
3921 : 0 : sal_uInt16 nLastPortion = Max( (sal_uInt16)aOldPositions.Max(), nNewPos );
3922 : :
3923 [ # # ]: 0 : ParaPortion* pUpperPortion = GetParaPortions().SafeGetObject( nFirstPortion );
3924 [ # # ]: 0 : ParaPortion* pLowerPortion = GetParaPortions().SafeGetObject( nLastPortion );
3925 : :
3926 [ # # ]: 0 : aInvalidRec = Rectangle(); // make empty
3927 : 0 : aInvalidRec.Left() = 0;
3928 : 0 : aInvalidRec.Right() = aPaperSize.Width();
3929 [ # # ]: 0 : aInvalidRec.Top() = GetParaPortions().GetYOffset( pUpperPortion );
3930 [ # # ]: 0 : aInvalidRec.Bottom() = GetParaPortions().GetYOffset( pLowerPortion ) + pLowerPortion->GetHeight();
3931 : :
3932 [ # # ]: 0 : UpdateViews( pCurView );
3933 : : }
3934 : : else
3935 : : {
3936 : : // redraw from the upper invalid position
3937 : 0 : sal_uInt16 nFirstInvPara = Min( (sal_uInt16)aOldPositions.Min(), nNewPos );
3938 [ # # ]: 0 : InvalidateFromParagraph( nFirstInvPara );
3939 : : }
3940 [ # # ]: 0 : return aSel;
3941 : : }
3942 : :
3943 : 0 : void ImpEditEngine::InvalidateFromParagraph( sal_uInt16 nFirstInvPara )
3944 : : {
3945 : : // The following paragraphs are not invalidated, since ResetHeight()
3946 : : // => size change => all the following are re-issued anyway.
3947 : : ParaPortion* pTmpPortion;
3948 [ # # ]: 0 : if ( nFirstInvPara != 0 )
3949 : : {
3950 : 0 : pTmpPortion = GetParaPortions()[nFirstInvPara-1];
3951 : 0 : pTmpPortion->MarkInvalid( pTmpPortion->GetNode()->Len(), 0 );
3952 : : }
3953 : : else
3954 : : {
3955 : 0 : pTmpPortion = GetParaPortions()[0];
3956 : 0 : pTmpPortion->MarkSelectionInvalid( 0, pTmpPortion->GetNode()->Len() );
3957 : : }
3958 : 0 : pTmpPortion->ResetHeight();
3959 : 0 : }
3960 : :
3961 : 0 : IMPL_LINK_NOARG_INLINE_START(ImpEditEngine, StatusTimerHdl)
3962 : : {
3963 : 0 : CallStatusHdl();
3964 : 0 : return 0;
3965 : : }
3966 : 0 : IMPL_LINK_NOARG_INLINE_END(ImpEditEngine, StatusTimerHdl)
3967 : :
3968 : 647119 : void ImpEditEngine::CallStatusHdl()
3969 : : {
3970 [ + + ][ + + ]: 647119 : if ( aStatusHdlLink.IsSet() && aStatus.GetStatusWord() )
[ + + ]
3971 : : {
3972 : : // The Status has to be reset before the Call,
3973 : : // since other Flags might be set in the handler...
3974 : 3187 : EditStatus aTmpStatus( aStatus );
3975 : 3187 : aStatus.Clear();
3976 [ + - ]: 3187 : aStatusHdlLink.Call( &aTmpStatus );
3977 [ + - ]: 3187 : aStatusTimer.Stop(); // If called by hand ...
3978 : : }
3979 : 647119 : }
3980 : :
3981 : 0 : ContentNode* ImpEditEngine::GetPrevVisNode( ContentNode* pCurNode )
3982 : : {
3983 : 0 : const ParaPortion* pPortion = FindParaPortion( pCurNode );
3984 : : DBG_ASSERT( pPortion, "GetPrevVisibleNode: No matching portion!" );
3985 : 0 : pPortion = GetPrevVisPortion( pPortion );
3986 [ # # ]: 0 : if ( pPortion )
3987 : 0 : return pPortion->GetNode();
3988 : 0 : return 0;
3989 : : }
3990 : :
3991 : 0 : ContentNode* ImpEditEngine::GetNextVisNode( ContentNode* pCurNode )
3992 : : {
3993 : 0 : const ParaPortion* pPortion = FindParaPortion( pCurNode );
3994 : : DBG_ASSERT( pPortion, "GetNextVisibleNode: No matching portion!" );
3995 : 0 : pPortion = GetNextVisPortion( pPortion );
3996 [ # # ]: 0 : if ( pPortion )
3997 : 0 : return pPortion->GetNode();
3998 : 0 : return 0;
3999 : : }
4000 : :
4001 : 0 : const ParaPortion* ImpEditEngine::GetPrevVisPortion( const ParaPortion* pCurPortion ) const
4002 : : {
4003 : 0 : sal_uInt16 nPara = GetParaPortions().GetPos( pCurPortion );
4004 : : DBG_ASSERT( nPara < GetParaPortions().Count() , "Portion not found: GetPrevVisPortion" );
4005 [ # # ]: 0 : const ParaPortion* pPortion = nPara ? GetParaPortions()[--nPara] : 0;
4006 [ # # ][ # # ]: 0 : while ( pPortion && !pPortion->IsVisible() )
[ # # ]
4007 [ # # ]: 0 : pPortion = nPara ? GetParaPortions()[--nPara] : 0;
4008 : :
4009 : 0 : return pPortion;
4010 : : }
4011 : :
4012 : 0 : const ParaPortion* ImpEditEngine::GetNextVisPortion( const ParaPortion* pCurPortion ) const
4013 : : {
4014 : 0 : sal_uInt16 nPara = GetParaPortions().GetPos( pCurPortion );
4015 : : DBG_ASSERT( nPara < GetParaPortions().Count() , "Portion not found: GetPrevVisNode" );
4016 : 0 : const ParaPortion* pPortion = GetParaPortions().SafeGetObject( ++nPara );
4017 [ # # ][ # # ]: 0 : while ( pPortion && !pPortion->IsVisible() )
[ # # ]
4018 : 0 : pPortion = GetParaPortions().SafeGetObject( ++nPara );
4019 : :
4020 : 0 : return pPortion;
4021 : : }
4022 : :
4023 : 16003 : long ImpEditEngine::CalcVertLineSpacing(Point& rStartPos) const
4024 : : {
4025 : 16003 : long nTotalOccupiedHeight = 0;
4026 : 16003 : sal_uInt16 nTotalLineCount = 0;
4027 : 16003 : const ParaPortionList& rParaPortions = GetParaPortions();
4028 : 16003 : sal_uInt16 nParaCount = rParaPortions.Count();
4029 : :
4030 [ + + ]: 16120 : for (sal_uInt16 i = 0; i < nParaCount; ++i)
4031 : : {
4032 [ + + ]: 16003 : if (GetVerJustification(i) != SVX_VER_JUSTIFY_BLOCK)
4033 : : // All paragraphs must have the block justification set.
4034 : 15886 : return 0;
4035 : :
4036 : 117 : const ParaPortion* pPortion = rParaPortions[i];
4037 : 117 : nTotalOccupiedHeight += pPortion->GetFirstLineOffset();
4038 : :
4039 : 117 : const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem(EE_PARA_SBL);
4040 : 117 : sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX )
4041 [ - + ]: 117 : ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
4042 : :
4043 : 117 : const SvxULSpaceItem& rULItem = (const SvxULSpaceItem&)pPortion->GetNode()->GetContentAttribs().GetItem(EE_PARA_ULSPACE);
4044 : 117 : long nUL = GetYValue( rULItem.GetLower() );
4045 : :
4046 : 117 : const EditLineList& rLines = pPortion->GetLines();
4047 : 117 : sal_uInt16 nLineCount = rLines.Count();
4048 : 117 : nTotalLineCount += nLineCount;
4049 [ + + ]: 583 : for (sal_uInt16 j = 0; j < nLineCount; ++j)
4050 : : {
4051 : 466 : const EditLine* pLine = rLines[j];
4052 : 466 : nTotalOccupiedHeight += pLine->GetHeight();
4053 [ + + ]: 466 : if (j < nLineCount-1)
4054 : 349 : nTotalOccupiedHeight += nSBL;
4055 : 466 : nTotalOccupiedHeight += nUL;
4056 : : }
4057 : : }
4058 : :
4059 [ - + ]: 117 : long nTotalSpace = IsVertical() ? aPaperSize.Width() : aPaperSize.Height();
4060 : 117 : nTotalSpace -= nTotalOccupiedHeight;
4061 [ - + ][ # # ]: 117 : if (nTotalSpace <= 0 || nTotalLineCount <= 1)
4062 : 117 : return 0;
4063 : :
4064 [ # # ]: 0 : if (IsVertical())
4065 : : // Shift the text to the right for the asian layout mode.
4066 : 0 : rStartPos.X() += nTotalSpace;
4067 : :
4068 : 16003 : return nTotalSpace / (nTotalLineCount-1);
4069 : : }
4070 : :
4071 : 492 : EditPaM ImpEditEngine::InsertParagraph( sal_uInt16 nPara )
4072 : : {
4073 [ + - ]: 492 : EditPaM aPaM;
4074 [ + - ]: 492 : if ( nPara != 0 )
4075 : : {
4076 [ + - ]: 492 : ContentNode* pNode = GetEditDoc().GetObject( nPara-1 );
4077 [ - + ]: 492 : if ( !pNode )
4078 [ # # ][ # # ]: 0 : pNode = GetEditDoc().GetObject( GetEditDoc().Count() - 1 );
4079 : : DBG_ASSERT( pNode, "Not a single paragraph in InsertParagraph ?" );
4080 [ + - ][ + - ]: 492 : aPaM = EditPaM( pNode, pNode->Len() );
[ + - ]
4081 : : }
4082 : : else
4083 : : {
4084 [ # # ]: 0 : ContentNode* pNode = GetEditDoc().GetObject( 0 );
4085 [ # # ][ # # ]: 0 : aPaM = EditPaM( pNode, 0 );
4086 : : }
4087 : :
4088 [ + - ]: 492 : return ImpInsertParaBreak( aPaM );
4089 : : }
4090 : :
4091 : 23786 : EditSelection* ImpEditEngine::SelectParagraph( sal_uInt16 nPara )
4092 : : {
4093 : 23786 : EditSelection* pSel = 0;
4094 : 23786 : ContentNode* pNode = GetEditDoc().GetObject( nPara );
4095 : : DBG_ASSERTWARNING( pNode, "Paragraph does not exist: SelectParagraph" );
4096 [ + - ]: 23786 : if ( pNode )
4097 [ + - ][ + - ]: 23786 : pSel = new EditSelection( EditPaM( pNode, 0 ), EditPaM( pNode, pNode->Len() ) );
[ + - ][ + - ]
4098 : :
4099 : 23786 : return pSel;
4100 : : }
4101 : :
4102 : 1074774 : void ImpEditEngine::FormatAndUpdate( EditView* pCurView )
4103 : : {
4104 [ - + ]: 1074774 : if ( bDowning )
4105 : 1074774 : return ;
4106 : :
4107 [ - + ]: 1074774 : if ( IsInUndo() )
4108 : 0 : IdleFormatAndUpdate( pCurView );
4109 : : else
4110 : : {
4111 : 1074774 : FormatDoc();
4112 : 1074774 : UpdateViews( pCurView );
4113 : : }
4114 : : }
4115 : :
4116 : 0 : void ImpEditEngine::SetFlatMode( sal_Bool bFlat )
4117 : : {
4118 [ # # ]: 0 : if ( bFlat != aStatus.UseCharAttribs() )
4119 : 0 : return;
4120 : :
4121 [ # # ]: 0 : if ( !bFlat )
4122 : 0 : aStatus.TurnOnFlags( EE_CNTRL_USECHARATTRIBS );
4123 : : else
4124 : 0 : aStatus.TurnOffFlags( EE_CNTRL_USECHARATTRIBS );
4125 : :
4126 : 0 : aEditDoc.CreateDefFont( !bFlat );
4127 : :
4128 : 0 : FormatFullDoc();
4129 : 0 : UpdateViews( (EditView*) 0);
4130 [ # # ]: 0 : if ( pActiveView )
4131 : 0 : pActiveView->ShowCursor();
4132 : : }
4133 : :
4134 : 353541 : void ImpEditEngine::SetCharStretching( sal_uInt16 nX, sal_uInt16 nY )
4135 : : {
4136 : 353541 : bool bChanged(false);
4137 [ + - ]: 353541 : if ( !IsVertical() )
4138 : : {
4139 [ + - ][ - + ]: 353541 : bChanged = nStretchX!=nX || nStretchY!=nY;
4140 : 353541 : nStretchX = nX;
4141 : 353541 : nStretchY = nY;
4142 : : }
4143 : : else
4144 : : {
4145 [ # # ][ # # ]: 0 : bChanged = nStretchX!=nY || nStretchY!=nX;
4146 : 0 : nStretchX = nY;
4147 : 0 : nStretchY = nX;
4148 : : }
4149 : :
4150 [ - + ][ # # ]: 353541 : if (bChanged && aStatus.DoStretch())
[ - + ]
4151 : : {
4152 : 0 : FormatFullDoc();
4153 : : // (potentially) need everything redrawn
4154 : 0 : aInvalidRec=Rectangle(0,0,1000000,1000000);
4155 : 0 : UpdateViews( GetActiveView() );
4156 : : }
4157 : 353541 : }
4158 : :
4159 : 415076 : const SvxNumberFormat* ImpEditEngine::GetNumberFormat( const ContentNode *pNode ) const
4160 : : {
4161 : 415076 : const SvxNumberFormat *pRes = 0;
4162 : :
4163 [ + - ]: 415076 : if (pNode)
4164 : : {
4165 : : // get index of paragraph
4166 : 415076 : sal_uInt16 nPara = GetEditDoc().GetPos( const_cast< ContentNode * >(pNode) );
4167 : : DBG_ASSERT( nPara < USHRT_MAX, "node not found in array" );
4168 [ + - ]: 415076 : if (nPara < USHRT_MAX)
4169 : : {
4170 : : // the called function may be overloaded by an OutlinerEditEng object to provide
4171 : : // access to the SvxNumberFormat of the Outliner.
4172 : : // The EditEngine implementation will just return 0.
4173 : 415076 : pRes = pEditEngine->GetNumberFormat( nPara );
4174 : : }
4175 : : }
4176 : :
4177 : 415076 : return pRes;
4178 : : }
4179 : :
4180 : 415076 : sal_Int32 ImpEditEngine::GetSpaceBeforeAndMinLabelWidth(
4181 : : const ContentNode *pNode,
4182 : : sal_Int32 *pnSpaceBefore, sal_Int32 *pnMinLabelWidth ) const
4183 : : {
4184 : : // nSpaceBefore matches the ODF attribut text:space-before
4185 : : // nMinLabelWidth matches the ODF attribut text:min-label-width
4186 : :
4187 : 415076 : const SvxNumberFormat *pNumFmt = GetNumberFormat( pNode );
4188 : :
4189 : : // if no number format was found we have no Outliner or the numbering level
4190 : : // within the Outliner is -1 which means no number format should be applied.
4191 : : // Thus the default values to be returned are 0.
4192 : 415076 : sal_Int32 nSpaceBefore = 0;
4193 : 415076 : sal_Int32 nMinLabelWidth = 0;
4194 : :
4195 [ + + ]: 415076 : if (pNumFmt)
4196 : : {
4197 : 3045 : nMinLabelWidth = -pNumFmt->GetFirstLineOffset();
4198 : 3045 : nSpaceBefore = pNumFmt->GetAbsLSpace() - nMinLabelWidth;
4199 : : DBG_ASSERT( nMinLabelWidth >= 0, "ImpEditEngine::GetSpaceBeforeAndMinLabelWidth: min-label-width < 0 encountered" );
4200 : : }
4201 [ + + ]: 415076 : if (pnSpaceBefore)
4202 : 324600 : *pnSpaceBefore = nSpaceBefore;
4203 [ + + ]: 415076 : if (pnMinLabelWidth)
4204 : 114343 : *pnMinLabelWidth = nMinLabelWidth;
4205 : :
4206 : 415076 : return nSpaceBefore + nMinLabelWidth;
4207 : : }
4208 : :
4209 : 415076 : const SvxLRSpaceItem& ImpEditEngine::GetLRSpaceItem( ContentNode* pNode )
4210 : : {
4211 [ - + ]: 415076 : return (const SvxLRSpaceItem&)pNode->GetContentAttribs().GetItem( aStatus.IsOutliner() ? EE_PARA_OUTLLRSPACE : EE_PARA_LRSPACE );
4212 : : }
4213 : :
4214 : : // Either sets the digit mode at the output device or
4215 : : // modifies the passed string according to the text numeral setting:
4216 : 459980 : void ImpEditEngine::ImplInitDigitMode( OutputDevice* pOutDev, String* pString, xub_StrLen nStt, xub_StrLen nLen, LanguageType eCurLang )
4217 : : {
4218 : : // #114278# Also setting up digit language from Svt options
4219 : : // (cannot reliably inherit the outdev's setting)
4220 [ - + ]: 459980 : if( !pCTLOptions )
4221 [ # # ]: 0 : pCTLOptions = new SvtCTLOptions;
4222 : :
4223 : 459980 : LanguageType eLang = eCurLang;
4224 : 459980 : const SvtCTLOptions::TextNumerals nCTLTextNumerals = pCTLOptions->GetCTLTextNumerals();
4225 : :
4226 [ - + ]: 459980 : if ( SvtCTLOptions::NUMERALS_HINDI == nCTLTextNumerals )
4227 : 0 : eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
4228 [ + - ]: 459980 : else if ( SvtCTLOptions::NUMERALS_ARABIC == nCTLTextNumerals )
4229 : 459980 : eLang = LANGUAGE_ENGLISH;
4230 [ # # ]: 0 : else if ( SvtCTLOptions::NUMERALS_SYSTEM == nCTLTextNumerals )
4231 : 0 : eLang = (LanguageType) Application::GetSettings().GetLanguage();
4232 : :
4233 [ + + ]: 459980 : if(pOutDev)
4234 : : {
4235 : 441946 : pOutDev->SetDigitLanguage( eLang );
4236 : : }
4237 [ + - ]: 18034 : else if (pString)
4238 : : {
4239 : : // see sallayout.cxx in vcl
4240 : : int nOffset;
4241 [ + - - ]: 18034 : switch( eLang & LANGUAGE_MASK_PRIMARY )
4242 : : {
4243 : : default:
4244 : 18034 : nOffset = 0;
4245 : 18034 : break;
4246 : : case LANGUAGE_ARABIC_SAUDI_ARABIA & LANGUAGE_MASK_PRIMARY:
4247 : 0 : nOffset = 0x0660 - '0'; // arabic-indic digits
4248 : 0 : break;
4249 : : case LANGUAGE_URDU & LANGUAGE_MASK_PRIMARY:
4250 : : case LANGUAGE_PUNJABI & LANGUAGE_MASK_PRIMARY: //???
4251 : : case LANGUAGE_SINDHI & LANGUAGE_MASK_PRIMARY:
4252 : 0 : nOffset = 0x06F0 - '0'; // eastern arabic-indic digits
4253 : 0 : break;
4254 : : }
4255 [ - + ]: 18034 : if (nOffset)
4256 : : {
4257 : 0 : const xub_StrLen nEnd = nStt + nLen;
4258 [ # # ]: 0 : for( xub_StrLen nIdx = nStt; nIdx < nEnd; ++nIdx )
4259 : : {
4260 : 0 : sal_Unicode nChar = pString->GetChar( nIdx );
4261 [ # # ][ # # ]: 0 : if( (nChar < '0') || ('9' < nChar) )
4262 : 0 : continue;
4263 : 0 : nChar = (sal_Unicode)(nChar + nOffset);
4264 : 0 : pString->SetChar( nIdx, nChar );
4265 : : }
4266 : : }
4267 : : }
4268 : 459980 : }
4269 : :
4270 : 229472 : void ImpEditEngine::ImplInitLayoutMode( OutputDevice* pOutDev, sal_uInt16 nPara, sal_uInt16 nIndex )
4271 : : {
4272 : 229472 : sal_Bool bCTL = sal_False;
4273 : 229472 : sal_uInt8 bR2L = sal_False;
4274 [ + + ]: 229472 : if ( nIndex == 0xFFFF )
4275 : : {
4276 : 208354 : bCTL = HasScriptType( nPara, i18n::ScriptType::COMPLEX );
4277 : 208354 : bR2L = IsRightToLeft( nPara );
4278 : : }
4279 : : else
4280 : : {
4281 : 21118 : ContentNode* pNode = GetEditDoc().GetObject( nPara );
4282 [ + - ]: 21118 : short nScriptType = GetScriptType( EditPaM( pNode, nIndex+1 ) );
4283 : 21118 : bCTL = nScriptType == i18n::ScriptType::COMPLEX;
4284 : 21118 : bR2L = GetRightToLeft( nPara, nIndex + 1); // this change was discussed in issue 37190
4285 : : // it also works for issue 55927
4286 : : }
4287 : :
4288 : 229472 : sal_uLong nLayoutMode = pOutDev->GetLayoutMode();
4289 : :
4290 : : // We always use the left postion for DrawText()
4291 : 229472 : nLayoutMode &= ~(TEXT_LAYOUT_BIDI_RTL);
4292 : :
4293 [ + + ][ + - ]: 229472 : if ( !bCTL && !bR2L)
4294 : : {
4295 : : // No CTL/Bidi checking neccessary
4296 : 227024 : nLayoutMode |= ( TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG );
4297 : : }
4298 : : else
4299 : : {
4300 : : // CTL/Bidi checking neccessary
4301 : : // Don't use BIDI_STRONG, VCL must do some checks.
4302 : 2448 : nLayoutMode &= ~( TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG );
4303 : :
4304 [ + - ]: 2448 : if ( bR2L )
4305 : 2448 : nLayoutMode |= TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_TEXTORIGIN_LEFT;
4306 : : }
4307 : :
4308 : 229472 : pOutDev->SetLayoutMode( nLayoutMode );
4309 : :
4310 : : // #114278# Also setting up digit language from Svt options
4311 : : // (cannot reliably inherit the outdev's setting)
4312 : : LanguageType eLang;
4313 : :
4314 [ + + ]: 229472 : if( !pCTLOptions )
4315 [ + - ]: 4095 : pCTLOptions = new SvtCTLOptions;
4316 : :
4317 [ - + ]: 229472 : if ( SvtCTLOptions::NUMERALS_HINDI == pCTLOptions->GetCTLTextNumerals() )
4318 : 0 : eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
4319 [ + - ]: 229472 : else if ( SvtCTLOptions::NUMERALS_ARABIC == pCTLOptions->GetCTLTextNumerals() )
4320 : 229472 : eLang = LANGUAGE_ENGLISH;
4321 : : else
4322 : 0 : eLang = (LanguageType) Application::GetSettings().GetLanguage();
4323 : :
4324 : 229472 : pOutDev->SetDigitLanguage( eLang );
4325 : 229472 : }
4326 : :
4327 : 284090 : Reference < i18n::XBreakIterator > ImpEditEngine::ImplGetBreakIterator() const
4328 : : {
4329 [ + + ]: 284090 : if ( !xBI.is() )
4330 : : {
4331 [ + - ]: 20421 : Reference< lang::XMultiServiceFactory > xMSF( ::comphelper::getProcessServiceFactory() );
4332 [ + - ][ + - ]: 20421 : xBI.set( xMSF->createInstance( OUString( "com.sun.star.i18n.BreakIterator" ) ), UNO_QUERY );
[ + - ]
4333 : : }
4334 : 284090 : return xBI;
4335 : : }
4336 : :
4337 : 0 : Reference < i18n::XExtendedInputSequenceChecker > ImpEditEngine::ImplGetInputSequenceChecker() const
4338 : : {
4339 [ # # ]: 0 : if ( !xISC.is() )
4340 : : {
4341 [ # # ]: 0 : Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
4342 [ # # ][ # # ]: 0 : Reference < XInterface > xI = xMSF->createInstance( OUString( "com.sun.star.i18n.InputSequenceChecker" ) );
4343 [ # # ]: 0 : if ( xI.is() )
4344 : : {
4345 [ # # ][ # # ]: 0 : Any x = xI->queryInterface( ::getCppuType((const Reference< i18n::XExtendedInputSequenceChecker >*)0) );
[ # # ]
4346 [ # # ]: 0 : x >>= xISC;
4347 : 0 : }
4348 : : }
4349 : 0 : return xISC;
4350 : : }
4351 : :
4352 : 17004 : Color ImpEditEngine::GetAutoColor() const
4353 : : {
4354 : 17004 : Color aColor = const_cast<ImpEditEngine*>(this)->GetColorConfig().GetColorValue( svtools::FONTCOLOR ).nColor;
4355 : :
4356 [ + + ]: 17004 : if ( GetBackgroundColor() != COL_AUTO )
4357 : : {
4358 [ + - ][ + + ]: 6634 : if ( GetBackgroundColor().IsDark() && aColor.IsDark() )
[ + - ][ + - ]
[ + - ]
[ + + # # ]
4359 : 1 : aColor = COL_WHITE;
4360 [ + - ][ + + ]: 6633 : else if ( GetBackgroundColor().IsBright() && aColor.IsBright() )
[ + - ][ - + ]
[ + - ]
[ - + # # ]
4361 : 0 : aColor = COL_BLACK;
4362 : : }
4363 : :
4364 : 17004 : return aColor;
4365 : : }
4366 : :
4367 : :
4368 : 0 : sal_Bool ImpEditEngine::ImplCalcAsianCompression( ContentNode* pNode, TextPortion* pTextPortion, sal_uInt16 nStartPos, sal_Int32* pDXArray, sal_uInt16 n100thPercentFromMax, sal_Bool bManipulateDXArray )
4369 : : {
4370 : : DBG_ASSERT( GetAsianCompressionMode(), "ImplCalcAsianCompression - Why?" );
4371 : : DBG_ASSERT( pTextPortion->GetLen(), "ImplCalcAsianCompression - Empty Portion?" );
4372 : :
4373 : : // Percent is 1/100 Percent...
4374 [ # # ]: 0 : if ( n100thPercentFromMax == 10000 )
4375 : 0 : pTextPortion->SetExtraInfos( NULL );
4376 : :
4377 : 0 : sal_Bool bCompressed = sal_False;
4378 : :
4379 [ # # ][ # # ]: 0 : if ( GetScriptType( EditPaM( pNode, nStartPos+1 ) ) == i18n::ScriptType::ASIAN )
4380 : : {
4381 : 0 : long nNewPortionWidth = pTextPortion->GetSize().Width();
4382 : 0 : sal_uInt16 nPortionLen = pTextPortion->GetLen();
4383 [ # # ]: 0 : for ( sal_uInt16 n = 0; n < nPortionLen; n++ )
4384 : : {
4385 : 0 : sal_uInt8 nType = GetCharTypeForCompression( pNode->GetChar( n+nStartPos ) );
4386 : :
4387 [ # # ][ # # ]: 0 : sal_Bool bCompressPunctuation = ( nType == CHAR_PUNCTUATIONLEFT ) || ( nType == CHAR_PUNCTUATIONRIGHT );
4388 [ # # ][ # # ]: 0 : sal_Bool bCompressKana = ( nType == CHAR_KANA ) && ( GetAsianCompressionMode() == text::CharacterCompressionType::PUNCTUATION_AND_KANA );
4389 : :
4390 : : // create Extra infos only if needed...
4391 [ # # ][ # # ]: 0 : if ( bCompressPunctuation || bCompressKana )
4392 : : {
4393 [ # # ]: 0 : if ( !pTextPortion->GetExtraInfos() )
4394 : : {
4395 [ # # ]: 0 : ExtraPortionInfo* pExtraInfos = new ExtraPortionInfo;
4396 : 0 : pTextPortion->SetExtraInfos( pExtraInfos );
4397 : 0 : pExtraInfos->nOrgWidth = pTextPortion->GetSize().Width();
4398 : 0 : pExtraInfos->nAsianCompressionTypes = CHAR_NORMAL;
4399 : : }
4400 : 0 : pTextPortion->GetExtraInfos()->nMaxCompression100thPercent = n100thPercentFromMax;
4401 : 0 : pTextPortion->GetExtraInfos()->nAsianCompressionTypes |= nType;
4402 : :
4403 : : long nOldCharWidth;
4404 [ # # ]: 0 : if ( (n+1) < nPortionLen )
4405 : : {
4406 : 0 : nOldCharWidth = pDXArray[n];
4407 : : }
4408 : : else
4409 : : {
4410 [ # # ]: 0 : if ( bManipulateDXArray )
4411 : 0 : nOldCharWidth = nNewPortionWidth - pTextPortion->GetExtraInfos()->nPortionOffsetX;
4412 : : else
4413 : 0 : nOldCharWidth = pTextPortion->GetExtraInfos()->nOrgWidth;
4414 : : }
4415 [ # # ]: 0 : nOldCharWidth -= ( n ? pDXArray[n-1] : 0 );
4416 : :
4417 : 0 : long nCompress = 0;
4418 : :
4419 [ # # ]: 0 : if ( bCompressPunctuation )
4420 : : {
4421 : 0 : nCompress = nOldCharWidth / 2;
4422 : : }
4423 : : else // Kana
4424 : : {
4425 : 0 : nCompress = nOldCharWidth / 10;
4426 : : }
4427 : :
4428 [ # # ]: 0 : if ( n100thPercentFromMax != 10000 )
4429 : : {
4430 : 0 : nCompress *= n100thPercentFromMax;
4431 : 0 : nCompress /= 10000;
4432 : : }
4433 : :
4434 [ # # ]: 0 : if ( nCompress )
4435 : : {
4436 : 0 : bCompressed = sal_True;
4437 : 0 : nNewPortionWidth -= nCompress;
4438 : 0 : pTextPortion->GetExtraInfos()->bCompressed = sal_True;
4439 : :
4440 : :
4441 : : // Special handling for rightpunctuation: For the 'compression' we must
4442 : : // start the output before the normal char position....
4443 [ # # ][ # # ]: 0 : if ( bManipulateDXArray && ( pTextPortion->GetLen() > 1 ) )
[ # # ]
4444 : : {
4445 [ # # ]: 0 : if ( !pTextPortion->GetExtraInfos()->pOrgDXArray )
4446 : 0 : pTextPortion->GetExtraInfos()->SaveOrgDXArray( pDXArray, pTextPortion->GetLen()-1 );
4447 : :
4448 [ # # ]: 0 : if ( nType == CHAR_PUNCTUATIONRIGHT )
4449 : : {
4450 : : // If it's the first char, I must handle it in Paint()...
4451 [ # # ]: 0 : if ( n )
4452 : : {
4453 : : // -1: No entry for the last character
4454 [ # # ]: 0 : for ( sal_uInt16 i = n-1; i < (nPortionLen-1); i++ )
4455 : 0 : pDXArray[i] -= nCompress;
4456 : : }
4457 : : else
4458 : : {
4459 : 0 : pTextPortion->GetExtraInfos()->bFirstCharIsRightPunktuation = sal_True;
4460 : 0 : pTextPortion->GetExtraInfos()->nPortionOffsetX = -nCompress;
4461 : : }
4462 : : }
4463 : : else
4464 : : {
4465 : : // -1: No entry for the last character
4466 [ # # ]: 0 : for ( sal_uInt16 i = n; i < (nPortionLen-1); i++ )
4467 : 0 : pDXArray[i] -= nCompress;
4468 : : }
4469 : : }
4470 : : }
4471 : : }
4472 : : }
4473 : :
4474 [ # # ][ # # ]: 0 : if ( bCompressed && ( n100thPercentFromMax == 10000 ) )
4475 : 0 : pTextPortion->GetExtraInfos()->nWidthFullCompression = nNewPortionWidth;
4476 : :
4477 : 0 : pTextPortion->GetSize().Width() = nNewPortionWidth;
4478 : :
4479 [ # # ][ # # ]: 0 : if ( pTextPortion->GetExtraInfos() && ( n100thPercentFromMax != 10000 ) )
[ # # ]
4480 : : {
4481 : : // Maybe rounding errors in nNewPortionWidth, assure that width not bigger than expected
4482 : 0 : long nShrink = pTextPortion->GetExtraInfos()->nOrgWidth - pTextPortion->GetExtraInfos()->nWidthFullCompression;
4483 : 0 : nShrink *= n100thPercentFromMax;
4484 : 0 : nShrink /= 10000;
4485 : 0 : long nNewWidth = pTextPortion->GetExtraInfos()->nOrgWidth - nShrink;
4486 [ # # ]: 0 : if ( nNewWidth < pTextPortion->GetSize().Width() )
4487 : 0 : pTextPortion->GetSize().Width() = nNewWidth;
4488 : : }
4489 : : }
4490 : 0 : return bCompressed;
4491 : : }
4492 : :
4493 : :
4494 : 0 : void ImpEditEngine::ImplExpandCompressedPortions( EditLine* pLine, ParaPortion* pParaPortion, long nRemainingWidth )
4495 : : {
4496 : 0 : sal_Bool bFoundCompressedPortion = sal_False;
4497 : 0 : long nCompressed = 0;
4498 [ # # ]: 0 : std::vector<TextPortion*> aCompressedPortions;
4499 : :
4500 : 0 : sal_uInt16 nPortion = pLine->GetEndPortion();
4501 [ # # ]: 0 : TextPortion* pTP = pParaPortion->GetTextPortions()[ nPortion ];
4502 [ # # ][ # # ]: 0 : while ( pTP && ( pTP->GetKind() == PORTIONKIND_TEXT ) )
[ # # ]
4503 : : {
4504 [ # # ][ # # ]: 0 : if ( pTP->GetExtraInfos() && pTP->GetExtraInfos()->bCompressed )
[ # # ]
4505 : : {
4506 : 0 : bFoundCompressedPortion = sal_True;
4507 : 0 : nCompressed += pTP->GetExtraInfos()->nOrgWidth - pTP->GetSize().Width();
4508 [ # # ]: 0 : aCompressedPortions.push_back(pTP);
4509 : : }
4510 [ # # ][ # # ]: 0 : pTP = ( nPortion > pLine->GetStartPortion() ) ? pParaPortion->GetTextPortions()[ --nPortion ] : NULL;
4511 : : }
4512 : :
4513 [ # # ]: 0 : if ( bFoundCompressedPortion )
4514 : : {
4515 : 0 : long nCompressPercent = 0;
4516 [ # # ]: 0 : if ( nCompressed > nRemainingWidth )
4517 : : {
4518 : 0 : nCompressPercent = nCompressed - nRemainingWidth;
4519 : : DBG_ASSERT( nCompressPercent < 200000, "ImplExpandCompressedPortions - Overflow!" );
4520 : 0 : nCompressPercent *= 10000;
4521 : 0 : nCompressPercent /= nCompressed;
4522 : : }
4523 : :
4524 [ # # ]: 0 : for (size_t i = 0, n = aCompressedPortions.size(); i < n; ++i)
4525 : : {
4526 : 0 : pTP = aCompressedPortions[i];
4527 : 0 : pTP->GetExtraInfos()->bCompressed = sal_False;
4528 : 0 : pTP->GetSize().Width() = pTP->GetExtraInfos()->nOrgWidth;
4529 [ # # ]: 0 : if ( nCompressPercent )
4530 : : {
4531 [ # # ]: 0 : size_t nTxtPortion = pParaPortion->GetTextPortions().GetPos( pTP );
4532 [ # # ]: 0 : sal_uInt16 nTxtPortionStart = pParaPortion->GetTextPortions().GetStartPos( nTxtPortion );
4533 : : DBG_ASSERT( nTxtPortionStart >= pLine->GetStart(), "Portion doesn't belong to the line!!!" );
4534 : 0 : sal_Int32* pDXArray = NULL;
4535 [ # # ][ # # ]: 0 : if (!pLine->GetCharPosArray().empty())
4536 [ # # ][ # # ]: 0 : pDXArray = &pLine->GetCharPosArray()[0]+( nTxtPortionStart-pLine->GetStart() );
4537 [ # # ]: 0 : if ( pTP->GetExtraInfos()->pOrgDXArray )
4538 : 0 : memcpy( pDXArray, pTP->GetExtraInfos()->pOrgDXArray, (pTP->GetLen()-1)*sizeof(sal_Int32) );
4539 [ # # ]: 0 : ImplCalcAsianCompression( pParaPortion->GetNode(), pTP, nTxtPortionStart, pDXArray, (sal_uInt16)nCompressPercent, sal_True );
4540 : : }
4541 : : }
4542 : 0 : }
4543 : 0 : }
4544 : :
4545 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|