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