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