Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <hintids.hxx>
30 : :
31 : : #include <com/sun/star/i18n/ScriptType.hpp>
32 : : #include <editeng/twolinesitem.hxx>
33 : : #include <editeng/charrotateitem.hxx>
34 : : #include <vcl/outdev.hxx>
35 : : #include <fmtfld.hxx>
36 : : #include <fldbas.hxx> // SwField
37 : : #include <txatbase.hxx>
38 : : #include <fmtruby.hxx> // SwFmtRuby
39 : : #include <txtatr.hxx> // SwTxtRuby
40 : : #include <charfmt.hxx>
41 : : #include <txtinet.hxx>
42 : : #include <fchrfmt.hxx>
43 : : #include <layfrm.hxx> // GetUpper()
44 : : #include <SwPortionHandler.hxx>
45 : : #include <pormulti.hxx> // SwMultiPortion
46 : : #include <inftxt.hxx> // SwTxtSizeInfo
47 : : #include <itrpaint.hxx> // SwTxtPainter
48 : : #include <viewopt.hxx> // SwViewOptions
49 : : #include <itrform2.hxx> // SwTxtFormatter
50 : : #include <porfld.hxx> // SwFldPortion
51 : : #include <porglue.hxx>
52 : : #include <breakit.hxx>
53 : : #include <pagefrm.hxx>
54 : : #include <rowfrm.hxx>
55 : : #include <pagedesc.hxx> // SwPageDesc
56 : : #include <tgrditem.hxx>
57 : : #include <swtable.hxx>
58 : : #include <fmtfsize.hxx>
59 : :
60 : : using namespace ::com::sun::star;
61 : : extern sal_Bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt );
62 : :
63 : : /*--------------------------------------------------
64 : : * class SwMultiPortion
65 : : *
66 : : * A SwMultiPortion is not a simple portion,
67 : : * it's a container, which contains almost a SwLineLayoutPortion.
68 : : * This SwLineLayout could be followed by other textportions via pPortion
69 : : * and by another SwLineLayout via pNext to realize a doubleline portion.
70 : : * --------------------------------------------------*/
71 : :
72 [ + - ]: 356 : SwMultiPortion::~SwMultiPortion()
73 : : {
74 [ - + ][ # # ]: 356 : delete pFldRest;
75 [ - + ]: 356 : }
76 : :
77 : 0 : void SwMultiPortion::Paint( const SwTxtPaintInfo & ) const
78 : : {
79 : : OSL_FAIL( "Don't try SwMultiPortion::Paint, try SwTxtPainter::PaintMultiPortion" );
80 : 0 : }
81 : :
82 : : /*--------------------------------------------------
83 : : * Summarize the internal lines to calculate the (external) size.
84 : : * The internal line has to calculate first.
85 : : * --------------------------------------------------*/
86 : :
87 : 932 : void SwMultiPortion::CalcSize( SwTxtFormatter& rLine, SwTxtFormatInfo &rInf )
88 : : {
89 : 932 : Width( 0 );
90 : 932 : Height( 0 );
91 : 932 : SetAscent( 0 );
92 : 932 : SetFlyInCntnt( sal_False );
93 : 932 : SwLineLayout *pLay = &GetRoot();
94 [ + + ]: 1544 : do
95 : : {
96 : 1544 : pLay->CalcLine( rLine, rInf );
97 [ - + ]: 1544 : if( rLine.IsFlyInCntBase() )
98 : 0 : SetFlyInCntnt( sal_True );
99 [ + + ][ + + ]: 1544 : if( IsRuby() && ( OnTop() == ( pLay == &GetRoot() ) ) )
[ + + ]
100 : : {
101 : : // An empty phonetic line don't need an ascent or a height.
102 [ + + ]: 672 : if( !pLay->Width() )
103 : : {
104 : 56 : pLay->SetAscent( 0 );
105 : 56 : pLay->Height( 0 );
106 : : }
107 [ + + ]: 672 : if( OnTop() )
108 : 560 : SetAscent( GetAscent() + pLay->Height() );
109 : : }
110 : : else
111 : 872 : SetAscent( GetAscent() + pLay->GetAscent() );
112 : 1544 : Height( Height() + pLay->Height() );
113 [ + + ]: 1544 : if( Width() < pLay->Width() )
114 : 864 : Width( pLay->Width() );
115 : 1544 : pLay = pLay->GetNext();
116 : : } while ( pLay );
117 [ + + ]: 932 : if( HasBrackets() )
118 : : {
119 : 208 : KSHORT nTmp = ((SwDoubleLinePortion*)this)->GetBrackets()->nHeight;
120 [ + + ]: 208 : if( nTmp > Height() )
121 : : {
122 : 32 : KSHORT nAdd = ( nTmp - Height() ) / 2;
123 : 32 : GetRoot().SetAscent( GetRoot().GetAscent() + nAdd );
124 : 32 : GetRoot().Height( GetRoot().Height() + nAdd );
125 : 32 : Height( nTmp );
126 : : }
127 : 208 : nTmp = ((SwDoubleLinePortion*)this)->GetBrackets()->nAscent;
128 [ + + ]: 208 : if( nTmp > GetAscent() )
129 : 32 : SetAscent( nTmp );
130 : : }
131 : 932 : }
132 : :
133 : 0 : long SwMultiPortion::CalcSpacing( long , const SwTxtSizeInfo & ) const
134 : : {
135 : 0 : return 0;
136 : : }
137 : :
138 : 354 : sal_Bool SwMultiPortion::ChgSpaceAdd( SwLineLayout*, long ) const
139 : : {
140 : 354 : return sal_False;
141 : : }
142 : :
143 : : /*************************************************************************
144 : : * virtual SwMultiPortion::HandlePortion()
145 : : *************************************************************************/
146 : :
147 : 0 : void SwMultiPortion::HandlePortion( SwPortionHandler& rPH ) const
148 : : {
149 : 0 : rPH.Text( GetLen(), GetWhichPor() );
150 : 0 : }
151 : :
152 : : /*--------------------------------------------------
153 : : * SwMultiPortion::ActualizeTabulator()
154 : : * sets the tabulator-flag, if there's any tabulator-portion inside.
155 : : * --------------------------------------------------*/
156 : :
157 : 336 : void SwMultiPortion::ActualizeTabulator()
158 : : {
159 : 336 : SwLinePortion* pPor = GetRoot().GetFirstPortion();
160 : : // First line
161 [ + + ]: 672 : for( bTab1 = bTab2 = sal_False; pPor; pPor = pPor->GetPortion() )
162 [ - + ]: 336 : if( pPor->InTabGrp() )
163 : 0 : SetTab1( sal_True );
164 [ + - ]: 336 : if( GetRoot().GetNext() )
165 : : {
166 : : // Second line
167 : 336 : pPor = GetRoot().GetNext()->GetFirstPortion();
168 [ + + ]: 510 : do
169 : : {
170 [ - + ]: 510 : if( pPor->InTabGrp() )
171 : 0 : SetTab2( sal_True );
172 : 510 : pPor = pPor->GetPortion();
173 : : } while ( pPor );
174 : : }
175 : 336 : }
176 : :
177 : : /*--------------------------------------------------
178 : : * SwRotatedPortion::SwRotatedPortion(..)
179 : : * --------------------------------------------------*/
180 : :
181 : 0 : SwRotatedPortion::SwRotatedPortion( const SwMultiCreator& rCreate,
182 : 0 : xub_StrLen nEnd, sal_Bool bRTL ) : SwMultiPortion( nEnd )
183 : : {
184 : 0 : const SvxCharRotateItem* pRot = (SvxCharRotateItem*)rCreate.pItem;
185 [ # # ]: 0 : if( !pRot )
186 : : {
187 : 0 : const SwTxtAttr& rAttr = *rCreate.pAttr;
188 : : const SfxPoolItem *const pItem =
189 [ # # ]: 0 : CharFmt::GetItem(rAttr, RES_CHRATR_ROTATE);
190 [ # # ]: 0 : if ( pItem )
191 : : {
192 : 0 : pRot = static_cast<const SvxCharRotateItem*>(pItem);
193 : : }
194 : : }
195 [ # # ]: 0 : if( pRot )
196 : : {
197 : : sal_uInt8 nDir;
198 [ # # ]: 0 : if ( bRTL )
199 [ # # ]: 0 : nDir = pRot->IsBottomToTop() ? 3 : 1;
200 : : else
201 [ # # ]: 0 : nDir = pRot->IsBottomToTop() ? 1 : 3;
202 : :
203 : 0 : SetDirection( nDir );
204 : : }
205 : 0 : }
206 : :
207 : : /*---------------------------------------------------
208 : : * SwBidiPortion::SwBidiPortion(..)
209 : : * --------------------------------------------------*/
210 : :
211 : 0 : SwBidiPortion::SwBidiPortion( xub_StrLen nEnd, sal_uInt8 nLv )
212 : 0 : : SwMultiPortion( nEnd ), nLevel( nLv )
213 : : {
214 : 0 : SetBidi();
215 : :
216 [ # # ]: 0 : if ( nLevel % 2 )
217 : 0 : SetDirection( DIR_RIGHT2LEFT );
218 : : else
219 : 0 : SetDirection( DIR_LEFT2RIGHT );
220 : 0 : }
221 : :
222 : :
223 : 0 : long SwBidiPortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo& rInf ) const
224 : : {
225 [ # # ]: 0 : return HasTabulator() ? 0 : GetSpaceCnt(rInf) * nSpaceAdd / SPACING_PRECISION_FACTOR;
226 : : }
227 : :
228 : 0 : sal_Bool SwBidiPortion::ChgSpaceAdd( SwLineLayout* pCurr, long nSpaceAdd ) const
229 : : {
230 : 0 : sal_Bool bRet = sal_False;
231 [ # # ][ # # ]: 0 : if( !HasTabulator() && nSpaceAdd > 0 && !pCurr->IsSpaceAdd() )
[ # # ][ # # ]
232 : : {
233 : 0 : pCurr->CreateSpaceAdd();
234 : 0 : pCurr->SetLLSpaceAdd( nSpaceAdd, 0 );
235 : 0 : bRet = sal_True;
236 : : }
237 : :
238 : 0 : return bRet;
239 : : }
240 : :
241 : 0 : xub_StrLen SwBidiPortion::GetSpaceCnt( const SwTxtSizeInfo &rInf ) const
242 : : {
243 : : // Calculate number of blanks for justified alignment
244 : 0 : SwLinePortion* pPor = GetRoot().GetFirstPortion();
245 : 0 : xub_StrLen nTmpStart = rInf.GetIdx();
246 : 0 : xub_StrLen nNull = 0;
247 : : xub_StrLen nBlanks;
248 : :
249 [ # # ]: 0 : for( nBlanks = 0; pPor; pPor = pPor->GetPortion() )
250 : : {
251 [ # # ]: 0 : if( pPor->InTxtGrp() )
252 [ # # ]: 0 : nBlanks = nBlanks + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
253 [ # # # # ]: 0 : else if ( pPor->IsMultiPortion() &&
[ # # ]
254 : 0 : ((SwMultiPortion*)pPor)->IsBidi() )
255 [ # # ]: 0 : nBlanks = nBlanks + ((SwBidiPortion*)pPor)->GetSpaceCnt( rInf );
256 : :
257 : 0 : ((SwTxtSizeInfo &)rInf).SetIdx( rInf.GetIdx() + pPor->GetLen() );
258 : : }
259 : 0 : ((SwTxtSizeInfo &)rInf).SetIdx( nTmpStart );
260 : 0 : return nBlanks;
261 : : }
262 : :
263 : : /*--------------------------------------------------
264 : : * SwDoubleLinePortion::SwDoubleLinePortion(..)
265 : : * This constructor is for the continuation of a doubleline portion
266 : : * in the next line.
267 : : * It takes the same brackets and if the original has no content except
268 : : * brackets, these will be deleted.
269 : : * --------------------------------------------------*/
270 : :
271 : 0 : SwDoubleLinePortion::SwDoubleLinePortion( SwDoubleLinePortion& rDouble,
272 : : xub_StrLen nEnd ) :
273 : : SwMultiPortion( nEnd ),
274 : 0 : pBracket( 0 )
275 : : {
276 : 0 : SetDirection( rDouble.GetDirection() );
277 : 0 : SetDouble();
278 [ # # ]: 0 : if( rDouble.GetBrackets() )
279 : : {
280 [ # # ]: 0 : SetBrackets( rDouble );
281 : : // An empty multiportion needs no brackets.
282 : : // Notice: GetLen() might be zero, if the multiportion contains
283 : : // the second part of a field and the width might be zero, if
284 : : // it contains a note only. In this cases the brackets are okay.
285 : : // But if the length and the width are both zero, the portion
286 : : // is really empty.
287 [ # # ]: 0 : if( rDouble.Width() == rDouble.BracketWidth() )
288 : 0 : rDouble.ClearBrackets();
289 : : }
290 : 0 : }
291 : :
292 : : /*--------------------------------------------------
293 : : * SwDoubleLinePortion::SwDoubleLinePortion(..)
294 : : * This constructor uses the textattribut to get the right brackets.
295 : : * The textattribut could be a 2-line-attribute or a character- or
296 : : * internetstyle, which contains the 2-line-attribute.
297 : : * --------------------------------------------------*/
298 : :
299 : 20 : SwDoubleLinePortion::SwDoubleLinePortion( const SwMultiCreator& rCreate,
300 [ + - ]: 20 : xub_StrLen nEnd ) : SwMultiPortion( nEnd ), pBracket( new SwBracket() )
301 : : {
302 : 20 : SetDouble();
303 : 20 : const SvxTwoLinesItem* pTwo = (SvxTwoLinesItem*)rCreate.pItem;
304 [ - + ]: 20 : if( pTwo )
305 : 0 : pBracket->nStart = 0;
306 : : else
307 : : {
308 : 20 : const SwTxtAttr& rAttr = *rCreate.pAttr;
309 : 20 : pBracket->nStart = *rAttr.GetStart();
310 : :
311 : : const SfxPoolItem * const pItem =
312 [ + - ]: 20 : CharFmt::GetItem( rAttr, RES_CHRATR_TWO_LINES );
313 [ + - ]: 20 : if ( pItem )
314 : : {
315 : 20 : pTwo = static_cast<const SvxTwoLinesItem*>(pItem);
316 : : }
317 : : }
318 [ + - ]: 20 : if( pTwo )
319 : : {
320 : 20 : pBracket->cPre = pTwo->GetStartBracket();
321 : 20 : pBracket->cPost = pTwo->GetEndBracket();
322 : : }
323 : : else
324 : : {
325 : 0 : pBracket->cPre = 0;
326 : 0 : pBracket->cPost = 0;
327 : : }
328 : 20 : sal_uInt8 nTmp = SW_SCRIPTS;
329 [ - + ]: 20 : if( pBracket->cPre > 255 )
330 : : {
331 [ # # ]: 0 : String aTxt = rtl::OUString(pBracket->cPre);
332 [ # # ][ # # ]: 0 : nTmp = SwScriptInfo::WhichFont( 0, &aTxt, 0 );
333 : : }
334 : 20 : pBracket->nPreScript = nTmp;
335 : 20 : nTmp = SW_SCRIPTS;
336 [ - + ]: 20 : if( pBracket->cPost > 255 )
337 : : {
338 [ # # ]: 0 : String aTxt = rtl::OUString(pBracket->cPost);
339 [ # # ][ # # ]: 0 : nTmp = SwScriptInfo::WhichFont( 0, &aTxt, 0 );
340 : : }
341 : 20 : pBracket->nPostScript = nTmp;
342 : :
343 [ + + ][ + - ]: 20 : if( !pBracket->cPre && !pBracket->cPost )
344 : : {
345 : 4 : delete pBracket;
346 : 4 : pBracket = 0;
347 : : }
348 : :
349 : : // double line portions have the same direction as the frame directions
350 [ - + ]: 20 : if ( rCreate.nLevel % 2 )
351 : 0 : SetDirection( DIR_RIGHT2LEFT );
352 : : else
353 : 20 : SetDirection( DIR_LEFT2RIGHT );
354 : 20 : }
355 : :
356 : :
357 : : /*--------------------------------------------------
358 : : * SwMultiPortion::PaintBracket paints the wished bracket,
359 : : * if the multiportion has surrounding brackets.
360 : : * The X-position of the SwTxtPaintInfo will be modified:
361 : : * the open bracket sets position behind itself,
362 : : * the close bracket in front of itself.
363 : : * --------------------------------------------------*/
364 : :
365 : 40 : void SwDoubleLinePortion::PaintBracket( SwTxtPaintInfo &rInf,
366 : : long nSpaceAdd,
367 : : sal_Bool bOpen ) const
368 : : {
369 [ + + ]: 40 : sal_Unicode cCh = bOpen ? pBracket->cPre : pBracket->cPost;
370 [ + + ]: 40 : if( !cCh )
371 : : return;
372 [ + + ]: 36 : KSHORT nChWidth = bOpen ? PreWidth() : PostWidth();
373 [ + - ]: 36 : if( !nChWidth )
374 : : return;
375 [ + + ]: 36 : if( !bOpen )
376 : 16 : rInf.X( rInf.X() + Width() - PostWidth() +
377 [ # # ][ - + ]: 16 : ( nSpaceAdd > 0 ? CalcSpacing( nSpaceAdd, rInf ) : 0 ) );
378 : :
379 [ + - ]: 36 : SwBlankPortion aBlank( cCh, sal_True );
380 : 36 : aBlank.SetAscent( pBracket->nAscent );
381 : 36 : aBlank.Width( nChWidth );
382 : 36 : aBlank.Height( pBracket->nHeight );
383 : : {
384 [ + - ][ + - ]: 36 : SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
385 [ + + ]: 36 : sal_uInt8 nAct = bOpen ? pBracket->nPreScript : pBracket->nPostScript;
386 [ - + ]: 36 : if( SW_SCRIPTS > nAct )
387 : 0 : pTmpFnt->SetActual( nAct );
388 [ + - ]: 36 : pTmpFnt->SetProportion( 100 );
389 [ + - ]: 36 : SwFontSave aSave( rInf, pTmpFnt );
390 [ + - ]: 36 : aBlank.Paint( rInf );
391 [ + - ][ + - ]: 36 : delete pTmpFnt;
[ + - ]
392 : : }
393 [ + + ]: 36 : if( bOpen )
394 [ + - ]: 40 : rInf.X( rInf.X() + PreWidth() );
395 : : }
396 : :
397 : : /*--------------------------------------------------
398 : : * SwDoubleLinePortion::SetBrackets creates the bracket-structur
399 : : * and fills it, if not both characters are 0x00.
400 : : * --------------------------------------------------*/
401 : :
402 : 0 : void SwDoubleLinePortion::SetBrackets( const SwDoubleLinePortion& rDouble )
403 : : {
404 [ # # ]: 0 : if( rDouble.pBracket )
405 : : {
406 : 0 : pBracket = new SwBracket;
407 : 0 : pBracket->cPre = rDouble.pBracket->cPre;
408 : 0 : pBracket->cPost = rDouble.pBracket->cPost;
409 : 0 : pBracket->nPreScript = rDouble.pBracket->nPreScript;
410 : 0 : pBracket->nPostScript = rDouble.pBracket->nPostScript;
411 : 0 : pBracket->nStart = rDouble.pBracket->nStart;
412 : : }
413 : 0 : }
414 : :
415 : : /*--------------------------------------------------
416 : : * SwDoubleLinePortion::FormatBrackets
417 : : * calculates the size of the brackets => pBracket,
418 : : * reduces the nMaxWidth-parameter ( minus bracket-width )
419 : : * and moves the rInf-x-position behind the opening bracket.
420 : : * --------------------------------------------------*/
421 : :
422 : 16 : void SwDoubleLinePortion::FormatBrackets( SwTxtFormatInfo &rInf, SwTwips& nMaxWidth )
423 : : {
424 : 16 : nMaxWidth -= rInf.X();
425 [ + - ]: 16 : SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
426 : 16 : pTmpFnt->SetProportion( 100 );
427 : 16 : pBracket->nAscent = 0;
428 : 16 : pBracket->nHeight = 0;
429 [ + - ]: 16 : if( pBracket->cPre )
430 : : {
431 : 16 : rtl::OUString aStr( pBracket->cPre );
432 : 16 : sal_uInt8 nActualScr = pTmpFnt->GetActual();
433 [ - + ]: 16 : if( SW_SCRIPTS > pBracket->nPreScript )
434 : 0 : pTmpFnt->SetActual( pBracket->nPreScript );
435 [ + - ]: 16 : SwFontSave aSave( rInf, pTmpFnt );
436 [ + - ][ + - ]: 16 : SwPosSize aSize = rInf.GetTxtSize( aStr );
[ + - ]
437 [ + - ]: 16 : pBracket->nAscent = rInf.GetAscent();
438 : 16 : pBracket->nHeight = aSize.Height();
439 : 16 : pTmpFnt->SetActual( nActualScr );
440 [ + - ]: 16 : if( nMaxWidth > aSize.Width() )
441 : : {
442 : 16 : pBracket->nPreWidth = aSize.Width();
443 : 16 : nMaxWidth -= aSize.Width();
444 : 16 : rInf.X( rInf.X() + aSize.Width() );
445 : : }
446 : : else
447 : : {
448 : 0 : pBracket->nPreWidth = 0;
449 : 0 : nMaxWidth = 0;
450 [ + - ]: 16 : }
451 : : }
452 : : else
453 : 0 : pBracket->nPreWidth = 0;
454 [ + + ]: 16 : if( pBracket->cPost )
455 : : {
456 : 12 : rtl::OUString aStr( pBracket->cPost );
457 [ - + ]: 12 : if( SW_SCRIPTS > pBracket->nPostScript )
458 : 0 : pTmpFnt->SetActual( pBracket->nPostScript );
459 [ + - ]: 12 : SwFontSave aSave( rInf, pTmpFnt );
460 [ + - ][ + - ]: 12 : SwPosSize aSize = rInf.GetTxtSize( aStr );
[ + - ]
461 [ + - ]: 12 : KSHORT nTmpAsc = rInf.GetAscent();
462 [ - + ]: 12 : if( nTmpAsc > pBracket->nAscent )
463 : : {
464 : 0 : pBracket->nHeight += nTmpAsc - pBracket->nAscent;
465 : 0 : pBracket->nAscent = nTmpAsc;
466 : : }
467 [ - + ]: 12 : if( aSize.Height() > pBracket->nHeight )
468 : 0 : pBracket->nHeight = aSize.Height();
469 [ + - ]: 12 : if( nMaxWidth > aSize.Width() )
470 : : {
471 : 12 : pBracket->nPostWidth = aSize.Width();
472 : 12 : nMaxWidth -= aSize.Width();
473 : : }
474 : : else
475 : : {
476 : 0 : pBracket->nPostWidth = 0;
477 : 0 : nMaxWidth = 0;
478 [ + - ]: 12 : }
479 : : }
480 : : else
481 : 4 : pBracket->nPostWidth = 0;
482 : 16 : nMaxWidth += rInf.X();
483 : 16 : }
484 : :
485 : : /*--------------------------------------------------
486 : : * SwDoubleLinePortion::CalcBlanks
487 : : * calculates the number of blanks in each line and
488 : : * the difference of the width of the two lines.
489 : : * These results are used from the text adjustment.
490 : : * --------------------------------------------------*/
491 : :
492 : 20 : void SwDoubleLinePortion::CalcBlanks( SwTxtFormatInfo &rInf )
493 : : {
494 : 20 : SwLinePortion* pPor = GetRoot().GetFirstPortion();
495 : 20 : xub_StrLen nNull = 0;
496 : 20 : xub_StrLen nStart = rInf.GetIdx();
497 : 20 : SetTab1( sal_False );
498 : 20 : SetTab2( sal_False );
499 [ + + ]: 40 : for( nBlank1 = 0; pPor; pPor = pPor->GetPortion() )
500 : : {
501 [ + - ]: 20 : if( pPor->InTxtGrp() )
502 [ + - ]: 20 : nBlank1 = nBlank1 + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
503 : 20 : rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
504 [ - + ]: 20 : if( pPor->InTabGrp() )
505 : 0 : SetTab1( sal_True );
506 : : }
507 : 20 : nLineDiff = GetRoot().Width();
508 [ + - ]: 20 : if( GetRoot().GetNext() )
509 : : {
510 : 20 : pPor = GetRoot().GetNext()->GetFirstPortion();
511 : 20 : nLineDiff -= GetRoot().GetNext()->Width();
512 : : }
513 [ + + ]: 40 : for( nBlank2 = 0; pPor; pPor = pPor->GetPortion() )
514 : : {
515 [ + - ]: 20 : if( pPor->InTxtGrp() )
516 [ + - ]: 20 : nBlank2 = nBlank2 + ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nNull );
517 : 20 : rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
518 [ - + ]: 20 : if( pPor->InTabGrp() )
519 : 0 : SetTab2( sal_True );
520 : : }
521 : 20 : rInf.SetIdx( nStart );
522 : 20 : }
523 : :
524 : 0 : long SwDoubleLinePortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo & ) const
525 : : {
526 [ # # ]: 0 : return HasTabulator() ? 0 : GetSpaceCnt() * nSpaceAdd / SPACING_PRECISION_FACTOR;
527 : : }
528 : :
529 : : /*--------------------------------------------------
530 : : * SwDoubleLinePortion::ChangeSpaceAdd(..)
531 : : * merges the spaces for text adjustment from the inner and outer part.
532 : : * Inside the doubleline portion the wider line has no spaceadd-array, the
533 : : * smaller line has such an array to reach width of the wider line.
534 : : * If the surrounding line has text adjustment and the doubleline portion
535 : : * contains no tabulator, it is necessary to create/manipulate the inner
536 : : * space arrays.
537 : : * --------------------------------------------------*/
538 : :
539 : 78 : sal_Bool SwDoubleLinePortion::ChgSpaceAdd( SwLineLayout* pCurr,
540 : : long nSpaceAdd ) const
541 : : {
542 : 78 : sal_Bool bRet = sal_False;
543 [ + - ][ - + ]: 78 : if( !HasTabulator() && nSpaceAdd > 0 )
[ - + ]
544 : : {
545 [ # # ]: 0 : if( !pCurr->IsSpaceAdd() )
546 : : {
547 : : // The wider line gets the spaceadd from the surrounding line direct
548 : 0 : pCurr->CreateSpaceAdd();
549 : 0 : pCurr->SetLLSpaceAdd( nSpaceAdd, 0 );
550 : 0 : bRet = sal_True;
551 : : }
552 : : else
553 : : {
554 : 0 : xub_StrLen nMyBlank = GetSmallerSpaceCnt();
555 : 0 : xub_StrLen nOther = GetSpaceCnt();
556 [ # # ]: 0 : SwTwips nMultiSpace = pCurr->GetLLSpaceAdd( 0 ) * nMyBlank + nOther * nSpaceAdd;
557 : :
558 [ # # ]: 0 : if( nMyBlank )
559 : 0 : nMultiSpace /= nMyBlank;
560 : :
561 [ # # ]: 0 : if( nMultiSpace < KSHRT_MAX * SPACING_PRECISION_FACTOR )
562 : : {
563 : : // pCurr->SetLLSpaceAdd( nMultiSpace, 0 );
564 : : // #i65711# SetLLSpaceAdd replaces the first value,
565 : : // instead we want to insert a new first value:
566 : 0 : std::vector<long>* pVec = pCurr->GetpLLSpaceAdd();
567 [ # # ]: 0 : pVec->insert( pVec->begin(), nMultiSpace );
568 : 0 : bRet = sal_True;
569 : : }
570 : : }
571 : : }
572 : 78 : return bRet;
573 : : }
574 : : /*--------------------------------------------------
575 : : * SwDoubleLinePortion::ResetSpaceAdd(..)
576 : : * cancels the manipulation from SwDoubleLinePortion::ChangeSpaceAdd(..)
577 : : * --------------------------------------------------*/
578 : :
579 : 0 : void SwDoubleLinePortion::ResetSpaceAdd( SwLineLayout* pCurr )
580 : : {
581 : 0 : pCurr->RemoveFirstLLSpaceAdd();;
582 [ # # ]: 0 : if( !pCurr->GetLLSpaceAddCount() )
583 : 0 : pCurr->FinishSpaceAdd();
584 : 0 : }
585 : :
586 : 20 : SwDoubleLinePortion::~SwDoubleLinePortion()
587 : : {
588 : 20 : delete pBracket;
589 [ - + ]: 40 : }
590 : :
591 : : /*--------------------------------------------------
592 : : * SwRubyPortion::SwRubyPortion(..)
593 : : * constructs a ruby portion, i.e. an additional text is displayed
594 : : * beside the main text, e.g. phonetic characters.
595 : : * --------------------------------------------------*/
596 : :
597 : :
598 : 0 : SwRubyPortion::SwRubyPortion( const SwRubyPortion& rRuby, xub_StrLen nEnd ) :
599 : : SwMultiPortion( nEnd ),
600 : 0 : nRubyOffset( rRuby.GetRubyOffset() ),
601 : 0 : nAdjustment( rRuby.GetAdjustment() )
602 : : {
603 : 0 : SetDirection( rRuby.GetDirection() ),
604 : 0 : SetTop( rRuby.OnTop() );
605 : 0 : SetRuby();
606 : 0 : }
607 : :
608 : : /*--------------------------------------------------
609 : : * SwRubyPortion::SwRubyPortion(..)
610 : : * constructs a ruby portion, i.e. an additional text is displayed
611 : : * beside the main text, e.g. phonetic characters.
612 : : * --------------------------------------------------*/
613 : :
614 : 336 : SwRubyPortion::SwRubyPortion( const SwMultiCreator& rCreate, const SwFont& rFnt,
615 : : const IDocumentSettingAccess& rIDocumentSettingAccess,
616 : : xub_StrLen nEnd, xub_StrLen nOffs,
617 : : const sal_Bool* pForceRubyPos )
618 : 336 : : SwMultiPortion( nEnd )
619 : : {
620 : 336 : SetRuby();
621 : : OSL_ENSURE( SW_MC_RUBY == rCreate.nId, "Ruby expected" );
622 : : OSL_ENSURE( RES_TXTATR_CJK_RUBY == rCreate.pAttr->Which(), "Wrong attribute" );
623 : 336 : const SwFmtRuby& rRuby = rCreate.pAttr->GetRuby();
624 : 336 : nAdjustment = rRuby.GetAdjustment();
625 : 336 : nRubyOffset = nOffs;
626 : :
627 : : // in grid mode we force the ruby text to the upper or lower line
628 [ - + ]: 336 : if ( pForceRubyPos )
629 : 0 : SetTop( *pForceRubyPos );
630 : : else
631 : 336 : SetTop( ! rRuby.GetPosition() );
632 : :
633 [ + - ]: 336 : const SwCharFmt* pFmt = ((SwTxtRuby*)rCreate.pAttr)->GetCharFmt();
634 : : SwFont *pRubyFont;
635 [ + - ]: 336 : if( pFmt )
636 : : {
637 : 336 : const SwAttrSet& rSet = pFmt->GetAttrSet();
638 [ + - ][ + - ]: 336 : pRubyFont = new SwFont( rFnt );
639 [ + - ]: 336 : pRubyFont->SetDiffFnt( &rSet, &rIDocumentSettingAccess );
640 : :
641 : : // we do not allow a vertical font for the ruby text
642 [ + - ][ + - ]: 336 : pRubyFont->SetVertical( rFnt.GetOrientation() );
643 : : }
644 : : else
645 : 0 : pRubyFont = NULL;
646 : :
647 [ + - ]: 336 : String aStr( rRuby.GetText(), nOffs, STRING_LEN );
648 [ + - ][ + - ]: 336 : SwFldPortion *pFld = new SwFldPortion( aStr, pRubyFont );
649 : 336 : pFld->SetNextOffset( nOffs );
650 : 336 : pFld->SetFollow( sal_True );
651 : :
652 [ + + ]: 336 : if( OnTop() )
653 : 280 : GetRoot().SetPortion( pFld );
654 : : else
655 : : {
656 [ + - ][ + - ]: 56 : GetRoot().SetNext( new SwLineLayout() );
657 : 56 : GetRoot().GetNext()->SetPortion( pFld );
658 : : }
659 : :
660 : : // ruby portions have the same direction as the frame directions
661 [ - + ]: 336 : if ( rCreate.nLevel % 2 )
662 : : {
663 : : // switch right and left ruby adjustment in rtl environment
664 [ # # ]: 0 : if ( 0 == nAdjustment )
665 : 0 : nAdjustment = 2;
666 [ # # ]: 0 : else if ( 2 == nAdjustment )
667 : 0 : nAdjustment = 0;
668 : :
669 : 0 : SetDirection( DIR_RIGHT2LEFT );
670 : : }
671 : : else
672 [ + - ]: 336 : SetDirection( DIR_LEFT2RIGHT );
673 : 336 : }
674 : :
675 : : /*--------------------------------------------------
676 : : * SwRubyPortion::_Adjust(..)
677 : : * In ruby portion there are different alignments for
678 : : * the ruby text and the main text.
679 : : * Left, right, centered and two possibilities of block adjustment
680 : : * The block adjustment is realized by spacing between the characteres,
681 : : * either with a half space or no space in front of the first letter and
682 : : * a half space at the end of the last letter.
683 : : * Notice: the smaller line will be manipulated, normally it's the ruby line,
684 : : * but it could be the main text, too.
685 : : * If there is a tabulator in smaller line, no adjustment is possible.
686 : : * --------------------------------------------------*/
687 : :
688 : 64 : void SwRubyPortion::_Adjust( SwTxtFormatInfo &rInf )
689 : : {
690 : 64 : SwTwips nLineDiff = GetRoot().Width() - GetRoot().GetNext()->Width();
691 : 64 : xub_StrLen nOldIdx = rInf.GetIdx();
692 [ - + ]: 64 : if( !nLineDiff )
693 : 0 : return;
694 : : SwLineLayout *pCurr;
695 [ + + ]: 64 : if( nLineDiff < 0 )
696 : : { // The first line has to be adjusted.
697 [ - + ]: 8 : if( GetTab1() )
698 : 0 : return;
699 : 8 : pCurr = &GetRoot();
700 : 8 : nLineDiff = -nLineDiff;
701 : : }
702 : : else
703 : : { // The second line has to be adjusted.
704 [ - + ]: 56 : if( GetTab2() )
705 : 0 : return;
706 : 56 : pCurr = GetRoot().GetNext();
707 : 56 : rInf.SetIdx( nOldIdx + GetRoot().GetLen() );
708 : : }
709 : 64 : KSHORT nLeft = 0; // the space in front of the first letter
710 : 64 : KSHORT nRight = 0; // the space at the end of the last letter
711 : 64 : sal_uInt16 nSub = 0;
712 [ + - - - : 64 : switch ( nAdjustment )
- ]
713 : : {
714 : 64 : case 1: nRight = static_cast<sal_uInt16>(nLineDiff / 2); // no break
715 : 64 : case 2: nLeft = static_cast<sal_uInt16>(nLineDiff - nRight); break;
716 : 0 : case 3: nSub = 1; // no break
717 : : case 4:
718 : : {
719 : 0 : xub_StrLen nCharCnt = 0;
720 : : SwLinePortion *pPor;
721 [ # # ]: 0 : for( pPor = pCurr->GetFirstPortion(); pPor; pPor = pPor->GetPortion() )
722 : : {
723 [ # # ]: 0 : if( pPor->InTxtGrp() )
724 [ # # ]: 0 : ((SwTxtPortion*)pPor)->GetSpaceCnt( rInf, nCharCnt );
725 : 0 : rInf.SetIdx( rInf.GetIdx() + pPor->GetLen() );
726 : : }
727 [ # # ]: 0 : if( nCharCnt > nSub )
728 : : {
729 : 0 : SwTwips nCalc = nLineDiff / ( nCharCnt - nSub );
730 : : short nTmp;
731 [ # # ]: 0 : if( nCalc < SHRT_MAX )
732 : 0 : nTmp = -short(nCalc);
733 : : else
734 : 0 : nTmp = SHRT_MIN;
735 : :
736 [ # # ]: 0 : pCurr->CreateSpaceAdd( SPACING_PRECISION_FACTOR * nTmp );
737 : 0 : nLineDiff -= nCalc * ( nCharCnt - 1 );
738 : : }
739 [ # # ]: 0 : if( nLineDiff > 1 )
740 : : {
741 : 0 : nRight = static_cast<sal_uInt16>(nLineDiff / 2);
742 : 0 : nLeft = static_cast<sal_uInt16>(nLineDiff - nRight);
743 : : }
744 : : break;
745 : : }
746 : : default: OSL_FAIL( "New ruby adjustment" );
747 : : }
748 [ - + ][ # # ]: 64 : if( nLeft || nRight )
749 : : {
750 [ - + ]: 64 : if( !pCurr->GetPortion() )
751 [ # # ]: 0 : pCurr->SetPortion( new SwTxtPortion( *pCurr ) );
752 [ + - ]: 64 : SwMarginPortion *pMarg = new SwMarginPortion( 0 );
753 [ + - ]: 64 : if( nLeft )
754 : : {
755 : 64 : pMarg->AddPrtWidth( nLeft );
756 : 64 : pMarg->SetPortion( pCurr->GetPortion() );
757 : 64 : pCurr->SetPortion( pMarg );
758 : : }
759 [ + - ]: 64 : if( nRight )
760 : : {
761 [ + - ]: 64 : pMarg = new SwMarginPortion( 0 );
762 : 64 : pMarg->AddPrtWidth( nRight );
763 : 64 : pCurr->FindLastPortion()->Append( pMarg );
764 : : }
765 : : }
766 : :
767 : 64 : pCurr->Width( Width() );
768 : 64 : rInf.SetIdx( nOldIdx );
769 : : }
770 : :
771 : : /*--------------------------------------------------
772 : : * CalcRubyOffset()
773 : : * has to change the nRubyOffset, if there's a fieldportion
774 : : * in the phonetic line.
775 : : * The nRubyOffset is the position in the rubystring, where the
776 : : * next SwRubyPortion has start the displaying of the phonetics.
777 : : * --------------------------------------------------*/
778 : :
779 : 336 : void SwRubyPortion::CalcRubyOffset()
780 : : {
781 : 336 : const SwLineLayout *pCurr = &GetRoot();
782 [ + + ]: 336 : if( !OnTop() )
783 : : {
784 : 56 : pCurr = pCurr->GetNext();
785 [ - + ]: 56 : if( !pCurr )
786 : 336 : return;
787 : : }
788 : 336 : const SwLinePortion *pPor = pCurr->GetFirstPortion();
789 : 336 : const SwFldPortion *pFld = NULL;
790 [ + + ]: 800 : while( pPor )
791 : : {
792 [ + + ]: 464 : if( pPor->InFldGrp() )
793 : 336 : pFld = (SwFldPortion*)pPor;
794 : 464 : pPor = pPor->GetPortion();
795 : : }
796 [ + - ]: 336 : if( pFld )
797 : : {
798 [ - + ]: 336 : if( pFld->HasFollow() )
799 : 0 : nRubyOffset = pFld->GetNextOffset();
800 : : else
801 : 336 : nRubyOffset = STRING_LEN;
802 : : }
803 : : }
804 : :
805 : : /*--------------------------------------------------
806 : : * SwTxtSizeInfo::GetMultiCreator(..)
807 : : * If we (e.g. the position rPos) are inside a two-line-attribute or
808 : : * a ruby-attribute, the attribute will be returned in a SwMultiCreator-struct,
809 : : * otherwise the function returns zero.
810 : : * The rPos parameter is set to the end of the multiportion,
811 : : * normally this is the end of the attribute,
812 : : * but sometimes it is the start of another attribute, which finished or
813 : : * interrupts the first attribute.
814 : : * E.g. a ruby portion interrupts a 2-line-attribute, a 2-line-attribute
815 : : * with different brackets interrupts another 2-line-attribute.
816 : : * --------------------------------------------------*/
817 : :
818 : : /*--------------------------------------------------
819 : : * lcl_Has2Lines(..)
820 : : * is a little help function for GetMultiCreator(..)
821 : : * It extracts the 2-line-format from a 2-line-attribute or a character style.
822 : : * The rValue is set to sal_True, if the 2-line-attribute's value is set and
823 : : * no 2-line-format reference is passed. If there is a 2-line-format reference,
824 : : * then the rValue is set only, if the 2-line-attribute's value is set _and_
825 : : * the 2-line-formats has the same brackets.
826 : : * --------------------------------------------------*/
827 : :
828 : 2764 : sal_Bool lcl_Has2Lines( const SwTxtAttr& rAttr, const SvxTwoLinesItem* &rpRef,
829 : : sal_Bool &rValue )
830 : : {
831 : 2764 : const SfxPoolItem* pItem = CharFmt::GetItem( rAttr, RES_CHRATR_TWO_LINES );
832 [ + + ]: 2764 : if( pItem )
833 : : {
834 : 108 : rValue = ((SvxTwoLinesItem*)pItem)->GetValue();
835 [ + + ]: 108 : if( !rpRef )
836 : 88 : rpRef = (SvxTwoLinesItem*)pItem;
837 [ + - - + ]: 60 : else if( ((SvxTwoLinesItem*)pItem)->GetEndBracket() !=
[ - + ]
838 : 20 : rpRef->GetEndBracket() ||
839 : 20 : ((SvxTwoLinesItem*)pItem)->GetStartBracket() !=
840 : 20 : rpRef->GetStartBracket() )
841 : 0 : rValue = sal_False;
842 : 108 : return sal_True;
843 : : }
844 : 2764 : return sal_False;
845 : : }
846 : :
847 : : /*--------------------------------------------------
848 : : * lcl_HasRotation(..)
849 : : * is a little help function for GetMultiCreator(..)
850 : : * It extracts the charrotation from a charrotate-attribute or a character style.
851 : : * The rValue is set to sal_True, if the charrotate-attribute's value is set and
852 : : * no charrotate-format reference is passed.
853 : : * If there is a charrotate-format reference, then the rValue is set only,
854 : : * if the charrotate-attribute's value is set _and_ identical
855 : : * to the charrotate-format's value.
856 : : * --------------------------------------------------*/
857 : :
858 : 2724 : sal_Bool lcl_HasRotation( const SwTxtAttr& rAttr,
859 : : const SvxCharRotateItem* &rpRef, sal_Bool &rValue )
860 : : {
861 : 2724 : const SfxPoolItem* pItem = CharFmt::GetItem( rAttr, RES_CHRATR_ROTATE );
862 [ + + ]: 2724 : if ( pItem )
863 : : {
864 : 52 : rValue = 0 != ((SvxCharRotateItem*)pItem)->GetValue();
865 [ + - ]: 52 : if( !rpRef )
866 : 52 : rpRef = (SvxCharRotateItem*)pItem;
867 [ # # ]: 0 : else if( ((SvxCharRotateItem*)pItem)->GetValue() !=
868 : 0 : rpRef->GetValue() )
869 : 0 : rValue = sal_False;
870 : 52 : return sal_True;
871 : : }
872 : :
873 : 2724 : return sal_False;
874 : : }
875 : :
876 : 65441 : SwMultiCreator* SwTxtSizeInfo::GetMultiCreator( xub_StrLen &rPos,
877 : : SwMultiPortion* pMulti ) const
878 : : {
879 : 65441 : SwScriptInfo& rSI = ((SwParaPortion*)GetParaPortion())->GetScriptInfo();
880 : :
881 : : // get the last embedding level
882 : : sal_uInt8 nCurrLevel;
883 [ - + ]: 65441 : if ( pMulti )
884 : : {
885 : : OSL_ENSURE( pMulti->IsBidi(), "Nested MultiPortion is not BidiPortion" );
886 : : // level associated with bidi-portion;
887 : 0 : nCurrLevel = ((SwBidiPortion*)pMulti)->GetLevel();
888 : : }
889 : : else
890 : : // no nested bidi portion required
891 [ + - ][ - + ]: 65441 : nCurrLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
892 : :
893 : : // check if there is a field at rPos:
894 : 65441 : sal_uInt8 nNextLevel = nCurrLevel;
895 : 65441 : sal_Bool bFldBidi = sal_False;
896 : :
897 [ + + ]: 65441 : if ( CH_TXTATR_BREAKWORD == GetChar( rPos ) )
898 : : {
899 : 2089 : bFldBidi = sal_True;
900 : : /*
901 : : // examining the script of the field text should be sufficient
902 : : // for 99% of all cases
903 : : XubString aTxt = GetTxtFrm()->GetTxtNode()->GetExpandTxt( rPos, 1 );
904 : :
905 : : if ( pBreakIt->GetBreakIter().is() && aTxt.Len() )
906 : : {
907 : : sal_Bool bFldDir = ( i18n::ScriptType::COMPLEX ==
908 : : pBreakIt->GetRealScriptOfText( aTxt, 0 ) );
909 : : sal_Bool bCurrDir = ( 0 != ( nCurrLevel % 2 ) );
910 : : if ( bFldDir != bCurrDir )
911 : : {
912 : : nNextLevel = nCurrLevel + 1;
913 : : bFldBidi = sal_True;
914 : : }
915 : : }*/
916 : : }
917 : : else
918 [ + - ]: 63352 : nNextLevel = rSI.DirType( rPos );
919 : :
920 [ + + ][ - + ]: 65441 : if ( GetTxt().Len() != rPos && nNextLevel > nCurrLevel )
[ - + ]
921 : : {
922 [ # # ][ # # ]: 0 : rPos = bFldBidi ? rPos + 1 : rSI.NextDirChg( rPos, &nCurrLevel );
923 [ # # ]: 0 : if ( STRING_LEN == rPos )
924 : 0 : return NULL;
925 [ # # ]: 0 : SwMultiCreator *pRet = new SwMultiCreator;
926 : 0 : pRet->pItem = NULL;
927 : 0 : pRet->pAttr = NULL;
928 : 0 : pRet->nId = SW_MC_BIDI;
929 : 0 : pRet->nLevel = nCurrLevel + 1;
930 : 0 : return pRet;
931 : : }
932 : :
933 : : // a bidi portion can only contain other bidi portions
934 [ - + ]: 65441 : if ( pMulti )
935 : 0 : return NULL;
936 : :
937 : 65441 : const SvxCharRotateItem* pRotate = NULL;
938 : : const SfxPoolItem* pRotItem;
939 [ + - ]: 131176 : if( SFX_ITEM_SET == pFrm->GetTxtNode()->GetSwAttrSet().
[ + + + - ]
[ + + ]
940 [ + - ]: 65441 : GetItemState( RES_CHRATR_ROTATE, sal_True, &pRotItem ) &&
941 : 294 : ((SvxCharRotateItem*)pRotItem)->GetValue() )
942 : 294 : pRotate = (SvxCharRotateItem*)pRotItem;
943 : : else
944 : 65147 : pRotItem = NULL;
945 : 65441 : const SvxTwoLinesItem* p2Lines = NULL;
946 : 65441 : const SwTxtNode *pLclTxtNode = pFrm->GetTxtNode();
947 [ - + ]: 65441 : if( !pLclTxtNode )
948 : 0 : return NULL;
949 : : const SfxPoolItem* pItem;
950 [ + - ]: 131394 : if( SFX_ITEM_SET == pLclTxtNode->GetSwAttrSet().
[ + + + - ]
[ + + ]
951 [ + - ]: 65441 : GetItemState( RES_CHRATR_TWO_LINES, sal_True, &pItem ) &&
952 : 512 : ((SvxTwoLinesItem*)pItem)->GetValue() )
953 : 512 : p2Lines = (SvxTwoLinesItem*)pItem;
954 : : else
955 : 64929 : pItem = NULL;
956 : :
957 : 65441 : const SwpHints *pHints = pLclTxtNode->GetpSwpHints();
958 [ + + ][ + - ]: 65441 : if( !pHints && !p2Lines && !pRotate )
[ + + ]
959 : 57379 : return NULL;
960 : 8062 : const SwTxtAttr *pRuby = NULL;
961 : 8062 : sal_Bool bTwo = sal_False;
962 : 8062 : sal_Bool bRot = sal_False;
963 : 8062 : sal_uInt16 n2Lines = USHRT_MAX;
964 : 8062 : sal_uInt16 nRotate = USHRT_MAX;
965 [ + + ]: 8062 : sal_uInt16 nCount = pHints ? pHints->Count() : 0;
966 : : sal_uInt16 i;
967 [ + + ]: 21876 : for( i = 0; i < nCount; ++i )
968 : : {
969 [ + - ]: 16072 : const SwTxtAttr *pTmp = (*pHints)[i];
970 : 16072 : xub_StrLen nStart = *pTmp->GetStart();
971 [ + + ]: 16072 : if( rPos < nStart )
972 : 2258 : break;
973 [ + - ][ + + ]: 13814 : if( *pTmp->GetAnyEnd() > rPos )
974 : : {
975 [ + - ][ + + ]: 3060 : if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
976 : 336 : pRuby = pTmp;
977 : : else
978 : : {
979 : 2724 : const SvxCharRotateItem* pRoTmp = NULL;
980 [ + - ][ + + ]: 2724 : if( lcl_HasRotation( *pTmp, pRoTmp, bRot ) )
981 : : {
982 [ + - ]: 52 : nRotate = bRot ? i : nCount;
983 : 52 : pRotate = pRoTmp;
984 : : }
985 : 2724 : const SvxTwoLinesItem* p2Tmp = NULL;
986 [ + - ][ + + ]: 2724 : if( lcl_Has2Lines( *pTmp, p2Tmp, bTwo ) )
987 : : {
988 [ + - ]: 88 : n2Lines = bTwo ? i : nCount;
989 : 2724 : p2Lines = p2Tmp;
990 : : }
991 : : }
992 : : }
993 : : }
994 [ + + ]: 8062 : if( pRuby )
995 : : { // The winner is ... a ruby attribute and so
996 : : // the end of the multiportion is the end of the ruby attribute.
997 [ + - ]: 336 : rPos = *pRuby->GetEnd();
998 [ + - ]: 336 : SwMultiCreator *pRet = new SwMultiCreator;
999 : 336 : pRet->pItem = NULL;
1000 : 336 : pRet->pAttr = pRuby;
1001 : 336 : pRet->nId = SW_MC_RUBY;
1002 [ + - ][ - + ]: 336 : pRet->nLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
1003 : 336 : return pRet;
1004 : : }
1005 [ + + ][ + + ]: 8238 : if( n2Lines < nCount || ( pItem && pItem == p2Lines &&
[ + - - + ]
[ + + ]
1006 : 512 : rPos < GetTxt().Len() ) )
1007 : : { // The winner is a 2-line-attribute,
1008 : : // the end of the multiportion depends on the following attributes...
1009 [ + - ]: 20 : SwMultiCreator *pRet = new SwMultiCreator;
1010 : :
1011 : : // We note the endpositions of the 2-line attributes in aEnd as stack
1012 [ + - ]: 20 : SvXub_StrLens aEnd;
1013 : :
1014 : : // The bOn flag signs the state of the last 2-line attribute in the
1015 : : // aEnd-stack, it is compatible with the winner-attribute or
1016 : : // it interrupts the other attribute.
1017 : 20 : sal_Bool bOn = sal_True;
1018 : :
1019 [ + - ]: 20 : if( n2Lines < nCount )
1020 : : {
1021 : 20 : pRet->pItem = NULL;
1022 [ + - ]: 20 : pRet->pAttr = (*pHints)[n2Lines];
1023 [ + - ][ + - ]: 20 : aEnd.push_front( *pRet->pAttr->GetEnd() );
1024 [ - + ]: 20 : if( pItem )
1025 : : {
1026 [ # # ]: 0 : aEnd.front() = GetTxt().Len();
1027 : 0 : bOn = ((SvxTwoLinesItem*)pItem)->GetEndBracket() ==
1028 : 0 : p2Lines->GetEndBracket() &&
1029 : 0 : ((SvxTwoLinesItem*)pItem)->GetStartBracket() ==
1030 [ # # # # ]: 0 : p2Lines->GetStartBracket();
1031 : : }
1032 : : }
1033 : : else
1034 : : {
1035 : 0 : pRet->pItem = pItem;
1036 : 0 : pRet->pAttr = NULL;
1037 [ # # ]: 0 : aEnd.push_front( GetTxt().Len() );
1038 : : }
1039 : 20 : pRet->nId = SW_MC_DOUBLE;
1040 [ + - ][ - + ]: 20 : pRet->nLevel = GetTxtFrm()->IsRightToLeft() ? 1 : 0;
1041 : :
1042 : : // n2Lines is the index of the last 2-line-attribute, which contains
1043 : : // the actual position.
1044 : 20 : i = 0;
1045 : : // At this moment we know that at position rPos the "winner"-attribute
1046 : : // causes a 2-line-portion. The end of the attribute is the end of the
1047 : : // portion, if there's no interrupting attribute.
1048 : : // There are two kinds of interruptors:
1049 : : // - ruby attributes stops the 2-line-attribute, the end of the
1050 : : // multiline is the start of the ruby attribute
1051 : : // - 2-line-attributes with value "Off" or with different brackets,
1052 : : // these attributes may interrupt the winner, but they could be
1053 : : // neutralized by another 2-line-attribute starting at the same
1054 : : // position with the same brackets as the winner-attribute.
1055 : :
1056 : : // In the following loop rPos is the critical position and it will be
1057 : : // evaluated, if at rPos starts a interrupting or a maintaining
1058 : : // continuity attribute.
1059 [ + + ]: 60 : while( i < nCount )
1060 : : {
1061 [ + - ]: 40 : const SwTxtAttr *pTmp = (*pHints)[i++];
1062 [ + - ][ - + ]: 40 : if( *pTmp->GetAnyEnd() <= rPos )
1063 : 0 : continue;
1064 [ - + ]: 40 : if( rPos < *pTmp->GetStart() )
1065 : : {
1066 : : // If bOn is sal_False and the next attribute starts later than rPos
1067 : : // the winner attribute is interrupted at rPos.
1068 : : // If the start of the next atribute is behind the end of
1069 : : // the last attribute on the aEnd-stack, this is the endposition
1070 : : // on the stack is the end of the 2-line portion.
1071 [ # # ][ # # ]: 0 : if( !bOn || aEnd.back() < *pTmp->GetStart() )
[ # # ][ # # ]
1072 : 0 : break;
1073 : : // At this moment, bOn is sal_True and the next attribute starts
1074 : : // behind rPos, so we could move rPos to the next startpoint
1075 : 0 : rPos = *pTmp->GetStart();
1076 : : // We clean up the aEnd-stack, endpositions equal to rPos are
1077 : : // superfluous.
1078 [ # # ][ # # ]: 0 : while( !aEnd.empty() && aEnd.back() <= rPos )
[ # # ][ # # ]
1079 : : {
1080 : 0 : bOn = !bOn;
1081 [ # # ]: 0 : aEnd.pop_back();
1082 : : }
1083 : : // If the endstack is empty, we simulate an attribute with
1084 : : // state sal_True and endposition rPos
1085 [ # # ]: 0 : if( aEnd.empty() )
1086 : : {
1087 [ # # ]: 0 : aEnd.push_front( rPos );
1088 : 0 : bOn = sal_True;
1089 : : }
1090 : : }
1091 : : // A ruby attribute stops the 2-line immediately
1092 [ + - ][ - + ]: 40 : if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
1093 : 0 : return pRet;
1094 [ + - ][ + + ]: 40 : if( lcl_Has2Lines( *pTmp, p2Lines, bTwo ) )
1095 : : { // We have an interesting attribute..
1096 [ + - ]: 20 : if( bTwo == bOn )
1097 : : { // .. with the same state, so the last attribute could
1098 : : // be continued.
1099 [ + - ][ + - ]: 20 : if( aEnd.back() < *pTmp->GetEnd() )
[ - + ]
1100 [ # # ][ # # ]: 0 : aEnd.back() = *pTmp->GetEnd();
1101 : : }
1102 : : else
1103 : : { // .. with a different state.
1104 : 0 : bOn = bTwo;
1105 : : // If this is smaller than the last on the stack, we put
1106 : : // it on the stack. If it has the same endposition, the last
1107 : : // could be removed.
1108 [ # # ][ # # ]: 0 : if( aEnd.back() > *pTmp->GetEnd() )
[ # # ]
1109 [ # # ][ # # ]: 0 : aEnd.push_back( *pTmp->GetEnd() );
1110 [ # # ]: 0 : else if( aEnd.size() > 1 )
1111 [ # # ]: 0 : aEnd.pop_back();
1112 : : else
1113 [ # # ][ # # ]: 0 : aEnd.back() = *pTmp->GetEnd();
1114 : : }
1115 : : }
1116 : : }
1117 [ + - ][ + - ]: 20 : if( bOn && !aEnd.empty() )
[ + - ]
1118 [ + - ]: 20 : rPos = aEnd.back();
1119 : 20 : return pRet;
1120 : : }
1121 [ + - ][ + + ]: 8000 : if( nRotate < nCount || ( pRotItem && pRotItem == pRotate &&
[ + - - + ]
[ - + ]
1122 : 294 : rPos < GetTxt().Len() ) )
1123 : : { // The winner is a rotate-attribute,
1124 : : // the end of the multiportion depends on the following attributes...
1125 [ # # ]: 0 : SwMultiCreator *pRet = new SwMultiCreator;
1126 : 0 : pRet->nId = SW_MC_ROTATE;
1127 : :
1128 : : // We note the endpositions of the 2-line attributes in aEnd as stack
1129 [ # # ]: 0 : SvXub_StrLens aEnd;
1130 : :
1131 : : // The bOn flag signs the state of the last 2-line attribute in the
1132 : : // aEnd-stack, which could interrupts the winning rotation attribute.
1133 [ # # ]: 0 : sal_Bool bOn = pItem ? sal_True : sal_False;
1134 [ # # ]: 0 : aEnd.push_front( GetTxt().Len() );
1135 : : // n2Lines is the index of the last 2-line-attribute, which contains
1136 : : // the actual position.
1137 : 0 : i = 0;
1138 : 0 : xub_StrLen n2Start = rPos;
1139 [ # # ]: 0 : while( i < nCount )
1140 : : {
1141 [ # # ]: 0 : const SwTxtAttr *pTmp = (*pHints)[i++];
1142 [ # # ][ # # ]: 0 : if( *pTmp->GetAnyEnd() <= n2Start )
1143 : 0 : continue;
1144 [ # # ]: 0 : if( n2Start < *pTmp->GetStart() )
1145 : : {
1146 [ # # ][ # # ]: 0 : if( bOn || aEnd.back() < *pTmp->GetStart() )
[ # # ][ # # ]
1147 : 0 : break;
1148 : 0 : n2Start = *pTmp->GetStart();
1149 [ # # ][ # # ]: 0 : while( !aEnd.empty() && aEnd.back() <= n2Start )
[ # # ][ # # ]
1150 : : {
1151 : 0 : bOn = !bOn;
1152 [ # # ]: 0 : aEnd.pop_back();
1153 : : }
1154 [ # # ]: 0 : if( aEnd.empty() )
1155 : : {
1156 [ # # ]: 0 : aEnd.push_front( n2Start );
1157 : 0 : bOn = sal_False;
1158 : : }
1159 : : }
1160 : : // A ruby attribute stops immediately
1161 [ # # ][ # # ]: 0 : if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
1162 : : {
1163 : 0 : bOn = sal_True;
1164 : 0 : break;
1165 : : }
1166 : 0 : p2Lines = NULL;
1167 [ # # ][ # # ]: 0 : if( lcl_Has2Lines( *pTmp, p2Lines, bTwo ) )
1168 : : {
1169 [ # # ]: 0 : if( bTwo == bOn )
1170 : : {
1171 [ # # ][ # # ]: 0 : if( aEnd.back() < *pTmp->GetEnd() )
[ # # ]
1172 [ # # ][ # # ]: 0 : aEnd.back() = *pTmp->GetEnd();
1173 : : }
1174 : : else
1175 : : {
1176 : 0 : bOn = bTwo;
1177 [ # # ][ # # ]: 0 : if( aEnd.back() > *pTmp->GetEnd() )
[ # # ]
1178 [ # # ][ # # ]: 0 : aEnd.push_back( *pTmp->GetEnd() );
1179 [ # # ]: 0 : else if( aEnd.size() > 1 )
1180 [ # # ]: 0 : aEnd.pop_back();
1181 : : else
1182 [ # # ][ # # ]: 0 : aEnd.back() = *pTmp->GetEnd();
1183 : : }
1184 : : }
1185 : : }
1186 [ # # ][ # # ]: 0 : if( !bOn && !aEnd.empty() )
[ # # ]
1187 [ # # ]: 0 : n2Start = aEnd.back();
1188 : :
1189 [ # # ]: 0 : if( !aEnd.empty() )
1190 : 0 : aEnd.clear();
1191 : :
1192 : 0 : bOn = sal_True;
1193 [ # # ]: 0 : if( nRotate < nCount )
1194 : : {
1195 : 0 : pRet->pItem = NULL;
1196 [ # # ]: 0 : pRet->pAttr = (*pHints)[nRotate];
1197 [ # # ][ # # ]: 0 : aEnd.push_front( *pRet->pAttr->GetEnd() );
1198 [ # # ]: 0 : if( pRotItem )
1199 : : {
1200 [ # # ]: 0 : aEnd.front() = GetTxt().Len();
1201 : 0 : bOn = ((SvxCharRotateItem*)pRotItem)->GetValue() ==
1202 : 0 : pRotate->GetValue();
1203 : : }
1204 : : }
1205 : : else
1206 : : {
1207 : 0 : pRet->pItem = pRotItem;
1208 : 0 : pRet->pAttr = NULL;
1209 [ # # ]: 0 : aEnd.push_front( GetTxt().Len() );
1210 : : }
1211 : 0 : i = 0;
1212 [ # # ]: 0 : while( i < nCount )
1213 : : {
1214 [ # # ]: 0 : const SwTxtAttr *pTmp = (*pHints)[i++];
1215 [ # # ][ # # ]: 0 : if( *pTmp->GetAnyEnd() <= rPos )
1216 : 0 : continue;
1217 [ # # ]: 0 : if( rPos < *pTmp->GetStart() )
1218 : : {
1219 [ # # ][ # # ]: 0 : if( !bOn || aEnd.back() < *pTmp->GetStart() )
[ # # ][ # # ]
1220 : 0 : break;
1221 : 0 : rPos = *pTmp->GetStart();
1222 [ # # ][ # # ]: 0 : while( !aEnd.empty() && aEnd.back() <= rPos )
[ # # ][ # # ]
1223 : : {
1224 : 0 : bOn = !bOn;
1225 [ # # ]: 0 : aEnd.pop_back();
1226 : : }
1227 [ # # ]: 0 : if( aEnd.empty() )
1228 : : {
1229 [ # # ]: 0 : aEnd.push_front( rPos );
1230 : 0 : bOn = sal_True;
1231 : : }
1232 : : }
1233 [ # # ][ # # ]: 0 : if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
1234 : : {
1235 : 0 : bOn = sal_False;
1236 : 0 : break;
1237 : : }
1238 [ # # ][ # # ]: 0 : if( lcl_HasRotation( *pTmp, pRotate, bTwo ) )
1239 : : {
1240 [ # # ]: 0 : if( bTwo == bOn )
1241 : : {
1242 [ # # ][ # # ]: 0 : if( aEnd.back() < *pTmp->GetEnd() )
[ # # ]
1243 [ # # ][ # # ]: 0 : aEnd.back() = *pTmp->GetEnd();
1244 : : }
1245 : : else
1246 : : {
1247 : 0 : bOn = bTwo;
1248 [ # # ][ # # ]: 0 : if( aEnd.back() > *pTmp->GetEnd() )
[ # # ]
1249 [ # # ][ # # ]: 0 : aEnd.push_back( *pTmp->GetEnd() );
1250 [ # # ]: 0 : else if( aEnd.size() > 1 )
1251 [ # # ]: 0 : aEnd.pop_back();
1252 : : else
1253 [ # # ][ # # ]: 0 : aEnd.back() = *pTmp->GetEnd();
1254 : : }
1255 : : }
1256 : : }
1257 [ # # ][ # # ]: 0 : if( bOn && !aEnd.empty() )
[ # # ]
1258 [ # # ]: 0 : rPos = aEnd.back();
1259 [ # # ]: 0 : if( rPos > n2Start )
1260 : 0 : rPos = n2Start;
1261 : 0 : return pRet;
1262 : : }
1263 : 65441 : return NULL;
1264 : : }
1265 : :
1266 : : /*--------------------------------------------------
1267 : : * SwSpaceManipulator
1268 : : * is a little helper class to manage the spaceadd-arrays of the text adjustment
1269 : : * during a PaintMultiPortion.
1270 : : * The constructor prepares the array for the first line of multiportion,
1271 : : * the SecondLine-function restores the values for the first line and prepares
1272 : : * the second line.
1273 : : * The destructor restores the values of the last manipulation.
1274 : : * --------------------------------------------------*/
1275 : :
1276 : : class SwSpaceManipulator
1277 : : {
1278 : : SwTxtPaintInfo& rInfo;
1279 : : SwMultiPortion& rMulti;
1280 : : std::vector<long>* pOldSpaceAdd;
1281 : : MSHORT nOldSpIdx;
1282 : : long nSpaceAdd;
1283 : : sal_Bool bSpaceChg : 1;
1284 : : sal_uInt8 nOldDir : 2;
1285 : : public:
1286 : : SwSpaceManipulator( SwTxtPaintInfo& rInf, SwMultiPortion& rMult );
1287 : : ~SwSpaceManipulator();
1288 : : void SecondLine();
1289 : 20 : inline long GetSpaceAdd() const { return nSpaceAdd; }
1290 : : };
1291 : :
1292 : 392 : SwSpaceManipulator::SwSpaceManipulator( SwTxtPaintInfo& rInf,
1293 : : SwMultiPortion& rMult ) :
1294 : 392 : rInfo( rInf ), rMulti( rMult )
1295 : : {
1296 : 392 : pOldSpaceAdd = rInfo.GetpSpaceAdd();
1297 : 392 : nOldSpIdx = rInfo.GetSpaceIdx();
1298 : 392 : nOldDir = rInfo.GetDirection();
1299 : 392 : rInfo.SetDirection( rMulti.GetDirection() );
1300 : 392 : bSpaceChg = sal_False;
1301 : :
1302 [ + + ]: 392 : if( rMulti.IsDouble() )
1303 : : {
1304 : 0 : nSpaceAdd = ( pOldSpaceAdd && !rMulti.HasTabulator() ) ?
1305 [ - + # # ]: 28 : rInfo.GetSpaceAdd() : 0;
1306 [ - + ]: 28 : if( rMulti.GetRoot().IsSpaceAdd() )
1307 : : {
1308 : 0 : rInfo.SetpSpaceAdd( rMulti.GetRoot().GetpLLSpaceAdd() );
1309 : 0 : rInfo.ResetSpaceIdx();
1310 : 0 : bSpaceChg = rMulti.ChgSpaceAdd( &rMulti.GetRoot(), nSpaceAdd );
1311 : : }
1312 [ - + ]: 28 : else if( rMulti.HasTabulator() )
1313 : 0 : rInfo.SetpSpaceAdd( NULL );
1314 : : }
1315 [ + - ]: 364 : else if ( ! rMulti.IsBidi() )
1316 : : {
1317 : 364 : rInfo.SetpSpaceAdd( rMulti.GetRoot().GetpLLSpaceAdd() );
1318 : 364 : rInfo.ResetSpaceIdx();
1319 : : }
1320 : 392 : }
1321 : :
1322 : 392 : void SwSpaceManipulator::SecondLine()
1323 : : {
1324 [ - + ]: 392 : if( bSpaceChg )
1325 : : {
1326 : 0 : rInfo.RemoveFirstSpaceAdd();
1327 : 0 : bSpaceChg = sal_False;
1328 : : }
1329 : 392 : SwLineLayout *pLay = rMulti.GetRoot().GetNext();
1330 [ + + ]: 392 : if( pLay->IsSpaceAdd() )
1331 : : {
1332 : 28 : rInfo.SetpSpaceAdd( pLay->GetpLLSpaceAdd() );
1333 : 28 : rInfo.ResetSpaceIdx();
1334 : 28 : bSpaceChg = rMulti.ChgSpaceAdd( pLay, nSpaceAdd );
1335 : : }
1336 : : else
1337 : : {
1338 : 364 : rInfo.SetpSpaceAdd( (!rMulti.IsDouble() || rMulti.HasTabulator() ) ?
1339 [ - + # # ]: 364 : 0 : pOldSpaceAdd );
1340 : 364 : rInfo.SetSpaceIdx( nOldSpIdx);
1341 : : }
1342 : 392 : }
1343 : :
1344 : 392 : SwSpaceManipulator::~SwSpaceManipulator()
1345 : : {
1346 [ - + ]: 392 : if( bSpaceChg )
1347 : : {
1348 : 0 : rInfo.RemoveFirstSpaceAdd();
1349 : 0 : bSpaceChg = sal_False;
1350 : : }
1351 : 392 : rInfo.SetpSpaceAdd( pOldSpaceAdd );
1352 : 392 : rInfo.SetSpaceIdx( nOldSpIdx);
1353 : 392 : rInfo.SetDirection( nOldDir );
1354 : 392 : }
1355 : :
1356 : : /*--------------------------------------------------
1357 : : * SwTxtPainter::PaintMultiPortion manages the paint for a SwMultiPortion.
1358 : : * External, for the calling function, it seems to be a normal Paint-function,
1359 : : * internal it is like a SwTxtFrm::Paint with multiple DrawTextLines
1360 : : * --------------------------------------------------*/
1361 : :
1362 : 392 : void SwTxtPainter::PaintMultiPortion( const SwRect &rPaint,
1363 : : SwMultiPortion& rMulti, const SwMultiPortion* pEnvPor )
1364 : : {
1365 [ + - ][ + - ]: 392 : GETGRID( pFrm->FindPageFrm() )
[ + - ][ - + ]
[ # # ][ # # ]
[ # # ][ - + ]
1366 [ - + ][ # # ]: 392 : const sal_Bool bHasGrid = pGrid && GetInfo().SnapToGrid();
1367 : 392 : sal_uInt16 nRubyHeight = 0;
1368 : 392 : sal_Bool bRubyTop = sal_False;
1369 : :
1370 [ - + ]: 392 : if ( bHasGrid )
1371 : : {
1372 : 0 : nRubyHeight = pGrid->GetRubyHeight();
1373 : 0 : bRubyTop = ! pGrid->GetRubyTextBelow();
1374 : : }
1375 : :
1376 : : // do not allow grid mode for first line in ruby portion
1377 [ - + ][ # # ]: 392 : const sal_Bool bRubyInGrid = bHasGrid && rMulti.IsRuby();
1378 : :
1379 : 392 : const sal_uInt16 nOldHeight = rMulti.Height();
1380 : 392 : const sal_Bool bOldGridModeAllowed = GetInfo().SnapToGrid();
1381 : :
1382 [ - + ]: 392 : if ( bRubyInGrid )
1383 : : {
1384 : 0 : GetInfo().SetSnapToGrid( ! bRubyTop );
1385 : 0 : rMulti.Height( pCurr->Height() );
1386 : : }
1387 : :
1388 [ + - ]: 392 : SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
1389 : 392 : sal_uInt8 nEnvDir = 0;
1390 : 392 : sal_uInt8 nThisDir = 0;
1391 : 392 : sal_uInt8 nFrmDir = 0;
1392 [ - + ]: 392 : if ( rMulti.IsBidi() )
1393 : : {
1394 : : // these values are needed for the calculation of the x coordinate
1395 : : // and the layout mode
1396 : : OSL_ENSURE( ! pEnvPor || pEnvPor->IsBidi(),
1397 : : "Oh no, I expected a BidiPortion" );
1398 [ # # ][ # # ]: 0 : nFrmDir = GetInfo().GetTxtFrm()->IsRightToLeft() ? 1 : 0;
1399 [ # # ]: 0 : nEnvDir = pEnvPor ? ((SwBidiPortion*)pEnvPor)->GetLevel() % 2 : nFrmDir;
1400 : 0 : nThisDir = ((SwBidiPortion&)rMulti).GetLevel() % 2;
1401 : : }
1402 : :
1403 : : #if OSL_DEBUG_LEVEL > 1
1404 : : // only paint first level bidi portions
1405 : : if( rMulti.Width() > 1 && ! pEnvPor )
1406 : : GetInfo().DrawViewOpt( rMulti, POR_FLD );
1407 : : #endif
1408 : :
1409 [ - + ]: 392 : if ( bRubyInGrid )
1410 : 0 : rMulti.Height( nOldHeight );
1411 : :
1412 : : // do we have to repaint a post it portion?
1413 [ + + ]: 625 : if( GetInfo().OnWin() && rMulti.GetPortion() &&
[ + + + + ]
[ + + ]
1414 : 233 : ! rMulti.GetPortion()->Width() )
1415 [ + - ]: 47 : rMulti.GetPortion()->PrePaint( GetInfo(), &rMulti );
1416 : :
1417 : : // old values must be saved and restored at the end
1418 : 392 : xub_StrLen nOldLen = GetInfo().GetLen();
1419 : 392 : KSHORT nOldX = KSHORT(GetInfo().X());
1420 : 392 : long nOldY = GetInfo().Y();
1421 : 392 : xub_StrLen nOldIdx = GetInfo().GetIdx();
1422 : :
1423 [ + - ]: 392 : SwSpaceManipulator aManip( GetInfo(), rMulti );
1424 : :
1425 : : SwFontSave *pFontSave;
1426 : : SwFont* pTmpFnt;
1427 : :
1428 [ + + ]: 392 : if( rMulti.IsDouble() )
1429 : : {
1430 [ + - ][ + - ]: 28 : pTmpFnt = new SwFont( *GetInfo().GetFont() );
1431 [ + - ]: 28 : if( rMulti.IsDouble() )
1432 : : {
1433 : 28 : SetPropFont( 50 );
1434 [ + - ]: 28 : pTmpFnt->SetProportion( GetPropFont() );
1435 : : }
1436 [ + - ][ + - ]: 28 : pFontSave = new SwFontSave( GetInfo(), pTmpFnt, this );
1437 : : }
1438 : : else
1439 : : {
1440 : 364 : pFontSave = NULL;
1441 : 364 : pTmpFnt = NULL;
1442 : : }
1443 : :
1444 [ + - ][ + + ]: 392 : if( rMulti.HasBrackets() )
1445 : : {
1446 : 20 : xub_StrLen nTmpOldIdx = GetInfo().GetIdx();
1447 : 20 : GetInfo().SetIdx(((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart);
1448 [ + - ]: 20 : SeekAndChg( GetInfo() );
1449 [ + - ]: 20 : ((SwDoubleLinePortion&)rMulti).PaintBracket( GetInfo(), 0, sal_True );
1450 : 20 : GetInfo().SetIdx( nTmpOldIdx );
1451 : : }
1452 : :
1453 : 392 : KSHORT nTmpX = KSHORT(GetInfo().X());
1454 : :
1455 : 392 : SwLineLayout* pLay = &rMulti.GetRoot();// the first line of the multiportion
1456 : 392 : SwLinePortion* pPor = pLay->GetFirstPortion();//first portion of these line
1457 : 392 : SwTwips nOfst = 0;
1458 : :
1459 : : // GetInfo().Y() is the baseline from the surrounding line. We must switch
1460 : : // this temporary to the baseline of the inner lines of the multiportion.
1461 [ - + ]: 392 : if( rMulti.HasRotation() )
1462 : : {
1463 [ # # ]: 0 : if( rMulti.IsRevers() )
1464 : : {
1465 : 0 : GetInfo().Y( nOldY - rMulti.GetAscent() );
1466 : 0 : nOfst = nTmpX + rMulti.Width();
1467 : : }
1468 : : else
1469 : : {
1470 : 0 : GetInfo().Y( nOldY - rMulti.GetAscent() + rMulti.Height() );
1471 : 0 : nOfst = nTmpX;
1472 : : }
1473 : : }
1474 [ - + ]: 392 : else if ( rMulti.IsBidi() )
1475 : : {
1476 : : // does the current bidi portion has the same direction
1477 : : // as its environment?
1478 [ # # ]: 0 : if ( nEnvDir != nThisDir )
1479 : : {
1480 : : // different directions, we have to adjust the x coordinate
1481 : 0 : SwTwips nMultiWidth = rMulti.Width() +
1482 [ # # ][ # # ]: 0 : rMulti.CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
1483 : :
1484 [ # # ]: 0 : if ( nFrmDir == nThisDir )
1485 : 0 : GetInfo().X( GetInfo().X() - nMultiWidth );
1486 : : else
1487 : 0 : GetInfo().X( GetInfo().X() + nMultiWidth );
1488 : : }
1489 : :
1490 : 0 : nOfst = nOldY - rMulti.GetAscent();
1491 : :
1492 : : // set layout mode
1493 [ # # ]: 0 : aLayoutModeModifier.Modify( nThisDir );
1494 : : }
1495 : : else
1496 : 392 : nOfst = nOldY - rMulti.GetAscent();
1497 : :
1498 : 392 : sal_Bool bRest = pLay->IsRest();
1499 : 392 : sal_Bool bFirst = sal_True;
1500 : :
1501 : : OSL_ENSURE( 0 == GetInfo().GetUnderFnt() || rMulti.IsBidi(),
1502 : : " Only BiDi portions are allowed to use the common underlining font" );
1503 : :
1504 [ + + ]: 1126 : do
1505 : : {
1506 [ - + ]: 1126 : if ( bHasGrid )
1507 : : {
1508 [ # # ]: 0 : if( rMulti.HasRotation() )
1509 : : {
1510 : 0 : const sal_uInt16 nAdjustment = ( pLay->Height() - pPor->Height() ) / 2 +
1511 : 0 : pPor->GetAscent();
1512 [ # # ]: 0 : if( rMulti.IsRevers() )
1513 : 0 : GetInfo().X( nOfst - nAdjustment );
1514 : : else
1515 : 0 : GetInfo().X( nOfst + nAdjustment );
1516 : : }
1517 : : else
1518 : : {
1519 : : // special treatment for ruby portions in grid mode
1520 : 0 : SwTwips nAdjustment = 0;
1521 [ # # ]: 0 : if ( rMulti.IsRuby() )
1522 : : {
1523 [ # # ]: 0 : if ( bRubyTop != ( pLay == &rMulti.GetRoot() ) )
1524 : : // adjust base text
1525 : 0 : nAdjustment = ( pCurr->Height() - nRubyHeight - pPor->Height() ) / 2;
1526 [ # # ]: 0 : else if ( bRubyTop )
1527 : : // adjust upper ruby text
1528 : 0 : nAdjustment = nRubyHeight - pPor->Height();
1529 : : // else adjust lower ruby text
1530 : : }
1531 : :
1532 : 0 : GetInfo().Y( nOfst + nAdjustment + pPor->GetAscent() );
1533 : : }
1534 : : }
1535 [ - + ]: 1126 : else if( rMulti.HasRotation() )
1536 : : {
1537 [ # # ]: 0 : if( rMulti.IsRevers() )
1538 [ # # ]: 0 : GetInfo().X( nOfst - AdjustBaseLine( *pLay, pPor, 0, 0, sal_True ) );
1539 : : else
1540 [ # # ]: 0 : GetInfo().X( nOfst + AdjustBaseLine( *pLay, pPor ) );
1541 : : }
1542 : : else
1543 [ + - ]: 1126 : GetInfo().Y( nOfst + AdjustBaseLine( *pLay, pPor ) );
1544 : :
1545 : 1126 : sal_Bool bSeeked = sal_True;
1546 : 1126 : GetInfo().SetLen( pPor->GetLen() );
1547 : :
1548 [ + + ][ + - ]: 1126 : if( bRest && pPor->InFldGrp() && !pPor->GetLen() )
[ + + ][ + + ]
1549 : : {
1550 [ + - ]: 364 : if( ((SwFldPortion*)pPor)->HasFont() )
1551 : 364 : bSeeked = sal_False;
1552 : : else
1553 [ # # ]: 0 : SeekAndChgBefore( GetInfo() );
1554 : : }
1555 [ + + ][ + - ]: 762 : else if( pPor->InTxtGrp() || pPor->InFldGrp() || pPor->InTabGrp() )
[ - + ][ + + ]
1556 [ + - ]: 598 : SeekAndChg( GetInfo() );
1557 [ + + ][ - + ]: 164 : else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
[ # # ][ - + ]
1558 : : {
1559 [ # # ]: 0 : if( GetRedln() )
1560 [ # # ]: 0 : SeekAndChg( GetInfo() );
1561 : : else
1562 [ # # ]: 0 : SeekAndChgBefore( GetInfo() );
1563 : : }
1564 : : else
1565 : 164 : bSeeked = sal_False;
1566 : :
1567 : 1126 : SwLinePortion *pNext = pPor->GetPortion();
1568 [ + + ][ + + ]: 1126 : if(GetInfo().OnWin() && pNext && !pNext->Width() )
[ + + ][ + + ]
1569 : : {
1570 [ - + ]: 30 : if ( !bSeeked )
1571 [ # # ]: 0 : SeekAndChg( GetInfo() );
1572 [ + - ]: 30 : pNext->PrePaint( GetInfo(), pPor );
1573 : : }
1574 : :
1575 [ + - ]: 1126 : CheckSpecialUnderline( pPor );
1576 : 1126 : SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
1577 [ + + ]: 1126 : if ( pUnderLineFnt )
1578 : : {
1579 [ - + ]: 6 : if ( rMulti.IsDouble() )
1580 [ # # ]: 0 : pUnderLineFnt->GetFont().SetProportion( 50 );
1581 : 6 : pUnderLineFnt->SetPos( GetInfo().GetPos() );
1582 : : }
1583 : :
1584 [ - + ]: 1126 : if ( rMulti.IsBidi() )
1585 : : {
1586 : : // we do not allow any rotation inside a bidi portion
1587 : 0 : SwFont* pTmpFont = GetInfo().GetFont();
1588 [ # # ][ # # ]: 0 : pTmpFont->SetVertical( 0, GetInfo().GetTxtFrm()->IsVertical() );
1589 : : }
1590 : :
1591 [ - + ][ # # ]: 1126 : if( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsBidi() )
[ - + ]
1592 : : {
1593 : : // but we do allow nested bidi portions
1594 : : OSL_ENSURE( rMulti.IsBidi(), "Only nesting of bidi portions is allowed" );
1595 [ # # ]: 0 : PaintMultiPortion( rPaint, (SwMultiPortion&)*pPor, &rMulti );
1596 : : }
1597 : : else
1598 [ + - ]: 1126 : pPor->Paint( GetInfo() );
1599 : :
1600 [ - + ][ # # ]: 1126 : if( GetFnt()->IsURL() && pPor->InTxtGrp() )
[ - + ]
1601 [ # # ]: 0 : GetInfo().NotifyURL( *pPor );
1602 : :
1603 : 1126 : bFirst &= !pPor->GetLen();
1604 [ + + ][ + + ]: 1126 : if( pNext || !pPor->IsMarginPortion() )
[ + + ]
1605 [ + - ]: 1030 : pPor->Move( GetInfo() );
1606 : :
1607 : 1126 : pPor = pNext;
1608 : :
1609 : : // If there's no portion left, we go to the next line
1610 [ + + ][ + + ]: 1126 : if( !pPor && pLay->GetNext() )
[ + + ]
1611 : : {
1612 : 392 : pLay = pLay->GetNext();
1613 : 392 : pPor = pLay->GetFirstPortion();
1614 : 392 : bRest = pLay->IsRest();
1615 [ + - ]: 392 : aManip.SecondLine();
1616 : :
1617 : : // delete underline font
1618 [ - + ][ # # ]: 392 : delete GetInfo().GetUnderFnt();
1619 : 392 : GetInfo().SetUnderFnt( 0 );
1620 : :
1621 [ - + ]: 392 : if( rMulti.HasRotation() )
1622 : : {
1623 [ # # ]: 0 : if( rMulti.IsRevers() )
1624 : : {
1625 : 0 : nOfst += pLay->Height();
1626 : 0 : GetInfo().Y( nOldY - rMulti.GetAscent() );
1627 : : }
1628 : : else
1629 : : {
1630 : 0 : nOfst -= pLay->Height();
1631 : 0 : GetInfo().Y( nOldY - rMulti.GetAscent() + rMulti.Height() );
1632 : : }
1633 : : }
1634 [ - + ][ # # ]: 392 : else if ( bHasGrid && rMulti.IsRuby() )
[ - + ]
1635 : : {
1636 : 0 : GetInfo().X( nTmpX );
1637 [ # # ]: 0 : if ( bRubyTop )
1638 : : {
1639 : 0 : nOfst += nRubyHeight;
1640 : 0 : GetInfo().SetSnapToGrid( sal_True );
1641 : : }
1642 : : else
1643 : : {
1644 : 0 : nOfst += pCurr->Height() - nRubyHeight;
1645 : 0 : GetInfo().SetSnapToGrid( sal_False );
1646 : : }
1647 : : } else
1648 : : {
1649 : 392 : GetInfo().X( nTmpX );
1650 : : // We switch to the baseline of the next inner line
1651 : 392 : nOfst += rMulti.GetRoot().Height();
1652 : : }
1653 : : }
1654 : : } while( pPor );
1655 : :
1656 [ - + ]: 392 : if ( bRubyInGrid )
1657 : 0 : GetInfo().SetSnapToGrid( bOldGridModeAllowed );
1658 : :
1659 : : // delete underline font
1660 [ + - ]: 392 : if ( ! rMulti.IsBidi() )
1661 : : {
1662 [ + + ][ + - ]: 392 : delete GetInfo().GetUnderFnt();
1663 : 392 : GetInfo().SetUnderFnt( 0 );
1664 : : }
1665 : :
1666 : 392 : GetInfo().SetIdx( nOldIdx );
1667 : 392 : GetInfo().Y( nOldY );
1668 : :
1669 [ + + ][ + - ]: 392 : if( rMulti.HasBrackets() )
1670 : : {
1671 : 20 : xub_StrLen nTmpOldIdx = GetInfo().GetIdx();
1672 : 20 : GetInfo().SetIdx(((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart);
1673 [ + - ]: 20 : SeekAndChg( GetInfo() );
1674 : 20 : GetInfo().X( nOldX );
1675 : 20 : ((SwDoubleLinePortion&)rMulti).PaintBracket( GetInfo(),
1676 [ + - ]: 40 : aManip.GetSpaceAdd(), sal_False );
1677 : 20 : GetInfo().SetIdx( nTmpOldIdx );
1678 : : }
1679 : : // Restore the saved values
1680 : 392 : GetInfo().X( nOldX );
1681 : 392 : GetInfo().SetLen( nOldLen );
1682 [ + - ][ + + ]: 392 : delete pFontSave;
1683 [ + + ][ + - ]: 392 : delete pTmpFnt;
1684 [ + - ][ + - ]: 392 : SetPropFont( 0 );
1685 : 392 : }
1686 : :
1687 : 0 : sal_Bool lcl_ExtractFieldFollow( SwLineLayout* pLine, SwLinePortion* &rpFld )
1688 : : {
1689 : 0 : SwLinePortion* pLast = pLine;
1690 : 0 : rpFld = pLine->GetPortion();
1691 [ # # ][ # # ]: 0 : while( rpFld && !rpFld->InFldGrp() )
[ # # ]
1692 : : {
1693 : 0 : pLast = rpFld;
1694 : 0 : rpFld = rpFld->GetPortion();
1695 : : }
1696 : 0 : sal_Bool bRet = rpFld != 0;
1697 [ # # ]: 0 : if( bRet )
1698 : : {
1699 [ # # ]: 0 : if( ((SwFldPortion*)rpFld)->IsFollow() )
1700 : : {
1701 : 0 : rpFld->Truncate();
1702 : 0 : pLast->SetPortion( NULL );
1703 : : }
1704 : : else
1705 : 0 : rpFld = NULL;
1706 : : }
1707 : 0 : pLine->Truncate();
1708 : 0 : return bRet;
1709 : : }
1710 : :
1711 : : /*----------------------------------------------------
1712 : : * lcl_TruncateMultiPortion
1713 : : * If a multi portion completely has to go to the
1714 : : * next line, this function is called to trunctate
1715 : : * the rest of the remaining multi portion
1716 : : * --------------------------------------------------*/
1717 : :
1718 : 0 : void lcl_TruncateMultiPortion( SwMultiPortion& rMulti, SwTxtFormatInfo& rInf,
1719 : : xub_StrLen nStartIdx )
1720 : : {
1721 : 0 : rMulti.GetRoot().Truncate();
1722 : 0 : rMulti.GetRoot().SetLen(0);
1723 : 0 : rMulti.GetRoot().Width(0);
1724 : : // rMulti.CalcSize( *this, aInf );
1725 [ # # ]: 0 : if ( rMulti.GetRoot().GetNext() )
1726 : : {
1727 : 0 : rMulti.GetRoot().GetNext()->Truncate();
1728 : 0 : rMulti.GetRoot().GetNext()->SetLen( 0 );
1729 : 0 : rMulti.GetRoot().GetNext()->Width( 0 );
1730 : : }
1731 : 0 : rMulti.Width( 0 );
1732 : 0 : rMulti.SetLen(0);
1733 : 0 : rInf.SetIdx( nStartIdx );
1734 : 0 : }
1735 : :
1736 : : /*-----------------------------------------------------------------------------
1737 : : * SwTxtFormatter::BuildMultiPortion
1738 : : * manages the formatting of a SwMultiPortion. External, for the calling
1739 : : * function, it seems to be a normal Format-function, internal it is like a
1740 : : * SwTxtFrm::_Format with multiple BuildPortions
1741 : : *---------------------------------------------------------------------------*/
1742 : :
1743 : 356 : sal_Bool SwTxtFormatter::BuildMultiPortion( SwTxtFormatInfo &rInf,
1744 : : SwMultiPortion& rMulti )
1745 : : {
1746 : 356 : SwTwips nMaxWidth = rInf.Width();
1747 : 356 : KSHORT nOldX = 0;
1748 : :
1749 [ + + ][ + - ]: 356 : if( rMulti.HasBrackets() )
1750 : : {
1751 : 16 : xub_StrLen nOldIdx = rInf.GetIdx();
1752 : 16 : rInf.SetIdx( ((SwDoubleLinePortion&)rMulti).GetBrackets()->nStart );
1753 [ + - ]: 16 : SeekAndChg( rInf );
1754 : 16 : nOldX = KSHORT(GetInfo().X());
1755 [ + - ]: 16 : ((SwDoubleLinePortion&)rMulti).FormatBrackets( rInf, nMaxWidth );
1756 : 16 : rInf.SetIdx( nOldIdx );
1757 : : }
1758 : :
1759 [ + - ]: 356 : SeekAndChg( rInf );
1760 : : SwFontSave *pFontSave;
1761 [ + + ]: 356 : if( rMulti.IsDouble() )
1762 : : {
1763 [ + - ][ + - ]: 20 : SwFont* pTmpFnt = new SwFont( *rInf.GetFont() );
1764 [ + - ]: 20 : if( rMulti.IsDouble() )
1765 : : {
1766 : 20 : SetPropFont( 50 );
1767 [ + - ]: 20 : pTmpFnt->SetProportion( GetPropFont() );
1768 : : }
1769 [ + - ][ + - ]: 20 : pFontSave = new SwFontSave( rInf, pTmpFnt, this );
1770 : : }
1771 : : else
1772 : 336 : pFontSave = NULL;
1773 : :
1774 [ + - ]: 356 : SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
1775 [ - + ]: 356 : if ( rMulti.IsBidi() )
1776 : : {
1777 : : // set layout mode
1778 [ # # ][ # # ]: 0 : aLayoutModeModifier.Modify( ! rInf.GetTxtFrm()->IsRightToLeft() );
1779 : : }
1780 : :
1781 : 356 : SwTwips nTmpX = 0;
1782 : :
1783 [ - + ]: 356 : if( rMulti.HasRotation() )
1784 : : {
1785 : : // For nMaxWidth we take the height of the body frame.
1786 : : // #i25067#: If the current frame is inside a table, we restrict
1787 : : // nMaxWidth to the current frame height, unless the frame size
1788 : : // attribute is set to variable size:
1789 : :
1790 : : // We set nTmpX (which is used for portion calculating) to the
1791 : : // current Y value
1792 [ # # ]: 0 : const SwPageFrm* pPage = pFrm->FindPageFrm();
1793 : : OSL_ENSURE( pPage, "No page in frame!");
1794 : 0 : const SwLayoutFrm* pUpperFrm = pPage;
1795 : :
1796 [ # # ][ # # ]: 0 : if ( pFrm->IsInTab() )
1797 : : {
1798 : 0 : pUpperFrm = pFrm->GetUpper();
1799 [ # # ][ # # ]: 0 : while ( pUpperFrm && !pUpperFrm->IsCellFrm() )
[ # # ]
1800 : 0 : pUpperFrm = pUpperFrm->GetUpper();
1801 : : OSL_ENSURE( pUpperFrm, "pFrm is in table but does not have an upper cell frame" );
1802 : 0 : const SwTableLine* pLine = ((SwRowFrm*)pUpperFrm->GetUpper())->GetTabLine();
1803 [ # # ]: 0 : const SwFmtFrmSize& rFrmFmtSize = pLine->GetFrmFmt()->GetFrmSize();
1804 [ # # ]: 0 : if ( ATT_VAR_SIZE == rFrmFmtSize.GetHeightSizeType() )
1805 : 0 : pUpperFrm = pPage;
1806 : : }
1807 [ # # ][ # # ]: 0 : if ( pUpperFrm == pPage && !pFrm->IsInFtn() )
[ # # ][ # # ]
1808 [ # # ]: 0 : pUpperFrm = pPage->FindBodyCont();
1809 : :
1810 : : nMaxWidth = pUpperFrm ?
1811 [ # # ]: 0 : ( rInf.GetTxtFrm()->IsVertical() ?
1812 : 0 : pUpperFrm->Prt().Width() :
1813 : 0 : pUpperFrm->Prt().Height() ) :
1814 [ # # ][ # # ]: 0 : USHRT_MAX;
1815 : : }
1816 : : else
1817 : 356 : nTmpX = rInf.X();
1818 : :
1819 : 356 : SwMultiPortion* pOldMulti = pMulti;
1820 : :
1821 : 356 : pMulti = &rMulti;
1822 : 356 : SwLineLayout *pOldCurr = pCurr;
1823 : 356 : xub_StrLen nOldStart = GetStart();
1824 : 356 : SwTwips nMinWidth = nTmpX + 1;
1825 : 356 : SwTwips nActWidth = nMaxWidth;
1826 : 356 : const xub_StrLen nStartIdx = rInf.GetIdx();
1827 : 356 : xub_StrLen nMultiLen = rMulti.GetLen();
1828 : :
1829 : : SwLinePortion *pFirstRest;
1830 : : SwLinePortion *pSecondRest;
1831 [ - + ]: 356 : if( rMulti.IsFormatted() )
1832 : : {
1833 [ # # ][ # # : 0 : if( !lcl_ExtractFieldFollow( &rMulti.GetRoot(), pFirstRest )
# # # # ]
[ # # ]
1834 : 0 : && rMulti.IsDouble() && rMulti.GetRoot().GetNext() )
1835 [ # # ]: 0 : lcl_ExtractFieldFollow( rMulti.GetRoot().GetNext(), pFirstRest );
1836 [ # # ][ # # ]: 0 : if( !rMulti.IsDouble() && rMulti.GetRoot().GetNext() )
[ # # ]
1837 [ # # ]: 0 : lcl_ExtractFieldFollow( rMulti.GetRoot().GetNext(), pSecondRest );
1838 : : else
1839 : 0 : pSecondRest = NULL;
1840 : : }
1841 : : else
1842 : : {
1843 : 356 : pFirstRest = rMulti.GetRoot().GetPortion();
1844 : 356 : pSecondRest = rMulti.GetRoot().GetNext() ?
1845 [ + + ]: 356 : rMulti.GetRoot().GetNext()->GetPortion() : NULL;
1846 [ + + ]: 356 : if( pFirstRest )
1847 : 280 : rMulti.GetRoot().SetPortion( NULL );
1848 [ + + ]: 356 : if( pSecondRest )
1849 : 56 : rMulti.GetRoot().GetNext()->SetPortion( NULL );
1850 : 356 : rMulti.SetFormatted();
1851 : 356 : nMultiLen = nMultiLen - rInf.GetIdx();
1852 : : }
1853 : :
1854 : : // save some values
1855 : 356 : const XubString* pOldTxt = &(rInf.GetTxt());
1856 : 356 : const SwTwips nOldPaintOfst = rInf.GetPaintOfst();
1857 : :
1858 [ + - ]: 356 : XubString aMultiStr( rInf.GetTxt(), 0, nMultiLen + rInf.GetIdx() );
1859 : 356 : rInf.SetTxt( aMultiStr );
1860 [ + - ]: 356 : SwTxtFormatInfo aInf( rInf, rMulti.GetRoot(), nActWidth );
1861 : : // Do we allow break cuts? The FirstMulti-Flag is evaluated during
1862 : : // line break determination.
1863 : 356 : sal_Bool bFirstMulti = rInf.GetIdx() != rInf.GetLineStart();
1864 : :
1865 : 356 : SwLinePortion *pNextFirst = NULL;
1866 : 356 : SwLinePortion *pNextSecond = NULL;
1867 : 356 : sal_Bool bRet = sal_False;
1868 : :
1869 [ + - ][ + - ]: 356 : GETGRID( pFrm->FindPageFrm() )
[ - + ][ # # ]
[ # # ][ # # ]
[ - + ][ + - ]
1870 [ - + ][ # # ]: 356 : const sal_Bool bHasGrid = pGrid && GRID_LINES_CHARS == pGrid->GetGridType();
1871 : :
1872 : 356 : sal_Bool bRubyTop = sal_False;
1873 : :
1874 [ - + ]: 356 : if ( bHasGrid )
1875 : 0 : bRubyTop = ! pGrid->GetRubyTextBelow();
1876 : :
1877 : 160 : do
1878 : : {
1879 : 516 : pCurr = &rMulti.GetRoot();
1880 : 516 : nStart = nStartIdx;
1881 : 516 : bRet = sal_False;
1882 [ + - ]: 516 : FormatReset( aInf );
1883 : 516 : aInf.X( nTmpX );
1884 : 516 : aInf.Width( KSHORT(nActWidth) );
1885 : 516 : aInf.RealWidth( KSHORT(nActWidth) );
1886 : 516 : aInf.SetFirstMulti( bFirstMulti );
1887 : 516 : aInf.SetNumDone( rInf.IsNumDone() );
1888 : 516 : aInf.SetFtnDone( rInf.IsFtnDone() );
1889 : :
1890 [ + + ]: 516 : if( pFirstRest )
1891 : : {
1892 : : OSL_ENSURE( pFirstRest->InFldGrp(), "BuildMulti: Fieldrest expected");
1893 : : SwFldPortion *pFld =
1894 : : ((SwFldPortion*)pFirstRest)->Clone(
1895 [ + - ]: 280 : ((SwFldPortion*)pFirstRest)->GetExp() );
1896 : 280 : pFld->SetFollow( sal_True );
1897 : 280 : aInf.SetRest( pFld );
1898 : : }
1899 [ + + ][ + + ]: 516 : aInf.SetRuby( rMulti.IsRuby() && rMulti.OnTop() );
1900 : :
1901 : : // in grid mode we temporarily have to disable the grid for the ruby line
1902 : 516 : const sal_Bool bOldGridModeAllowed = GetInfo().SnapToGrid();
1903 [ # # ][ # # ]: 516 : if ( bHasGrid && aInf.IsRuby() && bRubyTop )
[ - + ][ - + ]
1904 : 0 : aInf.SetSnapToGrid( sal_False );
1905 : :
1906 : : // If there's no more rubytext, then buildportion is forbidden
1907 [ + + ][ + - ]: 516 : if( pFirstRest || !aInf.IsRuby() )
[ + - ]
1908 [ + - ]: 516 : BuildPortions( aInf );
1909 : :
1910 : 516 : aInf.SetSnapToGrid( bOldGridModeAllowed );
1911 : :
1912 [ + - ]: 516 : rMulti.CalcSize( *this, aInf );
1913 : 516 : pCurr->SetRealHeight( pCurr->Height() );
1914 : :
1915 [ - + ]: 516 : if( rMulti.IsBidi() )
1916 : : {
1917 : 0 : pNextFirst = aInf.GetRest();
1918 : 0 : break;
1919 : : }
1920 : :
1921 [ - + ][ # # ]: 516 : if( rMulti.HasRotation() && !rMulti.IsDouble() )
[ - + ]
1922 : 0 : break;
1923 : : // second line has to be formatted
1924 [ + + ][ + + ]: 516 : else if( pCurr->GetLen()<nMultiLen || rMulti.IsRuby() || aInf.GetRest())
[ - + ][ + + ]
1925 : : {
1926 : 416 : xub_StrLen nFirstLen = pCurr->GetLen();
1927 [ + - ][ + + ]: 416 : delete pCurr->GetNext();
1928 [ + - ][ + - ]: 416 : pCurr->SetNext( new SwLineLayout() );
1929 : 416 : pCurr = pCurr->GetNext();
1930 : 416 : nStart = aInf.GetIdx();
1931 : 416 : aInf.X( nTmpX );
1932 [ + - ]: 416 : SwTxtFormatInfo aTmp( aInf, *pCurr, nActWidth );
1933 [ + + ]: 416 : if( rMulti.IsRuby() )
1934 : : {
1935 : 336 : aTmp.SetRuby( !rMulti.OnTop() );
1936 : 336 : pNextFirst = aInf.GetRest();
1937 [ + + ]: 336 : if( pSecondRest )
1938 : : {
1939 : : OSL_ENSURE( pSecondRest->InFldGrp(), "Fieldrest expected");
1940 : : SwFldPortion *pFld = ((SwFldPortion*)pSecondRest)->Clone(
1941 [ + - ]: 56 : ((SwFldPortion*)pSecondRest)->GetExp() );
1942 : 56 : pFld->SetFollow( sal_True );
1943 : 56 : aTmp.SetRest( pFld );
1944 : : }
1945 [ + + ][ - + ]: 336 : if( !rMulti.OnTop() && nFirstLen < nMultiLen )
[ - + ]
1946 : 0 : bRet = sal_True;
1947 : : }
1948 : : else
1949 : 80 : aTmp.SetRest( aInf.GetRest() );
1950 : 416 : aInf.SetRest( NULL );
1951 : :
1952 : : // in grid mode we temporarily have to disable the grid for the ruby line
1953 [ # # ][ # # ]: 416 : if ( bHasGrid && aTmp.IsRuby() && ! bRubyTop )
[ - + ][ - + ]
1954 : 0 : aTmp.SetSnapToGrid( sal_False );
1955 : :
1956 [ + - ]: 416 : BuildPortions( aTmp );
1957 : :
1958 : 416 : aTmp.SetSnapToGrid( bOldGridModeAllowed );
1959 : :
1960 [ + - ]: 416 : rMulti.CalcSize( *this, aInf );
1961 : 416 : rMulti.GetRoot().SetRealHeight( rMulti.GetRoot().Height() );
1962 : 416 : pCurr->SetRealHeight( pCurr->Height() );
1963 [ + + ]: 416 : if( rMulti.IsRuby() )
1964 : : {
1965 : 336 : pNextSecond = aTmp.GetRest();
1966 [ - + ]: 336 : if( pNextFirst )
1967 : 0 : bRet = sal_True;
1968 : : }
1969 : : else
1970 : 80 : pNextFirst = aTmp.GetRest();
1971 [ + + ]: 752 : if( ( !aTmp.IsRuby() && nFirstLen + pCurr->GetLen() < nMultiLen )
[ + + - + ]
[ + + ]
1972 : 336 : || aTmp.GetRest() )
1973 : : // our guess for width of multiportion was too small,
1974 : : // text did not fit into multiportion
1975 [ + - ]: 416 : bRet = sal_True;
1976 : : }
1977 [ + + ]: 516 : if( rMulti.IsRuby() )
1978 : 336 : break;
1979 [ + + ]: 180 : if( bRet )
1980 : : {
1981 : : // our guess for multiportion width was too small,
1982 : : // we set min to act
1983 : 80 : nMinWidth = nActWidth;
1984 : 80 : nActWidth = ( 3 * nMaxWidth + nMinWidth + 3 ) / 4;
1985 [ - + ][ # # ]: 80 : if ( nActWidth == nMaxWidth && rInf.GetLineStart() == rInf.GetIdx() )
[ - + ]
1986 : : // we have too less space, we must allow break cuts
1987 : : // ( the first multi flag is considered during TxtPortion::_Format() )
1988 : 0 : bFirstMulti = sal_False;
1989 [ - + ]: 80 : if( nActWidth <= nMinWidth )
1990 : 0 : break;
1991 : : }
1992 : : else
1993 : : {
1994 : : // For Solaris, this optimisation can causes trouble:
1995 : : // Setting this to the portion width ( = rMulti.Width() )
1996 : : // can make GetTextBreak inside SwTxtGuess::Guess return to small
1997 : : // values. Therefore we add some extra twips.
1998 [ + + ]: 100 : if( nActWidth > nTmpX + rMulti.Width() + 6 )
1999 : 20 : nActWidth = nTmpX + rMulti.Width() + 6;
2000 : 100 : nMaxWidth = nActWidth;
2001 : 100 : nActWidth = ( 3 * nMaxWidth + nMinWidth + 3 ) / 4;
2002 [ + + ]: 100 : if( nActWidth >= nMaxWidth )
2003 : 20 : break;
2004 : : // we do not allow break cuts during formatting
2005 : 80 : bFirstMulti = sal_True;
2006 : : }
2007 [ - + ][ # # ]: 160 : delete pNextFirst;
2008 : 160 : pNextFirst = NULL;
2009 : : } while ( sal_True );
2010 : :
2011 : 356 : pMulti = pOldMulti;
2012 : :
2013 : 356 : pCurr = pOldCurr;
2014 : 356 : nStart = nOldStart;
2015 : 356 : SetPropFont( 0 );
2016 : :
2017 : 356 : rMulti.SetLen( rMulti.GetRoot().GetLen() + ( rMulti.GetRoot().GetNext() ?
2018 [ + - ]: 356 : rMulti.GetRoot().GetNext()->GetLen() : 0 ) );
2019 : :
2020 [ + + ]: 356 : if( rMulti.IsDouble() )
2021 : : {
2022 [ + - ]: 20 : ((SwDoubleLinePortion&)rMulti).CalcBlanks( rInf );
2023 [ + - ]: 20 : if( ((SwDoubleLinePortion&)rMulti).GetLineDiff() )
2024 : : {
2025 : 20 : SwLineLayout* pLine = &rMulti.GetRoot();
2026 [ + - ]: 20 : if( ((SwDoubleLinePortion&)rMulti).GetLineDiff() > 0 )
2027 : : {
2028 : 20 : rInf.SetIdx( nStartIdx + pLine->GetLen() );
2029 : 20 : pLine = pLine->GetNext();
2030 : : }
2031 [ + - ]: 20 : if( pLine )
2032 : : {
2033 : 20 : GetInfo().SetMulti( sal_True );
2034 [ + - ]: 20 : CalcNewBlock( pLine, NULL, rMulti.Width() );
2035 : 20 : GetInfo().SetMulti( sal_False );
2036 : : }
2037 : 20 : rInf.SetIdx( nStartIdx );
2038 : : }
2039 [ + + ]: 20 : if( ((SwDoubleLinePortion&)rMulti).GetBrackets() )
2040 : : {
2041 : 16 : rMulti.Width( rMulti.Width() +
2042 : 16 : ((SwDoubleLinePortion&)rMulti).BracketWidth() );
2043 : 16 : GetInfo().X( nOldX );
2044 : : }
2045 : : }
2046 : : else
2047 : : {
2048 : 336 : rMulti.ActualizeTabulator();
2049 [ + - ]: 336 : if( rMulti.IsRuby() )
2050 : : {
2051 [ + - ]: 336 : ((SwRubyPortion&)rMulti).Adjust( rInf );
2052 : 336 : ((SwRubyPortion&)rMulti).CalcRubyOffset();
2053 : : }
2054 : : }
2055 [ - + ]: 356 : if( rMulti.HasRotation() )
2056 : : {
2057 : 0 : SwTwips nH = rMulti.Width();
2058 : 0 : SwTwips nAsc = rMulti.GetAscent() + ( nH - rMulti.Height() )/2;
2059 [ # # ]: 0 : if( nAsc > nH )
2060 : 0 : nAsc = nH;
2061 [ # # ]: 0 : else if( nAsc < 0 )
2062 : 0 : nAsc = 0;
2063 : 0 : rMulti.Width( rMulti.Height() );
2064 : 0 : rMulti.Height( KSHORT(nH) );
2065 : 0 : rMulti.SetAscent( KSHORT(nAsc) );
2066 : 0 : bRet = ( rInf.GetPos().X() + rMulti.Width() > rInf.Width() ) &&
2067 [ # # ][ # # ]: 0 : nStartIdx != rInf.GetLineStart();
2068 : : }
2069 [ - + ]: 356 : else if ( rMulti.IsBidi() )
2070 : : {
2071 [ # # ][ # # ]: 0 : bRet = rMulti.GetLen() < nMultiLen || pNextFirst;
2072 : : }
2073 : :
2074 : : // line break has to be performed!
2075 [ - + ]: 356 : if( bRet )
2076 : : {
2077 : : OSL_ENSURE( !pNextFirst || pNextFirst->InFldGrp(),
2078 : : "BuildMultiPortion: Surprising restportion, field expected" );
2079 : : SwMultiPortion *pTmp;
2080 [ # # ]: 0 : if( rMulti.IsDouble() )
2081 : : pTmp = new SwDoubleLinePortion( ((SwDoubleLinePortion&)rMulti),
2082 [ # # ][ # # ]: 0 : nMultiLen + rInf.GetIdx() );
2083 [ # # ]: 0 : else if( rMulti.IsRuby() )
2084 : : {
2085 : : OSL_ENSURE( !pNextSecond || pNextSecond->InFldGrp(),
2086 : : "BuildMultiPortion: Surprising restportion, field expected" );
2087 : :
2088 [ # # ]: 0 : if ( rInf.GetIdx() == rInf.GetLineStart() )
2089 : : {
2090 : : // the ruby portion has to be split in two portions
2091 : : pTmp = new SwRubyPortion( ((SwRubyPortion&)rMulti),
2092 [ # # ][ # # ]: 0 : nMultiLen + rInf.GetIdx() );
2093 : :
2094 [ # # ]: 0 : if( pNextSecond )
2095 : : {
2096 [ # # ][ # # ]: 0 : pTmp->GetRoot().SetNext( new SwLineLayout() );
2097 : 0 : pTmp->GetRoot().GetNext()->SetPortion( pNextSecond );
2098 : : }
2099 : 0 : pTmp->SetFollowFld();
2100 : : }
2101 : : else
2102 : : {
2103 : : // we try to keep our ruby portion together
2104 [ # # ]: 0 : lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
2105 : 0 : pTmp = 0;
2106 : : }
2107 : : }
2108 [ # # ]: 0 : else if( rMulti.HasRotation() )
2109 : : {
2110 : : // we try to keep our rotated portion together
2111 [ # # ]: 0 : lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
2112 : 0 : pTmp = new SwRotatedPortion( nMultiLen + rInf.GetIdx(),
2113 [ # # ][ # # ]: 0 : rMulti.GetDirection() );
2114 : : }
2115 : : // during a recursion of BuildMultiPortions we may not build
2116 : : // a new SwBidiPortion, this would cause a memory leak
2117 [ # # ][ # # ]: 0 : else if( rMulti.IsBidi() && ! pMulti )
[ # # ]
2118 : : {
2119 [ # # ]: 0 : if ( ! rMulti.GetLen() )
2120 [ # # ]: 0 : lcl_TruncateMultiPortion( rMulti, rInf, nStartIdx );
2121 : :
2122 : : // If there is a HolePortion at the end of the bidi portion,
2123 : : // it has to be moved behind the bidi portion. Otherwise
2124 : : // the visual cursor travelling gets into trouble.
2125 : 0 : SwLineLayout& aRoot = rMulti.GetRoot();
2126 : 0 : SwLinePortion* pPor = aRoot.GetFirstPortion();
2127 [ # # ]: 0 : while ( pPor )
2128 : : {
2129 [ # # ][ # # ]: 0 : if ( pPor->GetPortion() && pPor->GetPortion()->IsHolePortion() )
[ # # ]
2130 : : {
2131 : 0 : SwLinePortion* pHolePor = pPor->GetPortion();
2132 : 0 : pPor->SetPortion( NULL );
2133 : 0 : aRoot.SetLen( aRoot.GetLen() - pHolePor->GetLen() );
2134 : 0 : rMulti.SetLen( rMulti.GetLen() - pHolePor->GetLen() );
2135 : 0 : rMulti.SetPortion( pHolePor );
2136 : 0 : break;
2137 : : }
2138 : 0 : pPor = pPor->GetPortion();
2139 : : }
2140 : :
2141 : 0 : pTmp = new SwBidiPortion( nMultiLen + rInf.GetIdx(),
2142 [ # # ][ # # ]: 0 : ((SwBidiPortion&)rMulti).GetLevel() );
2143 : : }
2144 : : else
2145 : 0 : pTmp = NULL;
2146 : :
2147 [ # # ][ # # ]: 0 : if ( ! rMulti.GetLen() && rInf.GetLast() )
[ # # ]
2148 : : {
2149 [ # # ]: 0 : SeekAndChgBefore( rInf );
2150 [ # # ]: 0 : rInf.GetLast()->FormatEOL( rInf );
2151 : : }
2152 : :
2153 [ # # ][ # # ]: 0 : if( pNextFirst && pTmp )
2154 : : {
2155 : 0 : pTmp->SetFollowFld();
2156 : 0 : pTmp->GetRoot().SetPortion( pNextFirst );
2157 : : }
2158 : : else
2159 : : // A follow field portion is still waiting. If nobody wants it,
2160 : : // we delete it.
2161 [ # # ][ # # ]: 0 : delete pNextFirst;
2162 : :
2163 : 0 : rInf.SetRest( pTmp );
2164 : : }
2165 : :
2166 : 356 : rInf.SetTxt( *pOldTxt );
2167 : 356 : rInf.SetPaintOfst( nOldPaintOfst );
2168 : 356 : rInf.SetStop( aInf.IsStop() );
2169 : 356 : rInf.SetNumDone( sal_True );
2170 : 356 : rInf.SetFtnDone( sal_True );
2171 [ + - ]: 356 : SeekAndChg( rInf );
2172 [ + + ][ + - ]: 356 : delete pFirstRest;
2173 [ + + ][ + - ]: 356 : delete pSecondRest;
2174 [ + + ][ + - ]: 356 : delete pFontSave;
2175 [ + - ][ + - ]: 356 : return bRet;
[ + - ]
2176 : : }
2177 : :
2178 : : /*--------------------------------------------------
2179 : : * SwTxtFormatter::MakeRestPortion(..)
2180 : : * When a fieldportion at the end of line breaks and needs a following
2181 : : * fieldportion in the next line, then the "restportion" of the formatinfo
2182 : : * has to be set. Normally this happens during the formatting of the first
2183 : : * part of the fieldportion.
2184 : : * But sometimes the formatting starts at the line with the following part,
2185 : : * especially when the following part is on the next page.
2186 : : * In this case the MakeRestPortion-function has to create the following part.
2187 : : * The first parameter is the line that contains possibly a first part
2188 : : * of a field. When the function finds such field part, it creates the right
2189 : : * restportion. This may be a multiportion, e.g. if the field is surrounded by
2190 : : * a doubleline- or ruby-portion.
2191 : : * The second parameter is the start index of the line.
2192 : : * --------------------------------------------------*/
2193 : :
2194 : 70 : SwLinePortion* SwTxtFormatter::MakeRestPortion( const SwLineLayout* pLine,
2195 : : xub_StrLen nPosition )
2196 : : {
2197 [ - + ]: 70 : if( !nPosition )
2198 : 0 : return NULL;
2199 : 70 : xub_StrLen nMultiPos = nPosition - pLine->GetLen();
2200 : 70 : const SwMultiPortion *pTmpMulti = NULL;
2201 : 70 : const SwMultiPortion *pHelpMulti = NULL;
2202 : 70 : const SwLinePortion* pPor = pLine->GetFirstPortion();
2203 : 70 : SwFldPortion *pFld = NULL;
2204 [ + + ]: 148 : while( pPor )
2205 : : {
2206 [ + - ]: 78 : if( pPor->GetLen() )
2207 : : {
2208 [ + - ]: 78 : if( !pHelpMulti )
2209 : : {
2210 : 78 : nMultiPos = nMultiPos + pPor->GetLen();
2211 : 78 : pTmpMulti = NULL;
2212 : : }
2213 : : }
2214 [ - + ]: 78 : if( pPor->InFldGrp() )
2215 : : {
2216 [ # # ]: 0 : if( !pHelpMulti )
2217 : 0 : pTmpMulti = NULL;
2218 : 0 : pFld = (SwFldPortion*)pPor;
2219 : : }
2220 [ - + ]: 78 : else if( pPor->IsMultiPortion() )
2221 : : {
2222 : : OSL_ENSURE( !pHelpMulti || pHelpMulti->IsBidi(),
2223 : : "Nested multiportions are forbidden." );
2224 : :
2225 : 0 : pFld = NULL;
2226 : 0 : pTmpMulti = (SwMultiPortion*)pPor;
2227 : : }
2228 : 78 : pPor = pPor->GetPortion();
2229 : : // If the last portion is a multi-portion, we enter it
2230 : : // and look for a field portion inside.
2231 : : // If we are already in a multiportion, we could change to the
2232 : : // next line
2233 [ - + ][ + + ]: 78 : if( !pPor && pTmpMulti )
2234 : : {
2235 [ # # ]: 0 : if( pHelpMulti )
2236 : : { // We're already inside the multiportion, let's take the second
2237 : : // line, if we are in a double line portion
2238 [ # # ]: 0 : if( !pHelpMulti->IsRuby() )
2239 : 0 : pPor = pHelpMulti->GetRoot().GetNext();
2240 : 0 : pTmpMulti = NULL;
2241 : : }
2242 : : else
2243 : : { // Now we enter a multiportion, in a ruby portion we take the
2244 : : // main line, not the phonetic line, in a doublelineportion we
2245 : : // starts with the first line.
2246 : 0 : pHelpMulti = pTmpMulti;
2247 : 0 : nMultiPos = nMultiPos - pHelpMulti->GetLen();
2248 [ # # ][ # # ]: 0 : if( pHelpMulti->IsRuby() && pHelpMulti->OnTop() )
[ # # ]
2249 : 0 : pPor = pHelpMulti->GetRoot().GetNext();
2250 : : else
2251 : 0 : pPor = pHelpMulti->GetRoot().GetFirstPortion();
2252 : : }
2253 : : }
2254 : : }
2255 [ - + ][ # # ]: 70 : if( pFld && !pFld->HasFollow() )
[ - + ]
2256 : 0 : pFld = NULL;
2257 : :
2258 : 70 : SwLinePortion *pRest = NULL;
2259 [ - + ]: 70 : if( pFld )
2260 : : {
2261 [ # # ]: 0 : const SwTxtAttr *pHint = GetAttr( nPosition - 1 );
2262 [ # # ][ # # ]: 0 : if( pHint && pHint->Which() == RES_TXTATR_FIELD )
[ # # ][ # # ]
2263 : : {
2264 [ # # ]: 0 : pRest = NewFldPortion( GetInfo(), pHint );
2265 [ # # ]: 0 : if( pRest->InFldGrp() )
2266 [ # # ]: 0 : ((SwFldPortion*)pRest)->TakeNextOffset( pFld );
2267 : : else
2268 : : {
2269 [ # # ][ # # ]: 0 : delete pRest;
2270 : 0 : pRest = NULL;
2271 : : }
2272 : : }
2273 : : }
2274 [ + - ]: 70 : if( !pHelpMulti )
2275 : 70 : return pRest;
2276 : :
2277 : 0 : nPosition = nMultiPos + pHelpMulti->GetLen();
2278 [ # # ]: 0 : SwMultiCreator* pCreate = GetInfo().GetMultiCreator( nMultiPos, 0 );
2279 : :
2280 [ # # ]: 0 : if ( !pCreate )
2281 : : {
2282 : : OSL_ENSURE( !pHelpMulti->GetLen(), "Multiportion without attribut?" );
2283 [ # # ]: 0 : if ( nMultiPos )
2284 : 0 : --nMultiPos;
2285 [ # # ]: 0 : pCreate = GetInfo().GetMultiCreator( --nMultiPos, 0 );
2286 : : }
2287 : :
2288 [ # # ]: 0 : if (!pCreate)
2289 : 0 : return pRest;
2290 : :
2291 [ # # ][ # # ]: 0 : if( pRest || nMultiPos > nPosition || ( pHelpMulti->IsRuby() &&
[ # # # # ]
[ # # ]
2292 : 0 : ((SwRubyPortion*)pHelpMulti)->GetRubyOffset() < STRING_LEN ) )
2293 : : {
2294 : : SwMultiPortion* pTmp;
2295 [ # # ]: 0 : if( pHelpMulti->IsDouble() )
2296 [ # # ][ # # ]: 0 : pTmp = new SwDoubleLinePortion( *pCreate, nMultiPos );
2297 [ # # ]: 0 : else if( pHelpMulti->IsBidi() )
2298 [ # # ][ # # ]: 0 : pTmp = new SwBidiPortion( nMultiPos, pCreate->nLevel );
2299 [ # # ]: 0 : else if( pHelpMulti->IsRuby() )
2300 : : {
2301 : : sal_Bool bRubyTop;
2302 : 0 : sal_Bool* pRubyPos = 0;
2303 : :
2304 [ # # ]: 0 : if ( GetInfo().SnapToGrid() )
2305 : : {
2306 [ # # ][ # # ]: 0 : GETGRID( pFrm->FindPageFrm() )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
2307 [ # # ]: 0 : if ( pGrid )
2308 : : {
2309 : 0 : bRubyTop = ! pGrid->GetRubyTextBelow();
2310 : 0 : pRubyPos = &bRubyTop;
2311 : : }
2312 : : }
2313 : :
2314 : 0 : pTmp = new SwRubyPortion( *pCreate, *GetInfo().GetFont(),
2315 : 0 : *pFrm->GetTxtNode()->getIDocumentSettingAccess(),
2316 : 0 : nMultiPos, ((SwRubyPortion*)pHelpMulti)->GetRubyOffset(),
2317 [ # # ]: 0 : pRubyPos );
[ # # # # ]
2318 : : }
2319 [ # # ]: 0 : else if( pHelpMulti->HasRotation() )
2320 [ # # ][ # # ]: 0 : pTmp = new SwRotatedPortion( nMultiPos, pHelpMulti->GetDirection() );
2321 : : else
2322 : : {
2323 : 0 : delete pCreate;
2324 : 0 : return pRest;
2325 : : }
2326 : 0 : delete pCreate;
2327 : 0 : pTmp->SetFollowFld();
2328 [ # # ]: 0 : if( pRest )
2329 : : {
2330 : 0 : SwLineLayout *pLay = &pTmp->GetRoot();
2331 [ # # ][ # # ]: 0 : if( pTmp->IsRuby() && pTmp->OnTop() )
[ # # ]
2332 : : {
2333 [ # # ][ # # ]: 0 : pLay->SetNext( new SwLineLayout() );
2334 : 0 : pLay = pLay->GetNext();
2335 : : }
2336 : 0 : pLay->SetPortion( pRest );
2337 : : }
2338 : 0 : return pTmp;
2339 : : }
2340 : 70 : return pRest;
2341 : : }
2342 : :
2343 : :
2344 : :
2345 : : /*--------------------------------------------------
2346 : : * SwTxtCursorSave notes the start and current line of a SwTxtCursor,
2347 : : * sets them to the values for GetCrsrOfst inside a multiportion
2348 : : * and restores them in the destructor.
2349 : : * --------------------------------------------------*/
2350 : :
2351 : 0 : SwTxtCursorSave::SwTxtCursorSave( SwTxtCursor* pTxtCursor,
2352 : : SwMultiPortion* pMulti,
2353 : : SwTwips nY,
2354 : : sal_uInt16& nX,
2355 : : xub_StrLen nCurrStart,
2356 : : long nSpaceAdd )
2357 : : {
2358 : 0 : pTxtCrsr = pTxtCursor;
2359 : 0 : nStart = pTxtCursor->nStart;
2360 : 0 : pTxtCursor->nStart = nCurrStart;
2361 : 0 : pCurr = pTxtCursor->pCurr;
2362 : 0 : pTxtCursor->pCurr = &pMulti->GetRoot();
2363 [ # # # # ]: 0 : while( pTxtCursor->Y() + pTxtCursor->GetLineHeight() < nY &&
[ # # ]
2364 : 0 : pTxtCursor->Next() )
2365 : : ; // nothing
2366 : 0 : nWidth = pTxtCursor->pCurr->Width();
2367 : 0 : nOldProp = pTxtCursor->GetPropFont();
2368 : :
2369 [ # # ][ # # ]: 0 : if ( pMulti->IsDouble() || pMulti->IsBidi() )
[ # # ]
2370 : : {
2371 : 0 : bSpaceChg = pMulti->ChgSpaceAdd( pTxtCursor->pCurr, nSpaceAdd );
2372 : :
2373 : : sal_uInt16 nSpaceCnt;
2374 [ # # ]: 0 : if ( pMulti->IsDouble() )
2375 : : {
2376 : 0 : pTxtCursor->SetPropFont( 50 );
2377 : 0 : nSpaceCnt = ((SwDoubleLinePortion*)pMulti)->GetSpaceCnt();
2378 : : }
2379 : : else
2380 : : {
2381 : 0 : const xub_StrLen nOldIdx = pTxtCursor->GetInfo().GetIdx();
2382 : 0 : pTxtCursor->GetInfo().SetIdx ( nCurrStart );
2383 : 0 : nSpaceCnt = ((SwBidiPortion*)pMulti)->GetSpaceCnt(pTxtCursor->GetInfo());
2384 : 0 : pTxtCursor->GetInfo().SetIdx ( nOldIdx );
2385 : : }
2386 : :
2387 [ # # ][ # # ]: 0 : if( nSpaceAdd > 0 && !pMulti->HasTabulator() )
[ # # ]
2388 : 0 : pTxtCursor->pCurr->Width( static_cast<sal_uInt16>(nWidth + nSpaceAdd * nSpaceCnt / SPACING_PRECISION_FACTOR ) );
2389 : :
2390 : : // For a BidiPortion we have to calculate the offset from the
2391 : : // end of the portion
2392 [ # # ][ # # ]: 0 : if ( nX && pMulti->IsBidi() )
[ # # ]
2393 : 0 : nX = pTxtCursor->pCurr->Width() - nX;
2394 : : }
2395 : : else
2396 : 0 : bSpaceChg = sal_False;
2397 : 0 : }
2398 : :
2399 : 0 : SwTxtCursorSave::~SwTxtCursorSave()
2400 : : {
2401 [ # # ]: 0 : if( bSpaceChg )
2402 : 0 : SwDoubleLinePortion::ResetSpaceAdd( pTxtCrsr->pCurr );
2403 : 0 : pTxtCrsr->pCurr->Width( KSHORT(nWidth) );
2404 : 0 : pTxtCrsr->pCurr = pCurr;
2405 : 0 : pTxtCrsr->nStart = nStart;
2406 : 0 : pTxtCrsr->SetPropFont( nOldProp );
2407 : 0 : }
2408 : :
2409 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|