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