LibreOffice Module sw (master)  1
txttab.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 <hintids.hxx>
21 #include <comphelper/string.hxx>
22 #include <editeng/tstpitem.hxx>
23 #include <rtl/ustrbuf.hxx>
25 #include <doc.hxx>
26 #include <SwPortionHandler.hxx>
27 
28 #include <viewopt.hxx>
29 #include "portab.hxx"
30 #include "inftxt.hxx"
31 #include "itrform2.hxx"
32 #include <txtfrm.hxx>
33 #include "porfld.hxx"
34 #include <memory>
35 
43 const SvxTabStop* SwLineInfo::GetTabStop(const SwTwips nSearchPos, SwTwips& nRight) const
44 {
45  for( sal_uInt16 i = 0; i < m_pRuler->Count(); ++i )
46  {
47  const SvxTabStop &rTabStop = m_pRuler->operator[](i);
48  if (nRight && rTabStop.GetTabPos() > nRight)
49  {
50  // Consider the first tabstop to always be in-bounds.
51  if (!i)
52  nRight = rTabStop.GetTabPos();
53  return i ? nullptr : &rTabStop;
54  }
55  if( rTabStop.GetTabPos() > nSearchPos )
56  {
57  if (!i && !nRight)
58  nRight = rTabStop.GetTabPos();
59  return &rTabStop;
60  }
61  }
62  return nullptr;
63 }
64 
65 sal_uInt16 SwLineInfo::NumberOfTabStops() const
66 {
67  return m_pRuler->Count();
68 }
69 
71 {
73  const bool bTabOverSpacing = rIDSA.get(DocumentSettingId::TAB_OVER_SPACING);
74  const bool bTabsRelativeToIndent = rIDSA.get(DocumentSettingId::TABS_RELATIVE_TO_INDENT);
75 
76  // Update search location - since Center/Decimal tabstops' width is dependent on the following text.
77  SwTabPortion* pTmpLastTab = rInf.GetLastTab();
78  if (pTmpLastTab && (pTmpLastTab->IsTabCenterPortion() || pTmpLastTab->IsTabDecimalPortion()))
79  pTmpLastTab->PostFormat(rInf);
80 
81  sal_Unicode cFill = 0;
82  sal_Unicode cDec = 0;
83  SvxTabAdjust eAdj;
84 
85  sal_uInt16 nNewTabPos;
86  bool bAutoTabStop = true;
87  {
88  const bool bRTL = m_pFrame->IsRightToLeft();
89  // #i24363# tab stops relative to indent
90  // nTabLeft: The absolute value, the tab stops are relative to: Tabs origin.
91 
92  // #i91133#
93  const SwTwips nTabLeft = bRTL
94  ? m_pFrame->getFrameArea().Right() -
95  ( bTabsRelativeToIndent ? GetTabLeft() : 0 )
96  : m_pFrame->getFrameArea().Left() +
97  ( bTabsRelativeToIndent ? GetTabLeft() : 0 );
98 
99  // The absolute position, where we started the line formatting
100  SwTwips nLinePos = GetLeftMargin();
101  if ( bRTL )
102  {
103  Point aPoint( nLinePos, 0 );
104  m_pFrame->SwitchLTRtoRTL( aPoint );
105  nLinePos = aPoint.X();
106  }
107 
108  // The current position, relative to the line start
109  SwTwips nTabPos = rInf.GetLastTab() ? rInf.GetLastTab()->GetTabPos() : 0;
110  if( nTabPos < rInf.X() )
111  {
112  nTabPos = rInf.X();
113  }
114 
115  // The current position in absolute coordinates
116  const SwTwips nCurrentAbsPos = bRTL ?
117  nLinePos - nTabPos :
118  nLinePos + nTabPos;
119 
120  SwTwips nMyRight;
121  if ( m_pFrame->IsVertLR() )
122  nMyRight = Left();
123  else
124  nMyRight = Right();
125 
126  if ( m_pFrame->IsVertical() )
127  {
128  Point aRightTop( nMyRight, m_pFrame->getFrameArea().Top() );
129  m_pFrame->SwitchHorizontalToVertical( aRightTop );
130  nMyRight = aRightTop.Y();
131  }
132 
133  SwTwips nNextPos = 0;
134  bool bAbsoluteNextPos = false;
135 
136  // #i24363# tab stops relative to indent
137  // nSearchPos: The current position relative to the tabs origin
138  const SwTwips nSearchPos = bRTL ?
139  nTabLeft - nCurrentAbsPos :
140  nCurrentAbsPos - nTabLeft;
141 
142  // First, we examine the tab stops set at the paragraph style or
143  // any hard set tab stops:
144  // Note: If there are no user defined tab stops, there is always a
145  // default tab stop.
146  const SwTwips nOldRight = nMyRight;
147  // Accept left-tabstops beyond the paragraph margin for bTabOverSpacing
148  if (bTabOverSpacing)
149  nMyRight = 0;
150  const SvxTabStop* pTabStop = m_aLineInf.GetTabStop( nSearchPos, nMyRight );
151  if (!nMyRight)
152  nMyRight = nOldRight;
153  if (pTabStop)
154  {
155  cFill = ' ' != pTabStop->GetFill() ? pTabStop->GetFill() : 0;
156  cDec = pTabStop->GetDecimal();
157  eAdj = pTabStop->GetAdjustment();
158  nNextPos = pTabStop->GetTabPos();
159  if(!bTabsRelativeToIndent && eAdj == SvxTabAdjust::Default && nSearchPos < 0)
160  {
161  //calculate default tab position of default tabs in negative indent
162  nNextPos = ( nSearchPos / nNextPos ) * nNextPos;
163  }
164  else if (pTabStop->GetTabPos() > nMyRight
165  && pTabStop->GetAdjustment() != SvxTabAdjust::Left)
166  {
167  // A rather special situation. The tabstop found is:
168  // 1.) in a document compatible with MS formats
169  // 2.) not a left tabstop.
170  // 3.) not the first tabstop (in that case nMyRight was adjusted to match tabPos).
171  // 4.) beyond the end of the text area
172  // Therefore, they act like right-tabstops at the edge of the para area.
173  // This benefits DOCX 2013+, and doesn't hurt the earlier formats,
174  // since up till now these were just treated as automatic tabstops.
175  eAdj = SvxTabAdjust::Right;
176  bAbsoluteNextPos = true;
177  nNextPos = rInf.Width();
178  }
179  bAutoTabStop = false;
180  }
181  else
182  {
183  sal_uInt16 nDefTabDist = m_aLineInf.GetDefTabStop();
184  if( USHRT_MAX == nDefTabDist )
185  {
186  const SvxTabStopItem& rTab =
188  if( rTab.Count() )
189  nDefTabDist = o3tl::narrowing<sal_uInt16>(rTab[0].GetTabPos());
190  else
191  nDefTabDist = SVX_TAB_DEFDIST;
192  m_aLineInf.SetDefTabStop( nDefTabDist );
193  }
194  SwTwips nCount = nSearchPos;
195 
196  // Minimum tab stop width is 1
197  if (nDefTabDist <= 0)
198  nDefTabDist = 1;
199 
200  nCount /= nDefTabDist;
201  nNextPos = ( nCount < 0 || ( !nCount && nSearchPos <= 0 ) )
202  ? ( nCount * nDefTabDist )
203  : ( ( nCount + 1 ) * nDefTabDist );
204 
205  // --> FME 2004-09-21 #117919 Minimum tab stop width is 1 or 51 twips:
206  const SwTwips nMinimumTabWidth = m_pFrame->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_COMPAT) ? 0 : 50;
207  if( ( bRTL && nTabLeft - nNextPos >= nCurrentAbsPos - nMinimumTabWidth ) ||
208  ( !bRTL && nNextPos + nTabLeft <= nCurrentAbsPos + nMinimumTabWidth ) )
209  {
210  nNextPos += nDefTabDist;
211  }
212  cFill = 0;
213  eAdj = SvxTabAdjust::Left;
214  }
215 
216  // #i115705# - correction and refactoring:
217  // overrule determined next tab stop position in order to apply
218  // a tab stop at the left margin under the following conditions:
219  // - the new tab portion is inside the hanging indent
220  // - a tab stop at the left margin is allowed
221  // - the determined next tab stop is a default tab stop position OR
222  // the determined next tab stop is beyond the left margin
223  {
224  tools::Long nLeftMarginTabPos = 0;
225  {
226  if ( !bTabsRelativeToIndent )
227  {
228  if ( bRTL )
229  {
230  Point aPoint( Left(), 0 );
231  m_pFrame->SwitchLTRtoRTL( aPoint );
232  nLeftMarginTabPos = m_pFrame->getFrameArea().Right() - aPoint.X();
233  }
234  else
235  {
236  nLeftMarginTabPos = Left() - m_pFrame->getFrameArea().Left();
237  }
238  }
240  {
242  while( pPor && !pPor->IsFlyPortion() )
243  {
244  pPor = pPor->GetNextPortion();
245  }
246  if ( pPor )
247  {
248  nLeftMarginTabPos += pPor->Width();
249  }
250  }
251  }
252  const bool bNewTabPortionInsideHangingIndent =
253  bRTL ? nCurrentAbsPos > nTabLeft - nLeftMarginTabPos
254  : nCurrentAbsPos < nTabLeft + nLeftMarginTabPos;
255  if ( bNewTabPortionInsideHangingIndent )
256  {
257  // If the paragraph is not inside a list having a list tab stop following
258  // the list label or no further tab stop found in such a paragraph or
259  // the next tab stop position does not equal the list tab stop,
260  // a tab stop at the left margin can be applied. If this condition is
261  // not hold, it is overruled by compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST.
262  const bool bTabAtLeftMarginAllowed =
264  !pTabStop ||
265  nNextPos != m_aLineInf.GetListTabStopPosition() ) ||
266  // compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST:
269  if ( bTabAtLeftMarginAllowed )
270  {
271  if ( !pTabStop || eAdj == SvxTabAdjust::Default ||
272  ( nNextPos > nLeftMarginTabPos ) )
273  {
274  eAdj = SvxTabAdjust::Default;
275  cFill = 0;
276  nNextPos = nLeftMarginTabPos;
277  }
278  }
279  }
280  }
281 
282  if (!bAbsoluteNextPos)
283  nNextPos += bRTL ? nLinePos - nTabLeft : nTabLeft - nLinePos;
284  OSL_ENSURE( nNextPos >= 0, "GetTabStop: Don't go back!" );
285  nNewTabPos = sal_uInt16(nNextPos);
286  }
287 
288  SwTabPortion *pTabPor = nullptr;
289  if ( bAuto )
290  {
291  if ( SvxTabAdjust::Decimal == eAdj &&
293  pTabPor = new SwAutoTabDecimalPortion( nNewTabPos, cDec, cFill );
294  }
295  else
296  {
297  switch( eAdj )
298  {
299  case SvxTabAdjust::Right :
300  {
301  pTabPor = new SwTabRightPortion( nNewTabPos, cFill );
302  break;
303  }
304  case SvxTabAdjust::Center :
305  {
306  pTabPor = new SwTabCenterPortion( nNewTabPos, cFill );
307  break;
308  }
309  case SvxTabAdjust::Decimal :
310  {
311  pTabPor = new SwTabDecimalPortion( nNewTabPos, cDec, cFill );
312  break;
313  }
314  default:
315  {
316  OSL_ENSURE( SvxTabAdjust::Left == eAdj || SvxTabAdjust::Default == eAdj,
317  "+SwTextFormatter::NewTabPortion: unknown adjustment" );
318  pTabPor = new SwTabLeftPortion( nNewTabPos, cFill, bAutoTabStop );
319  break;
320  }
321  }
322  }
323 
324  return pTabPor;
325 }
326 
330 SwTabPortion::SwTabPortion( const sal_uInt16 nTabPosition, const sal_Unicode cFillChar, const bool bAutoTab )
331  : m_nTabPos(nTabPosition), m_cFill(cFillChar), m_bAutoTabStop( bAutoTab )
332 {
334  OSL_ENSURE(!IsFilled() || ' ' != m_cFill, "SwTabPortion::CTOR: blanks ?!");
336 }
337 
339 {
340  SwTabPortion *pLastTab = rInf.GetLastTab();
341  if( pLastTab == this )
342  return PostFormat( rInf );
343  if( pLastTab )
344  pLastTab->PostFormat( rInf );
345  return PreFormat( rInf );
346 }
347 
349 {
350  if( rInf.GetLastTab() == this )
351  PostFormat( rInf );
352 }
353 
355 {
356  OSL_ENSURE( rInf.X() <= GetTabPos(), "SwTabPortion::PreFormat: rush hour" );
357 
358  // Here we settle down ...
359  SetFix( o3tl::narrowing<sal_uInt16>(rInf.X()) );
360 
362  const bool bTabCompat = rIDSA.get(DocumentSettingId::TAB_COMPAT);
363  const bool bTabOverflow = rIDSA.get(DocumentSettingId::TAB_OVERFLOW);
364  const bool bTabOverMargin = rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN);
365  const bool bTabOverSpacing = rIDSA.get(DocumentSettingId::TAB_OVER_SPACING);
366  const sal_Int32 nTextFrameWidth = rInf.GetTextFrame()->getFrameArea().Width();
367 
368  // The minimal width of a tab is one blank at least.
369  // #i37686# In compatibility mode, the minimum width
370  // should be 1, even for non-left tab stops.
371  sal_uInt16 nMinimumTabWidth = 1;
372  if ( !bTabCompat )
373  {
374  // #i89179#
375  // tab portion representing the list tab of a list label gets the
376  // same font as the corresponding number portion
377  std::unique_ptr< SwFontSave > pSave;
378  if ( GetLen() == TextFrameIndex(0) &&
379  rInf.GetLast() && rInf.GetLast()->InNumberGrp() &&
380  static_cast<SwNumberPortion*>(rInf.GetLast())->HasFont() )
381  {
382  const SwFont* pNumberPortionFont =
383  static_cast<SwNumberPortion*>(rInf.GetLast())->GetFont();
384  pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) );
385  }
386  OUString aTmp( ' ' );
387  SwTextSizeInfo aInf( rInf, &aTmp );
388  nMinimumTabWidth = aInf.GetTextSize().Width();
389  }
390  PrtWidth( nMinimumTabWidth );
391 
392  // Break tab stop to next line if:
393  // 1. Minimal width does not fit to line anymore.
394  // 2. An underflow event was called for the tab portion.
395  bool bFull = ( bTabCompat && rInf.IsUnderflow() ) ||
396  ( rInf.Width() <= rInf.X() + PrtWidth() && rInf.X() <= rInf.Width() ) ;
397 
398  // #95477# Rotated tab stops get the width of one blank
399  const Degree10 nDir = rInf.GetFont()->GetOrientation( rInf.GetTextFrame()->IsVertical() );
400 
401  if( ! bFull && 0_deg10 == nDir )
402  {
403  const PortionType nWhich = GetWhichPor();
404  switch( nWhich )
405  {
409  {
410  if( PortionType::TabDecimal == nWhich )
411  rInf.SetTabDecimal(
412  static_cast<SwTabDecimalPortion*>(this)->GetTabDecimal());
413  rInf.SetLastTab( this );
414  break;
415  }
417  {
418  // handle this case in PostFormat
419  if ((bTabOverMargin || bTabOverSpacing) && GetTabPos() > rInf.Width()
420  && (!m_bAutoTabStop || (!bTabOverMargin && rInf.X() > rInf.Width())))
421  {
422  if (bTabOverMargin || GetTabPos() < nTextFrameWidth)
423  {
424  rInf.SetLastTab(this);
425  break;
426  }
427  else
428  {
429  assert(!bTabOverMargin && bTabOverSpacing && GetTabPos() >= nTextFrameWidth);
430  bFull = true;
431  break;
432  }
433  }
434 
435  PrtWidth( o3tl::narrowing<sal_uInt16>(GetTabPos() - rInf.X()) );
436  bFull = rInf.Width() <= rInf.X() + PrtWidth();
437 
438  // In tabulator compatibility mode, we reset the bFull flag
439  // if the tabulator is at the end of the paragraph and the
440  // tab stop position is outside the frame:
441  bool bAtParaEnd = rInf.GetIdx() + GetLen() == TextFrameIndex(rInf.GetText().getLength());
442  if ( bFull && bTabCompat &&
443  ( ( bTabOverflow && ( rInf.IsTabOverflow() || !m_bAutoTabStop ) ) || bAtParaEnd ) &&
444  GetTabPos() >= nTextFrameWidth)
445  {
446  bFull = false;
447  if ( bTabOverflow && !m_bAutoTabStop )
448  rInf.SetTabOverflow( true );
449  }
450 
451  break;
452  }
453  default: OSL_ENSURE( false, "SwTabPortion::PreFormat: unknown adjustment" );
454  }
455  }
456 
457  if( bFull )
458  {
459  // We have to look for endless loops, if the width is smaller than one blank
460  if( rInf.GetIdx() == rInf.GetLineStart() &&
461  // #119175# TabStop should be forced to current
462  // line if there is a fly reducing the line width:
463  !rInf.GetFly() )
464  {
465  PrtWidth( o3tl::narrowing<sal_uInt16>(rInf.Width() - rInf.X()) );
466  SetFixWidth( PrtWidth() );
467  }
468  else
469  {
470  Height( 0 );
471  Width( 0 );
472  SetLen( TextFrameIndex(0) );
473  SetAscent( 0 );
474  SetNextPortion( nullptr ); //?????
475  }
476  return true;
477  }
478  else
479  {
480  // A trick with impact: The new Tabportions now behave like
481  // FlyFrames, located in the line - including adjustment !
482  SetFixWidth( PrtWidth() );
483  return false;
484  }
485 }
486 
488 {
489  bool bTabOverMargin = rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
491  bool bTabOverSpacing = rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
493  if (rInf.GetTextFrame()->IsInSct())
494  bTabOverMargin = false;
495 
496  // If the tab position is larger than the right margin, it gets scaled down by default.
497  // However, if compat mode enabled, we allow tabs to go over the margin: the rest of the paragraph is not broken into lines.
498  const sal_uInt16 nRight
499  = bTabOverMargin
500  ? GetTabPos()
501  : bTabOverSpacing
502  ? std::min<long>(GetTabPos(), rInf.GetTextFrame()->getFrameArea().Right())
503  : std::min(GetTabPos(), rInf.Width());
504  const SwLinePortion *pPor = GetNextPortion();
505 
506  sal_uInt16 nPorWidth = 0;
507  while( pPor )
508  {
509  nPorWidth = nPorWidth + pPor->Width();
510  pPor = pPor->GetNextPortion();
511  }
512 
513  const PortionType nWhich = GetWhichPor();
515 
516  if ((bTabOverMargin || bTabOverSpacing) && PortionType::TabLeft == nWhich)
517  {
518  nPorWidth = 0;
519  }
520 
521  // #127428# Abandon dec. tab position if line is full
522  if ( bTabCompat && PortionType::TabDecimal == nWhich )
523  {
524  sal_uInt16 nPrePorWidth = static_cast<const SwTabDecimalPortion*>(this)->GetWidthOfPortionsUpToDecimalPosition();
525 
526  // no value was set => no decimal character was found
527  if ( USHRT_MAX != nPrePorWidth )
528  {
529  if ( !bTabOverMargin && nPrePorWidth && nPorWidth - nPrePorWidth > rInf.Width() - nRight )
530  {
531  nPrePorWidth += nPorWidth - nPrePorWidth - ( rInf.Width() - nRight );
532  }
533 
534  nPorWidth = nPrePorWidth - 1;
535  }
536  }
537 
538  if( PortionType::TabCenter == nWhich )
539  {
540  // centered tabs are problematic:
541  // We have to detect how much fits into the line.
542  sal_uInt16 nNewWidth = nPorWidth /2;
543  if (!bTabOverMargin && !bTabOverSpacing && nNewWidth > rInf.Width() - nRight)
544  nNewWidth = nPorWidth - (rInf.Width() - nRight);
545  nPorWidth = nNewWidth;
546  }
547 
548  const sal_uInt16 nDiffWidth = nRight - GetFix();
549 
550  if( nDiffWidth > nPorWidth )
551  {
552  const sal_uInt16 nOldWidth = GetFixWidth();
553  const sal_uInt16 nAdjDiff = nDiffWidth - nPorWidth;
554  if( nAdjDiff > GetFixWidth() )
555  PrtWidth( nAdjDiff );
556  // Don't be afraid: we have to move rInf further.
557  // The right-tab till now only had the width of one blank.
558  // Now that we stretched, the difference had to be added to rInf.X() !
559  rInf.X( rInf.X() + PrtWidth() - nOldWidth );
560  }
561  SetFixWidth( PrtWidth() );
562  // reset last values
563  rInf.SetLastTab(nullptr);
564  if( PortionType::TabDecimal == nWhich )
565  rInf.SetTabDecimal(0);
566 
567  return rInf.Width() <= rInf.X();
568 }
569 
573 void SwTabPortion::Paint( const SwTextPaintInfo &rInf ) const
574 {
575  // #i89179#
576  // tab portion representing the list tab of a list label gets the
577  // same font as the corresponding number portion
578  std::unique_ptr< SwFontSave > pSave;
579  bool bAfterNumbering = false;
580  if (GetLen() == TextFrameIndex(0))
581  {
582  const SwLinePortion* pPrevPortion =
583  const_cast<SwTabPortion*>(this)->FindPrevPortion( rInf.GetParaPortion() );
584  if ( pPrevPortion &&
585  pPrevPortion->InNumberGrp() &&
586  static_cast<const SwNumberPortion*>(pPrevPortion)->HasFont() )
587  {
588  const SwFont* pNumberPortionFont =
589  static_cast<const SwNumberPortion*>(pPrevPortion)->GetFont();
590  pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) );
591  bAfterNumbering = true;
592  }
593  }
594  rInf.DrawBackBrush( *this );
595  if( !bAfterNumbering )
596  rInf.DrawBorder( *this );
597 
598  // do we have to repaint a post it portion?
599  if( rInf.OnWin() && mpNextPortion && !mpNextPortion->Width() )
600  mpNextPortion->PrePaint( rInf, this );
601 
602  // display special characters
603  if( rInf.OnWin() && rInf.GetOpt().IsTab() )
604  {
605  // filled tabs are shaded in gray
606  if( IsFilled() )
607  rInf.DrawViewOpt( *this, PortionType::Table );
608  else
609  rInf.DrawTab( *this );
610  }
611 
612  // Tabs should be underlined at once
613  if( rInf.GetFont()->IsPaintBlank() )
614  {
615  // Tabs with filling/filled tabs
616  const sal_uInt16 nCharWidth = rInf.GetTextSize(OUString(' ')).Width();
617 
618  // Robust:
619  if( nCharWidth )
620  {
621  // Always with kerning, also on printer!
622  sal_uInt16 nChar = Width() / nCharWidth;
623  OUStringBuffer aBuf;
624  comphelper::string::padToLength(aBuf, nChar, ' ');
625  rInf.DrawText(aBuf.makeStringAndClear(), *this, TextFrameIndex(0),
626  TextFrameIndex(nChar), true);
627  }
628  }
629 
630  // Display fill characters
631  if( !IsFilled() )
632  return;
633 
634  // Tabs with filling/filled tabs
635  const sal_uInt16 nCharWidth = rInf.GetTextSize(OUString(m_cFill)).Width();
636  OSL_ENSURE( nCharWidth, "!SwTabPortion::Paint: sophisticated tabchar" );
637 
638  // Robust:
639  if( nCharWidth )
640  {
641  // Always with kerning, also on printer!
642  sal_uInt16 nChar = Width() / nCharWidth;
643  if ( m_cFill == '_' )
644  ++nChar; // to avoid gaps
645  OUStringBuffer aBuf;
647  rInf.DrawText(aBuf.makeStringAndClear(), *this, TextFrameIndex(0),
648  TextFrameIndex(nChar), true);
649  }
650 }
651 
653 {
654 }
655 
657 {
658  rPH.Text( GetLen(), GetWhichPor(), Height(), Width() );
659 }
660 
661 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::unique_ptr< SvxTabStopItem > m_pRuler
Definition: inftxt.hxx:64
void Right(const tools::Long nRight)
Definition: swrect.hxx:199
void DrawBackBrush(const SwLinePortion &rPor) const
Definition: inftxt.cxx:1118
sal_uInt16 Count() const
constexpr TypedWhichId< SvxTabStopItem > RES_PARATR_TABSTOP(68)
bool IsInSct() const
Definition: frame.hxx:968
bool IsUnderflow() const
Definition: inftxt.hxx:582
SwFont * GetFont()
Definition: inftxt.hxx:231
bool PreFormat(SwTextFormatInfo &rInf)
Definition: txttab.cxx:354
bool InNumberGrp() const
Definition: porlin.hxx:103
void SetFix(const sal_uInt16 nNewFix)
Definition: porglue.hxx:55
SwTwips GetTabLeft() const
Definition: itrtxt.hxx:197
void Left(const tools::Long nLeft)
Definition: swrect.hxx:194
void SetFixWidth(const sal_uInt16 nNew)
Definition: porglue.hxx:38
void SwitchHorizontalToVertical(SwRect &rRect) const
Calculates the coordinates of a rectangle when switching from horizontal to vertical layout...
Definition: txtfrm.cxx:475
long Long
The SwPortionHandler interface implements a visitor for the layout engine's text portions.
SwTabPortion * NewTabPortion(SwTextFormatInfo &rInf, bool bAuto) const
Definition: txttab.cxx:70
SwTabPortion * GetLastTab()
Definition: inftxt.hxx:614
void DrawBorder(const SwLinePortion &rPor) const
Draw character border around a line portion.
Definition: inftxt.cxx:1265
aBuf
virtual void Paint(const SwTextPaintInfo &rInf) const override
Ex: LineIter::DrawTab()
Definition: txttab.cxx:573
void SetLen(TextFrameIndex const nLen)
Definition: porlin.hxx:76
bool PostFormat(SwTextFormatInfo &rInf)
Definition: txttab.cxx:487
void DrawText(const OUString &rText, const SwLinePortion &rPor, TextFrameIndex nIdx=TextFrameIndex(0), TextFrameIndex nLen=TextFrameIndex(COMPLETE_STRING), const bool bKern=false) const
Definition: inftxt.hxx:740
SwLineInfo m_aLineInf
Definition: itrtxt.hxx:33
sal_uInt16 GetFix() const
Definition: porglue.hxx:56
bool HasForcedLeftMargin() const
Definition: porlay.hxx:145
SwPosSize GetTextSize(OutputDevice *pOut, const SwScriptInfo *pSI, const OUString &rText, TextFrameIndex nIdx, TextFrameIndex nLen) const
Definition: inftxt.cxx:382
virtual void Text(TextFrameIndex nLength, PortionType nType, sal_Int32 nHeight=0, sal_Int32 nWidth=0)=0
(empty) destructor
Degree10 GetOrientation(const bool bVertLayout=false, const bool bVertFormatLRBT=false) const
Definition: swfont.cxx:412
void SetDefTabStop(sal_uInt16 nNew) const
Definition: inftxt.hxx:81
bool IsFilled() const
Definition: portab.hxx:37
sal_uInt16 sal_Unicode
bool IsTabDecimalPortion() const
Definition: porlin.hxx:121
void SetLastTab(SwTabPortion *pNew)
Definition: inftxt.hxx:615
bool IsTabOverflow() const
Definition: inftxt.hxx:662
const SwRect & getFrameArea() const
Definition: frame.hxx:180
int nCount
SwTwips Right() const
Definition: itrtxt.hxx:181
sal_Int32 & GetTabPos()
void DrawViewOpt(const SwLinePortion &rPor, PortionType nWhich, const Color *pColor=nullptr) const
Definition: inftxt.cxx:1277
void Width(tools::Long nNew)
Definition: swrect.hxx:186
sal_Unicode & GetDecimal()
const bool m_bAutoTabStop
Definition: portab.hxx:27
void SetAscent(const sal_uInt32 nNewAsc)
Definition: porlin.hxx:80
TextFrameIndex GetLineStart() const
Definition: inftxt.hxx:589
SwAttrPool * GetPool() const
Definition: swatrset.hxx:183
const SwAttrSet * GetAttrSet() const
WARNING: this may not return correct RES_PAGEDESC/RES_BREAK items for SwTextFrame, use GetBreakItem()/GetPageDescItem() instead.
Definition: findfrm.cxx:677
SvxTabAdjust & GetAdjustment()
SwTabPortion(const sal_uInt16 nTabPos, const sal_Unicode cFill, const bool bAutoTab=true)
The base class is initialized without setting anything.
Definition: txttab.cxx:330
const SwViewOption & GetOpt() const
Definition: inftxt.hxx:238
SwTwips Left() const
Definition: itrtxt.hxx:333
int i
const sal_Unicode m_cFill
Definition: portab.hxx:26
SwParaPortion * GetParaPortion()
Definition: inftxt.hxx:121
void SetWhichPor(const PortionType nNew)
Definition: porlin.hxx:95
bool IsTabCenterPortion() const
Definition: porlin.hxx:120
bool IsFlyPortion() const
Definition: porlin.hxx:128
SwTwips GetLeftMargin() const
Definition: itrtxt.hxx:328
sal_uInt16 Width() const
Definition: inftxt.hxx:527
Provides access to settings of a document.
bool IsTab(bool bHard=false) const
Definition: viewopt.hxx:219
PortionType
Definition: txttypes.hxx:23
sal_uInt16 GetTabPos() const
Definition: portab.hxx:38
void DrawTab(const SwLinePortion &rPor) const
Definition: inftxt.cxx:944
TextFrameIndex GetIdx() const
Definition: inftxt.hxx:271
void SetTabDecimal(const sal_Unicode cNew)
Definition: inftxt.hxx:617
void SetTabOverflow(bool bOverflow)
Definition: inftxt.hxx:661
void PrePaint(const SwTextPaintInfo &rInf, const SwLinePortion *pLast) const
Definition: porlin.cxx:76
vcl::Font GetFont(vcl::Font const &rFont, DrawModeFlags nDrawMode, StyleSettings const &rStyleSettings)
const SfxPoolItem & GetDefaultItem(sal_uInt16 nWhich) const
TextFrameIndex GetLen() const
Definition: porlin.hxx:75
SwTextFrame * GetTextFrame()
Definition: inftxt.hxx:284
tools::Long SwTwips
Definition: swtypes.hxx:52
bool IsPaintBlank() const
Definition: swfont.hxx:257
const OUString & GetText() const
Definition: inftxt.hxx:239
sal_uInt32 Height() const
Definition: possiz.hxx:49
SwLinePortion * mpNextPortion
Definition: porlin.hxx:55
SwTwips X() const
Definition: inftxt.hxx:378
void SwitchLTRtoRTL(SwRect &rRect) const
Calculates the coordinates of a rectangle when switching from LTR to RTL layout.
Definition: txtfrm.cxx:685
SwTextFrame * m_pFrame
Definition: itrtxt.hxx:34
Base class for anything that can be part of a line in the Writer layout.
Definition: porlin.hxx:51
TextFrameIndex mnLineLength
Definition: porlin.hxx:57
virtual bool Format(SwTextFormatInfo &rInf) override
Definition: txttab.cxx:338
bool IsVertLR() const
Definition: frame.hxx:980
virtual void Paint(const SwTextPaintInfo &rInf) const override
Ex: LineIter::DrawTab()
Definition: txttab.cxx:652
sal_uInt16 GetDefTabStop() const
Definition: inftxt.hxx:80
sal_Unicode & GetFill()
sal_uInt16 NumberOfTabStops() const
Definition: txttab.cxx:65
PortionType GetWhichPor() const
Definition: porlin.hxx:96
#define SVX_TAB_DEFDIST
IDocumentSettingAccess const & getIDocumentSettingAccess() const
Definition: doc.cxx:176
bool OnWin() const
Definition: inftxt.hxx:192
bool IsRightToLeft() const
Definition: frame.hxx:988
void Top(const tools::Long nTop)
Definition: swrect.hxx:203
SwLinePortion * FindPrevPortion(const SwLinePortion *pRoot)
Definition: porlin.cxx:209
SwLinePortion * GetLast()
Definition: inftxt.hxx:560
virtual bool get(DocumentSettingId id) const =0
Return the specified document setting.
void SetNextPortion(SwLinePortion *pNew)
Definition: porlin.hxx:77
const SvxTabStop * GetTabStop(const SwTwips nSearchPos, SwTwips &nRight) const
#i24363# tab stops relative to indent
Definition: txttab.cxx:43
bool IsVertical() const
Definition: frame.hxx:974
SwDoc & GetDoc()
Definition: txtfrm.hxx:460
SwLineLayout * m_pCurr
Definition: itrtxt.hxx:36
bool IsListTabStopIncluded() const
Definition: inftxt.hxx:94
SwFlyPortion * GetFly()
Definition: inftxt.hxx:608
sal_uInt32 Width() const
Definition: possiz.hxx:51
sal_uInt16 GetFixWidth() const
Definition: porglue.hxx:37
SwLinePortion * GetNextPortion() const
Definition: porlin.hxx:73
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...
virtual void FormatEOL(SwTextFormatInfo &rInf) override
Definition: txttab.cxx:348
tools::Long GetListTabStopPosition() const
Definition: inftxt.hxx:98
sal_uInt32 PrtWidth() const
Definition: porlin.hxx:82
SvxTabAdjust
virtual void HandlePortion(SwPortionHandler &rPH) const override
Definition: txttab.cxx:656
OStringBuffer & padToLength(OStringBuffer &rBuffer, sal_Int32 nLength, char cFill= '\0')