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