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>
24 #include <IDocumentSettingAccess.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
36 /**
37 * #i24363# tab stops relative to indent
38 *
39 * Return the first tab stop that is > nSearchPos.
40 * If the tab stop is outside the print area, we
41 * return 0 if it is not the first tab stop.
42 */
GetTabStop(const SwTwips nSearchPos,const SwTwips nRight) const43 const SvxTabStop *SwLineInfo::GetTabStop( const SwTwips nSearchPos, const 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( rTabStop.GetTabPos() > SwTwips(nRight) )
49 return i ? nullptr : &rTabStop;
50
51 if( rTabStop.GetTabPos() > nSearchPos )
52 return &rTabStop;
53 }
54 return nullptr;
55 }
56
NumberOfTabStops() const57 sal_uInt16 SwLineInfo::NumberOfTabStops() const
58 {
59 return m_pRuler->Count();
60 }
61
NewTabPortion(SwTextFormatInfo & rInf,bool bAuto) const62 SwTabPortion *SwTextFormatter::NewTabPortion( SwTextFormatInfo &rInf, bool bAuto ) const
63 {
64 // Update search location - since Center/Decimal tabstops' width is dependent on the following text.
65 SwTabPortion* pTmpLastTab = rInf.GetLastTab();
66 if (pTmpLastTab && (pTmpLastTab->IsTabCenterPortion() || pTmpLastTab->IsTabDecimalPortion()))
67 pTmpLastTab->PostFormat(rInf);
68
69 sal_Unicode cFill = 0;
70 sal_Unicode cDec = 0;
71 SvxTabAdjust eAdj;
72
73 sal_uInt16 nNewTabPos;
74 bool bAutoTabStop = true;
75 {
76 const bool bRTL = m_pFrame->IsRightToLeft();
77 // #i24363# tab stops relative to indent
78 // nTabLeft: The absolute value, the tab stops are relative to: Tabs origin.
79
80 // #i91133#
81 const bool bTabsRelativeToIndent =
82 m_pFrame->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TABS_RELATIVE_TO_INDENT);
83 const SwTwips nTabLeft = bRTL
84 ? m_pFrame->getFrameArea().Right() -
85 ( bTabsRelativeToIndent ? GetTabLeft() : 0 )
86 : m_pFrame->getFrameArea().Left() +
87 ( bTabsRelativeToIndent ? GetTabLeft() : 0 );
88
89 // The absolute position, where we started the line formatting
90 SwTwips nLinePos = GetLeftMargin();
91 if ( bRTL )
92 {
93 Point aPoint( nLinePos, 0 );
94 m_pFrame->SwitchLTRtoRTL( aPoint );
95 nLinePos = aPoint.X();
96 }
97
98 // The current position, relative to the line start
99 SwTwips nTabPos = rInf.GetLastTab() ? rInf.GetLastTab()->GetTabPos() : 0;
100 if( nTabPos < rInf.X() )
101 {
102 nTabPos = rInf.X();
103 }
104
105 // The current position in absolute coordinates
106 const SwTwips nCurrentAbsPos = bRTL ?
107 nLinePos - nTabPos :
108 nLinePos + nTabPos;
109
110 SwTwips nMyRight;
111 if ( m_pFrame->IsVertLR() )
112 nMyRight = Left();
113 else
114 nMyRight = Right();
115
116 if ( m_pFrame->IsVertical() )
117 {
118 Point aRightTop( nMyRight, m_pFrame->getFrameArea().Top() );
119 m_pFrame->SwitchHorizontalToVertical( aRightTop );
120 nMyRight = aRightTop.Y();
121 }
122
123 SwTwips nNextPos = 0;
124
125 // #i24363# tab stops relative to indent
126 // nSearchPos: The current position relative to the tabs origin
127 const SwTwips nSearchPos = bRTL ?
128 nTabLeft - nCurrentAbsPos :
129 nCurrentAbsPos - nTabLeft;
130
131 // First, we examine the tab stops set at the paragraph style or
132 // any hard set tab stops:
133 // Note: If there are no user defined tab stops, there is always a
134 // default tab stop.
135 const SvxTabStop* pTabStop = m_aLineInf.GetTabStop( nSearchPos, nMyRight );
136 if ( pTabStop )
137 {
138 cFill = ' ' != pTabStop->GetFill() ? pTabStop->GetFill() : 0;
139 cDec = pTabStop->GetDecimal();
140 eAdj = pTabStop->GetAdjustment();
141 nNextPos = pTabStop->GetTabPos();
142 if(!bTabsRelativeToIndent && eAdj == SvxTabAdjust::Default && nSearchPos < 0)
143 {
144 //calculate default tab position of default tabs in negative indent
145 nNextPos = ( nSearchPos / nNextPos ) * nNextPos;
146 }
147 bAutoTabStop = false;
148 }
149 else
150 {
151 sal_uInt16 nDefTabDist = m_aLineInf.GetDefTabStop();
152 if( USHRT_MAX == nDefTabDist )
153 {
154 const SvxTabStopItem& rTab =
155 m_pFrame->GetAttrSet()->GetPool()->GetDefaultItem( RES_PARATR_TABSTOP );
156 if( rTab.Count() )
157 nDefTabDist = o3tl::narrowing<sal_uInt16>(rTab[0].GetTabPos());
158 else
159 nDefTabDist = SVX_TAB_DEFDIST;
160 m_aLineInf.SetDefTabStop( nDefTabDist );
161 }
162 SwTwips nCount = nSearchPos;
163
164 // Minimum tab stop width is 1
165 if (nDefTabDist <= 0)
166 nDefTabDist = 1;
167
168 nCount /= nDefTabDist;
169 nNextPos = ( nCount < 0 || ( !nCount && nSearchPos <= 0 ) )
170 ? ( nCount * nDefTabDist )
171 : ( ( nCount + 1 ) * nDefTabDist );
172
173 // --> FME 2004-09-21 #117919 Minimum tab stop width is 1 or 51 twips:
174 const SwTwips nMinimumTabWidth = m_pFrame->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_COMPAT) ? 0 : 50;
175 if( ( bRTL && nTabLeft - nNextPos >= nCurrentAbsPos - nMinimumTabWidth ) ||
176 ( !bRTL && nNextPos + nTabLeft <= nCurrentAbsPos + nMinimumTabWidth ) )
177 {
178 nNextPos += nDefTabDist;
179 }
180 cFill = 0;
181 eAdj = SvxTabAdjust::Left;
182 }
183
184 // #i115705# - correction and refactoring:
185 // overrule determined next tab stop position in order to apply
186 // a tab stop at the left margin under the following conditions:
187 // - the new tab portion is inside the hanging indent
188 // - a tab stop at the left margin is allowed
189 // - the determined next tab stop is a default tab stop position OR
190 // the determined next tab stop is beyond the left margin
191 {
192 tools::Long nLeftMarginTabPos = 0;
193 {
194 if ( !bTabsRelativeToIndent )
195 {
196 if ( bRTL )
197 {
198 Point aPoint( Left(), 0 );
199 m_pFrame->SwitchLTRtoRTL( aPoint );
200 nLeftMarginTabPos = m_pFrame->getFrameArea().Right() - aPoint.X();
201 }
202 else
203 {
204 nLeftMarginTabPos = Left() - m_pFrame->getFrameArea().Left();
205 }
206 }
207 if( m_pCurr->HasForcedLeftMargin() )
208 {
209 SwLinePortion* pPor = m_pCurr->GetNextPortion();
210 while( pPor && !pPor->IsFlyPortion() )
211 {
212 pPor = pPor->GetNextPortion();
213 }
214 if ( pPor )
215 {
216 nLeftMarginTabPos += pPor->Width();
217 }
218 }
219 }
220 const bool bNewTabPortionInsideHangingIndent =
221 bRTL ? nCurrentAbsPos > nTabLeft - nLeftMarginTabPos
222 : nCurrentAbsPos < nTabLeft + nLeftMarginTabPos;
223 if ( bNewTabPortionInsideHangingIndent )
224 {
225 // If the paragraph is not inside a list having a list tab stop following
226 // the list label or no further tab stop found in such a paragraph or
227 // the next tab stop position does not equal the list tab stop,
228 // a tab stop at the left margin can be applied. If this condition is
229 // not hold, it is overruled by compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST.
230 const bool bTabAtLeftMarginAllowed =
231 ( !m_aLineInf.IsListTabStopIncluded() ||
232 !pTabStop ||
233 nNextPos != m_aLineInf.GetListTabStopPosition() ) ||
234 // compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST:
235 m_pFrame->GetDoc().getIDocumentSettingAccess().
236 get(DocumentSettingId::TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST);
237 if ( bTabAtLeftMarginAllowed )
238 {
239 if ( !pTabStop || eAdj == SvxTabAdjust::Default ||
240 ( nNextPos > nLeftMarginTabPos ) )
241 {
242 eAdj = SvxTabAdjust::Default;
243 cFill = 0;
244 nNextPos = nLeftMarginTabPos;
245 }
246 }
247 }
248 }
249
250 nNextPos += bRTL ? nLinePos - nTabLeft : nTabLeft - nLinePos;
251 OSL_ENSURE( nNextPos >= 0, "GetTabStop: Don't go back!" );
252 nNewTabPos = sal_uInt16(nNextPos);
253 }
254
255 SwTabPortion *pTabPor = nullptr;
256 if ( bAuto )
257 {
258 if ( SvxTabAdjust::Decimal == eAdj &&
259 1 == m_aLineInf.NumberOfTabStops() )
260 pTabPor = new SwAutoTabDecimalPortion( nNewTabPos, cDec, cFill );
261 }
262 else
263 {
264 switch( eAdj )
265 {
266 case SvxTabAdjust::Right :
267 {
268 pTabPor = new SwTabRightPortion( nNewTabPos, cFill );
269 break;
270 }
271 case SvxTabAdjust::Center :
272 {
273 pTabPor = new SwTabCenterPortion( nNewTabPos, cFill );
274 break;
275 }
276 case SvxTabAdjust::Decimal :
277 {
278 pTabPor = new SwTabDecimalPortion( nNewTabPos, cDec, cFill );
279 break;
280 }
281 default:
282 {
283 OSL_ENSURE( SvxTabAdjust::Left == eAdj || SvxTabAdjust::Default == eAdj,
284 "+SwTextFormatter::NewTabPortion: unknown adjustment" );
285 pTabPor = new SwTabLeftPortion( nNewTabPos, cFill, bAutoTabStop );
286 break;
287 }
288 }
289 }
290
291 return pTabPor;
292 }
293
294 /**
295 * The base class is initialized without setting anything
296 */
SwTabPortion(const sal_uInt16 nTabPosition,const sal_Unicode cFillChar,const bool bAutoTab)297 SwTabPortion::SwTabPortion( const sal_uInt16 nTabPosition, const sal_Unicode cFillChar, const bool bAutoTab )
298 : SwFixPortion(), m_nTabPos(nTabPosition), m_cFill(cFillChar), m_bAutoTabStop( bAutoTab )
299 {
300 mnLineLength = TextFrameIndex(1);
301 OSL_ENSURE(!IsFilled() || ' ' != m_cFill, "SwTabPortion::CTOR: blanks ?!");
302 SetWhichPor( PortionType::Table );
303 }
304
Format(SwTextFormatInfo & rInf)305 bool SwTabPortion::Format( SwTextFormatInfo &rInf )
306 {
307 SwTabPortion *pLastTab = rInf.GetLastTab();
308 if( pLastTab == this )
309 return PostFormat( rInf );
310 if( pLastTab )
311 pLastTab->PostFormat( rInf );
312 return PreFormat( rInf );
313 }
314
FormatEOL(SwTextFormatInfo & rInf)315 void SwTabPortion::FormatEOL( SwTextFormatInfo &rInf )
316 {
317 if( rInf.GetLastTab() == this )
318 PostFormat( rInf );
319 }
320
PreFormat(SwTextFormatInfo & rInf)321 bool SwTabPortion::PreFormat( SwTextFormatInfo &rInf )
322 {
323 OSL_ENSURE( rInf.X() <= GetTabPos(), "SwTabPortion::PreFormat: rush hour" );
324
325 // Here we settle down ...
326 SetFix( o3tl::narrowing<sal_uInt16>(rInf.X()) );
327
328 IDocumentSettingAccess const& rIDSA(rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess());
329 const bool bTabCompat = rIDSA.get(DocumentSettingId::TAB_COMPAT);
330 const bool bTabOverflow = rIDSA.get(DocumentSettingId::TAB_OVERFLOW);
331 const bool bTabOverMargin = rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN);
332 const bool bTabOverSpacing = rIDSA.get(DocumentSettingId::TAB_OVER_SPACING);
333
334 // The minimal width of a tab is one blank at least.
335 // #i37686# In compatibility mode, the minimum width
336 // should be 1, even for non-left tab stops.
337 sal_uInt16 nMinimumTabWidth = 1;
338 if ( !bTabCompat )
339 {
340 // #i89179#
341 // tab portion representing the list tab of a list label gets the
342 // same font as the corresponding number portion
343 std::unique_ptr< SwFontSave > pSave;
344 if ( GetLen() == TextFrameIndex(0) &&
345 rInf.GetLast() && rInf.GetLast()->InNumberGrp() &&
346 static_cast<SwNumberPortion*>(rInf.GetLast())->HasFont() )
347 {
348 const SwFont* pNumberPortionFont =
349 static_cast<SwNumberPortion*>(rInf.GetLast())->GetFont();
350 pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) );
351 }
352 OUString aTmp( ' ' );
353 SwTextSizeInfo aInf( rInf, &aTmp );
354 nMinimumTabWidth = aInf.GetTextSize().Width();
355 }
356 PrtWidth( nMinimumTabWidth );
357
358 // Break tab stop to next line if:
359 // 1. Minimal width does not fit to line anymore.
360 // 2. An underflow event was called for the tab portion.
361 bool bFull = ( bTabCompat && rInf.IsUnderflow() ) ||
362 ( rInf.Width() <= rInf.X() + PrtWidth() && rInf.X() <= rInf.Width() ) ;
363
364 // #95477# Rotated tab stops get the width of one blank
365 const Degree10 nDir = rInf.GetFont()->GetOrientation( rInf.GetTextFrame()->IsVertical() );
366
367 if( ! bFull && 0_deg10 == nDir )
368 {
369 const PortionType nWhich = GetWhichPor();
370 switch( nWhich )
371 {
372 case PortionType::TabRight:
373 case PortionType::TabDecimal:
374 case PortionType::TabCenter:
375 {
376 if( PortionType::TabDecimal == nWhich )
377 rInf.SetTabDecimal(
378 static_cast<SwTabDecimalPortion*>(this)->GetTabDecimal());
379 rInf.SetLastTab( this );
380 break;
381 }
382 case PortionType::TabLeft:
383 {
384 // handle this case in PostFormat
385 if ((bTabOverMargin || bTabOverSpacing) && !m_bAutoTabStop && GetTabPos() > rInf.Width())
386 {
387 if (bTabOverMargin || GetTabPos() < rInf.GetTextFrame()->getFrameArea().Width())
388 {
389 rInf.SetLastTab(this);
390 break;
391 }
392 }
393
394 PrtWidth( o3tl::narrowing<sal_uInt16>(GetTabPos() - rInf.X()) );
395 bFull = rInf.Width() <= rInf.X() + PrtWidth();
396
397 // In tabulator compatibility mode, we reset the bFull flag
398 // if the tabulator is at the end of the paragraph and the
399 // tab stop position is outside the frame:
400 bool bAtParaEnd = rInf.GetIdx() + GetLen() == TextFrameIndex(rInf.GetText().getLength());
401 if ( bFull && bTabCompat &&
402 ( ( bTabOverflow && ( rInf.IsTabOverflow() || !m_bAutoTabStop ) ) || bAtParaEnd ) &&
403 GetTabPos() >= rInf.GetTextFrame()->getFrameArea().Width() )
404 {
405 bFull = false;
406 if ( bTabOverflow && !m_bAutoTabStop )
407 rInf.SetTabOverflow( true );
408 }
409
410 break;
411 }
412 default: OSL_ENSURE( false, "SwTabPortion::PreFormat: unknown adjustment" );
413 }
414 }
415
416 if( bFull )
417 {
418 // We have to look for endless loops, if the width is smaller than one blank
419 if( rInf.GetIdx() == rInf.GetLineStart() &&
420 // #119175# TabStop should be forced to current
421 // line if there is a fly reducing the line width:
422 !rInf.GetFly() )
423 {
424 PrtWidth( o3tl::narrowing<sal_uInt16>(rInf.Width() - rInf.X()) );
425 SetFixWidth( PrtWidth() );
426 }
427 else
428 {
429 Height( 0 );
430 Width( 0 );
431 SetLen( TextFrameIndex(0) );
432 SetAscent( 0 );
433 SetNextPortion( nullptr ); //?????
434 }
435 return true;
436 }
437 else
438 {
439 // A trick with impact: The new Tabportions now behave like
440 // FlyFrames, located in the line - including adjustment !
441 SetFixWidth( PrtWidth() );
442 return false;
443 }
444 }
445
PostFormat(SwTextFormatInfo & rInf)446 bool SwTabPortion::PostFormat( SwTextFormatInfo &rInf )
447 {
448 bool bTabOverMargin = rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
449 DocumentSettingId::TAB_OVER_MARGIN);
450 bool bTabOverSpacing = rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
451 DocumentSettingId::TAB_OVER_SPACING);
452 if (rInf.GetTextFrame()->IsInSct())
453 bTabOverMargin = false;
454
455 // If the tab position is larger than the right margin, it gets scaled down by default.
456 // However, if compat mode enabled, we allow tabs to go over the margin: the rest of the paragraph is not broken into lines.
457 const sal_uInt16 nRight
458 = bTabOverMargin
459 ? GetTabPos()
460 : bTabOverSpacing
461 ? std::min<long>(GetTabPos(), rInf.GetTextFrame()->getFrameArea().Right())
462 : std::min(GetTabPos(), rInf.Width());
463 const SwLinePortion *pPor = GetNextPortion();
464
465 sal_uInt16 nPorWidth = 0;
466 while( pPor )
467 {
468 nPorWidth = nPorWidth + pPor->Width();
469 pPor = pPor->GetNextPortion();
470 }
471
472 const PortionType nWhich = GetWhichPor();
473 const bool bTabCompat = rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_COMPAT);
474
475 if ((bTabOverMargin || bTabOverSpacing) && PortionType::TabLeft == nWhich)
476 {
477 nPorWidth = 0;
478 }
479
480 // #127428# Abandon dec. tab position if line is full
481 if ( bTabCompat && PortionType::TabDecimal == nWhich )
482 {
483 sal_uInt16 nPrePorWidth = static_cast<const SwTabDecimalPortion*>(this)->GetWidthOfPortionsUpToDecimalPosition();
484
485 // no value was set => no decimal character was found
486 if ( USHRT_MAX != nPrePorWidth )
487 {
488 if ( !bTabOverMargin && nPrePorWidth && nPorWidth - nPrePorWidth > rInf.Width() - nRight )
489 {
490 nPrePorWidth += nPorWidth - nPrePorWidth - ( rInf.Width() - nRight );
491 }
492
493 nPorWidth = nPrePorWidth - 1;
494 }
495 }
496
497 if( PortionType::TabCenter == nWhich )
498 {
499 // centered tabs are problematic:
500 // We have to detect how much fits into the line.
501 sal_uInt16 nNewWidth = nPorWidth /2;
502 if (!bTabOverMargin && !bTabOverSpacing && nNewWidth > rInf.Width() - nRight)
503 nNewWidth = nPorWidth - (rInf.Width() - nRight);
504 nPorWidth = nNewWidth;
505 }
506
507 const sal_uInt16 nDiffWidth = nRight - GetFix();
508
509 if( nDiffWidth > nPorWidth )
510 {
511 const sal_uInt16 nOldWidth = GetFixWidth();
512 const sal_uInt16 nAdjDiff = nDiffWidth - nPorWidth;
513 if( nAdjDiff > GetFixWidth() )
514 PrtWidth( nAdjDiff );
515 // Don't be afraid: we have to move rInf further.
516 // The right-tab till now only had the width of one blank.
517 // Now that we stretched, the difference had to be added to rInf.X() !
518 rInf.X( rInf.X() + PrtWidth() - nOldWidth );
519 }
520 SetFixWidth( PrtWidth() );
521 // reset last values
522 rInf.SetLastTab(nullptr);
523 if( PortionType::TabDecimal == nWhich )
524 rInf.SetTabDecimal(0);
525
526 return rInf.Width() <= rInf.X();
527 }
528
529 /**
530 * Ex: LineIter::DrawTab()
531 */
Paint(const SwTextPaintInfo & rInf) const532 void SwTabPortion::Paint( const SwTextPaintInfo &rInf ) const
533 {
534 // #i89179#
535 // tab portion representing the list tab of a list label gets the
536 // same font as the corresponding number portion
537 std::unique_ptr< SwFontSave > pSave;
538 bool bAfterNumbering = false;
539 if (GetLen() == TextFrameIndex(0))
540 {
541 const SwLinePortion* pPrevPortion =
542 const_cast<SwTabPortion*>(this)->FindPrevPortion( rInf.GetParaPortion() );
543 if ( pPrevPortion &&
544 pPrevPortion->InNumberGrp() &&
545 static_cast<const SwNumberPortion*>(pPrevPortion)->HasFont() )
546 {
547 const SwFont* pNumberPortionFont =
548 static_cast<const SwNumberPortion*>(pPrevPortion)->GetFont();
549 pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) );
550 bAfterNumbering = true;
551 }
552 }
553 rInf.DrawBackBrush( *this );
554 if( !bAfterNumbering )
555 rInf.DrawBorder( *this );
556
557 // do we have to repaint a post it portion?
558 if( rInf.OnWin() && mpNextPortion && !mpNextPortion->Width() )
559 mpNextPortion->PrePaint( rInf, this );
560
561 // display special characters
562 if( rInf.OnWin() && rInf.GetOpt().IsTab() )
563 {
564 // filled tabs are shaded in gray
565 if( IsFilled() )
566 rInf.DrawViewOpt( *this, PortionType::Table );
567 else
568 rInf.DrawTab( *this );
569 }
570
571 // Tabs should be underlined at once
572 if( rInf.GetFont()->IsPaintBlank() )
573 {
574 // Tabs with filling/filled tabs
575 const sal_uInt16 nCharWidth = rInf.GetTextSize(OUString(' ')).Width();
576
577 // Robust:
578 if( nCharWidth )
579 {
580 // Always with kerning, also on printer!
581 sal_uInt16 nChar = Width() / nCharWidth;
582 OUStringBuffer aBuf;
583 comphelper::string::padToLength(aBuf, nChar, ' ');
584 rInf.DrawText(aBuf.makeStringAndClear(), *this, TextFrameIndex(0),
585 TextFrameIndex(nChar), true);
586 }
587 }
588
589 // Display fill characters
590 if( !IsFilled() )
591 return;
592
593 // Tabs with filling/filled tabs
594 const sal_uInt16 nCharWidth = rInf.GetTextSize(OUString(m_cFill)).Width();
595 OSL_ENSURE( nCharWidth, "!SwTabPortion::Paint: sophisticated tabchar" );
596
597 // Robust:
598 if( nCharWidth )
599 {
600 // Always with kerning, also on printer!
601 sal_uInt16 nChar = Width() / nCharWidth;
602 if ( m_cFill == '_' )
603 ++nChar; // to avoid gaps
604 OUStringBuffer aBuf;
605 comphelper::string::padToLength(aBuf, nChar, m_cFill);
606 rInf.DrawText(aBuf.makeStringAndClear(), *this, TextFrameIndex(0),
607 TextFrameIndex(nChar), true);
608 }
609 }
610
Paint(const SwTextPaintInfo &) const611 void SwAutoTabDecimalPortion::Paint( const SwTextPaintInfo & ) const
612 {
613 }
614
HandlePortion(SwPortionHandler & rPH) const615 void SwTabPortion::HandlePortion( SwPortionHandler& rPH ) const
616 {
617 rPH.Text( GetLen(), GetWhichPor(), Height(), Width() );
618 }
619
620 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
621