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