xref: /aoo42x/main/sw/source/core/text/txttab.cxx (revision efeef26f)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 #include "hintids.hxx"
28 #include <editeng/lrspitem.hxx>
29 #ifndef _SVX_TSTPITEM_HXX //autogen
30 #include <editeng/tstpitem.hxx>
31 #endif
32 #include <IDocumentSettingAccess.hxx>
33 #include <frmatr.hxx>
34 #include <SwPortionHandler.hxx>
35 
36 #include "viewopt.hxx"	// SwViewOptions
37 #include "txtcfg.hxx"
38 #include "portab.hxx"
39 #include "inftxt.hxx"
40 #include "itrform2.hxx"
41 #include "txtfrm.hxx"
42 #include <numrule.hxx>
43 // --> OD 2008-06-05 #i89179#
44 #include <porfld.hxx>
45 // <--
46 
47 
48 /*************************************************************************
49  *                    SwLineInfo::GetTabStop()
50  *************************************************************************/
51 
52 //#i24363# tab stops relative to indent
53 /* Return the first tab stop that is > nSearchPos.
54  * If the tab stop is outside the print area, we
55  * return 0 if it is not the first tab stop.*/
56 const SvxTabStop *SwLineInfo::GetTabStop( const SwTwips nSearchPos,
57                                          const SwTwips nRight ) const
58 {
59 	for( MSHORT i = 0; i < pRuler->Count(); ++i )
60 	{
61 		const SvxTabStop &rTabStop = pRuler->operator[](i);
62 		if( rTabStop.GetTabPos() > SwTwips(nRight) )
63             return i ? 0 : &rTabStop;
64 
65         if( rTabStop.GetTabPos() > nSearchPos )
66 			return &rTabStop;
67 	}
68 	return 0;
69 }
70 
71 /*************************************************************************
72  *                    SwLineInfo::NumberOfTabStops()
73  *************************************************************************/
74 
75 sal_uInt16 SwLineInfo::NumberOfTabStops() const
76 {
77     return pRuler->Count();
78 }
79 
80 /*************************************************************************
81  *                      SwTxtFormatter::NewTabPortion()
82  *************************************************************************/
83 SwTabPortion *SwTxtFormatter::NewTabPortion( SwTxtFormatInfo &rInf, bool bAuto ) const
84 {
85 	SwTabPortion *pTabPor = 0;
86 	SwTabPortion  *pLastTab = rInf.GetLastTab();
87     if( pLastTab && ( pLastTab->IsTabCntPortion() || pLastTab->IsTabDecimalPortion() ) )
88 		if( pLastTab->PostFormat( rInf ) )
89 			return 0;
90 
91     xub_Unicode cFill = 0;
92     xub_Unicode cDec = 0;
93 	SvxTabAdjust eAdj;
94 
95 	KSHORT nNewTabPos;
96 	{
97         const bool bRTL = pFrm->IsRightToLeft();
98         // #i24363# tab stops relative to indent
99         // nTabLeft: The absolute value, the tab stops are relative to: Tabs origin.
100         //
101         // --> OD 2008-07-01 #i91133#
102         const bool bTabsRelativeToIndent =
103             pFrm->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT);
104         const SwTwips nTabLeft = bRTL
105                                  ? pFrm->Frm().Right() -
106                                    ( bTabsRelativeToIndent ? GetTabLeft() : 0 )
107                                  : pFrm->Frm().Left() +
108                                    ( bTabsRelativeToIndent ? GetTabLeft() : 0 );
109         // <--
110 
111         //
112         // nLinePos: The absolute position, where we started the line formatting.
113         //
114         SwTwips nLinePos = GetLeftMargin();
115         if ( bRTL )
116         {
117             Point aPoint( nLinePos, 0 );
118             pFrm->SwitchLTRtoRTL( aPoint );
119             nLinePos = aPoint.X();
120         }
121 
122         //
123         // nTabPos: The current position, relative to the line start.
124         //
125         SwTwips nTabPos = rInf.GetLastTab() ? rInf.GetLastTab()->GetTabPos() : 0;
126         if( nTabPos < rInf.X() )
127         {
128             nTabPos = rInf.X();
129         }
130 
131         //
132         // nCurrentAbsPos: The current position in absolute coordinates.
133         //
134         const SwTwips nCurrentAbsPos = bRTL ?
135                                        nLinePos - nTabPos :
136                                        nLinePos + nTabPos;
137 
138        //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
139         SwTwips nMyRight;
140         if ( pFrm->IsVertLR() )
141            nMyRight = Left();
142         else
143            nMyRight = Right();
144 
145         if ( pFrm->IsVertical() )
146         {
147             Point aRightTop( nMyRight, pFrm->Frm().Top() );
148             pFrm->SwitchHorizontalToVertical( aRightTop );
149             nMyRight = aRightTop.Y();
150         }
151 
152 		SwTwips nNextPos;
153 
154         // #i24363# tab stops relative to indent
155         // nSearchPos: The current position relative to the tabs origin.
156         //
157         const SwTwips nSearchPos = bRTL ?
158                                    nTabLeft - nCurrentAbsPos :
159                                    nCurrentAbsPos - nTabLeft;
160 
161         //
162         // First, we examine the tab stops set at the paragraph style or
163         // any hard set tab stops:
164         // Note: If there are no user defined tab stops, there is always a
165         // default tab stop.
166         //
167 		const SvxTabStop* pTabStop =
168             aLineInf.GetTabStop( nSearchPos, nMyRight );
169 		if( pTabStop )
170 		{
171 			cFill = ' ' != pTabStop->GetFill() ? pTabStop->GetFill() : 0;
172 			cDec = pTabStop->GetDecimal();
173 			eAdj = pTabStop->GetAdjustment();
174             nNextPos = pTabStop->GetTabPos();
175             if(!bTabsRelativeToIndent && eAdj == SVX_TAB_ADJUST_DEFAULT && nSearchPos < 0)
176             {
177                 //calculate default tab position of default tabs in negative indent
178                 nNextPos = ( nSearchPos / nNextPos ) * nNextPos;
179             }
180 		}
181 		else
182 		{
183 			KSHORT nDefTabDist = aLineInf.GetDefTabStop();
184 			if( KSHRT_MAX == nDefTabDist )
185 			{
186 				const SvxTabStopItem& rTab =
187 					(const SvxTabStopItem &)pFrm->GetAttrSet()->
188 					GetPool()->GetDefaultItem( RES_PARATR_TABSTOP );
189 				if( rTab.Count() )
190 					nDefTabDist = (KSHORT)rTab.GetStart()->GetTabPos();
191 				else
192 					nDefTabDist = SVX_TAB_DEFDIST;
193 				aLineInf.SetDefTabStop( nDefTabDist );
194 			}
195             SwTwips nCount = nSearchPos;
196 
197 			//Minimum tab stop width is 1
198 			if (nDefTabDist <= 0)
199 			    nDefTabDist = 1;
200 
201 			nCount /= nDefTabDist;
202             nNextPos = nCount < 0 || (!nCount && nSearchPos <= 0)? nCount * nDefTabDist :( nCount + 1 ) * nDefTabDist ;
203             // --> FME 2004-09-21 #117919 Minimum tab stop width is 1 or 51 twips:
204             const SwTwips nMinimumTabWidth = pFrm->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) ? 0 : 50;
205             // <--
206             if( (  bRTL && nTabLeft - nNextPos >= nCurrentAbsPos - nMinimumTabWidth ) ||
207                  ( !bRTL && nNextPos + nTabLeft <= nCurrentAbsPos + nMinimumTabWidth  ) )
208             {
209                 nNextPos += nDefTabDist;
210             }
211 			cFill = 0;
212 			eAdj = SVX_TAB_ADJUST_LEFT;
213 		}
214 
215         // --> OD #i115705# - correction and refactoring:
216         // overrule determined next tab stop position in order to apply
217         // a tab stop at the left margin under the following conditions:
218         // - the new tab portion is inside the hanging indent
219         // - a tab stop at the left margin is allowed
220         // - the determined next tab stop is a default tab stop position OR
221         //   the determined next tab stop is beyond the left margin
222         {
223             long nLeftMarginTabPos = 0;
224             {
225                 if ( !bTabsRelativeToIndent )
226                 {
227                     if ( bRTL )
228                     {
229                         Point aPoint( Left(), 0 );
230                         pFrm->SwitchLTRtoRTL( aPoint );
231                         nLeftMarginTabPos = pFrm->Frm().Right() - aPoint.X();
232                     }
233                     else
234                     {
235                         nLeftMarginTabPos = Left() - pFrm->Frm().Left();
236                     }
237                 }
238                 if( pCurr->HasForcedLeftMargin() )
239                 {
240                     SwLinePortion* pPor = pCurr->GetPortion();
241                     while( pPor && !pPor->IsFlyPortion() )
242                     {
243                         pPor = pPor->GetPortion();
244                     }
245                     if ( pPor )
246                     {
247                         nLeftMarginTabPos += pPor->Width();
248                     }
249                 }
250             }
251             const bool bNewTabPortionInsideHangingIndent =
252                         bRTL ? nCurrentAbsPos > nTabLeft - nLeftMarginTabPos
253                              : nCurrentAbsPos < nTabLeft + nLeftMarginTabPos;
254             if ( bNewTabPortionInsideHangingIndent )
255             {
256                 // If the paragraph is not inside a list having a list tab stop following
257                 // the list label or no further tab stop found in such a paragraph or
258                 // the next tab stop position does not equal the list tab stop,
259                 // a tab stop at the left margin can be applied. If this condition is
260                 // not hold, it is overruled by compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST.
261                 const bool bTabAtLeftMarginAllowed =
262                     ( !aLineInf.IsListTabStopIncluded() ||
263                       !pTabStop ||
264                       nNextPos != aLineInf.GetListTabStopPosition() ) ||
265                     // compatibility option TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST:
266                     pFrm->GetTxtNode()->getIDocumentSettingAccess()->
267                         get(IDocumentSettingAccess::TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST);
268                 if ( bTabAtLeftMarginAllowed )
269                 {
270                     if ( !pTabStop || eAdj == SVX_TAB_ADJUST_DEFAULT ||
271                          ( nNextPos > nLeftMarginTabPos ) )
272                     {
273                         eAdj = SVX_TAB_ADJUST_DEFAULT;
274                         cFill = 0;
275                         nNextPos = nLeftMarginTabPos;
276                     }
277                 }
278             }
279         }
280         // <--
281 
282         nNextPos += bRTL ? nLinePos - nTabLeft : nTabLeft - nLinePos;
283 		ASSERT( nNextPos >= 0, "GetTabStop: Don't go back!" );
284 		nNewTabPos = KSHORT(nNextPos);
285 	}
286 
287     if ( bAuto )
288     {
289         if ( SVX_TAB_ADJUST_DECIMAL == eAdj &&
290              // --> FME 2005-12-19 #127428#
291              1 == aLineInf.NumberOfTabStops() )
292              // <--
293             pTabPor = new SwAutoTabDecimalPortion( nNewTabPos, cDec, cFill );
294     }
295     else
296     {
297         switch( eAdj )
298         {
299 	        case SVX_TAB_ADJUST_RIGHT :
300    		    {
301     		    pTabPor = new SwTabRightPortion( nNewTabPos, cFill );
302 		        break;
303 	        }
304 	        case SVX_TAB_ADJUST_CENTER :
305 	        {
306        			pTabPor = new SwTabCenterPortion( nNewTabPos, cFill );
307 		        break;
308 	        }
309 	        case SVX_TAB_ADJUST_DECIMAL :
310 	        {
311        			pTabPor = new SwTabDecimalPortion( nNewTabPos, cDec, cFill );
312 		        break;
313 	        }
314 	        default:
315 	        {
316        			ASSERT( SVX_TAB_ADJUST_LEFT == eAdj || SVX_TAB_ADJUST_DEFAULT == eAdj,
317 				        "+SwTxtFormatter::NewTabPortion: unknown adjustment" );
318 		        pTabPor = new SwTabLeftPortion( nNewTabPos, cFill );
319 		        break;
320 	        }
321         }
322     }
323 
324 	// Vorhandensein von Tabulatoren anzeigen ... ist nicht mehr noetig
325 	// pCurr->SetTabulation();
326 	// Aus Sicherheitsgruenden lassen wir uns die Daten errechnen
327 	// pTabPor->Height( pLast->Height() );
328 	// pTabPor->SetAscent( pLast->GetAscent() );
329 	return pTabPor;
330 }
331 
332 /*************************************************************************
333  *                SwTabPortion::SwTabPortion()
334  *************************************************************************/
335 
336 // Die Basisklasse wird erstmal ohne alles initialisiert.
337 
338 
339 SwTabPortion::SwTabPortion( const KSHORT nTabPosition, const xub_Unicode cFillChar )
340     : SwFixPortion( 0, 0 ), nTabPos(nTabPosition), cFill(cFillChar)
341 {
342 	nLineLength = 1;
343 #ifdef DBG_UTIL
344 	if( IsFilled() )
345 	{
346 		ASSERT( ' ' != cFill, "SwTabPortion::CTOR: blanks ?!" );
347 	}
348 #endif
349 	SetWhichPor( POR_TAB );
350 }
351 
352 /*************************************************************************
353  *                 virtual SwTabPortion::Format()
354  *************************************************************************/
355 
356 
357 
358 sal_Bool SwTabPortion::Format( SwTxtFormatInfo &rInf )
359 {
360 	SwTabPortion *pLastTab = rInf.GetLastTab();
361 	if( pLastTab == this )
362 		return PostFormat( rInf );
363 	if( pLastTab )
364 		pLastTab->PostFormat( rInf );
365 	return PreFormat( rInf );
366 }
367 
368 /*************************************************************************
369  *                 virtual SwTabPortion::FormatEOL()
370  *************************************************************************/
371 
372 
373 
374 void SwTabPortion::FormatEOL( SwTxtFormatInfo &rInf )
375 {
376 	if( rInf.GetLastTab() == this && !IsTabLeftPortion() )
377 		PostFormat( rInf );
378 }
379 
380 /*************************************************************************
381  *                    SwTabPortion::PreFormat()
382  *************************************************************************/
383 
384 
385 
386 sal_Bool SwTabPortion::PreFormat( SwTxtFormatInfo &rInf )
387 {
388 	ASSERT( rInf.X() <= GetTabPos(), "SwTabPortion::PreFormat: rush hour" );
389 
390 	// Hier lassen wir uns nieder...
391     Fix( static_cast<sal_uInt16>(rInf.X()) );
392 
393     const bool bTabCompat = rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT);
394 
395     // Die Mindestbreite eines Tabs ist immer mindestens ein Blank
396     // --> FME 2004-11-25 #i37686# In compatibility mode, the minimum width
397     // should be 1, even for non-left tab stops.
398     sal_uInt16 nMinimumTabWidth = 1;
399     // <--
400     if ( !bTabCompat )
401     {
402         // --> OD 2008-06-05 #i89179#
403         // tab portion representing the list tab of a list label gets the
404         // same font as the corresponding number portion
405         std::auto_ptr< SwFontSave > pSave( 0 );
406         if ( GetLen() == 0 &&
407              rInf.GetLast() && rInf.GetLast()->InNumberGrp() &&
408              static_cast<SwNumberPortion*>(rInf.GetLast())->HasFont() )
409         {
410             const SwFont* pNumberPortionFont =
411                     static_cast<SwNumberPortion*>(rInf.GetLast())->GetFont();
412             pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) );
413         }
414         // <--
415         XubString aTmp( ' ' );
416         SwTxtSizeInfo aInf( rInf, aTmp );
417         nMinimumTabWidth = aInf.GetTxtSize().Width();
418     }
419     PrtWidth( nMinimumTabWidth );
420 
421     // Break tab stop to next line if:
422     // 1. Minmal width does not fit to line anymore.
423     // 2. An underflow event was called for the tab portion.
424 	sal_Bool bFull = ( bTabCompat && rInf.IsUnderFlow() ) ||
425                        rInf.Width() <= rInf.X() + PrtWidth();
426 
427     // #95477# Rotated tab stops get the width of one blank
428     const sal_uInt16 nDir = rInf.GetFont()->GetOrientation( rInf.GetTxtFrm()->IsVertical() );
429 
430     if( ! bFull && 0 == nDir )
431 	{
432 		const MSHORT nWhich = GetWhichPor();
433 		switch( nWhich )
434 		{
435 			case POR_TABRIGHT:
436 			case POR_TABDECIMAL:
437 			case POR_TABCENTER:
438 			{
439 				if( POR_TABDECIMAL == nWhich )
440 					rInf.SetTabDecimal(
441 						((SwTabDecimalPortion*)this)->GetTabDecimal());
442 				rInf.SetLastTab( this );
443 				break;
444 			}
445 			case POR_TABLEFT:
446 			{
447                 PrtWidth( static_cast<sal_uInt16>(GetTabPos() - rInf.X()) );
448                 bFull = rInf.Width() <= rInf.X() + PrtWidth();
449 
450                 // In tabulator compatibility mode, we reset the bFull flag
451                 // if the tabulator is at the end of the paragraph and the
452                 // tab stop position is outside the frame:
453                 if ( bFull && bTabCompat &&
454                      rInf.GetIdx() + GetLen() == rInf.GetTxt().Len() &&
455                      GetTabPos() >= rInf.GetTxtFrm()->Frm().Width() )
456                     bFull = sal_False;
457 
458 				break;
459 			}
460 			default: ASSERT( !this, "SwTabPortion::PreFormat: unknown adjustment" );
461 		}
462 	}
463 
464 	if( bFull )
465 	{
466 		// Wir muessen aufpassen, dass wir nicht endlos schleifen,
467 		// wenn die Breite kleiner ist, als ein Blank ...
468 		if( rInf.GetIdx() == rInf.GetLineStart() &&
469             // --> FME 2005-01-19 #119175# TabStop should be forced to current
470             // line if there is a fly reducing the line width:
471             !rInf.GetFly() )
472             // <--
473 		{
474             PrtWidth( static_cast<sal_uInt16>(rInf.Width() - rInf.X()) );
475 			SetFixWidth( PrtWidth() );
476 		}
477 		else
478 		{
479 			Height( 0 );
480 			Width( 0 );
481 			SetLen( 0 );
482 			SetAscent( 0 );
483 			SetPortion( NULL ); //?????
484 		}
485 		return sal_True;
486 	}
487 	else
488 	{
489 		// Ein Kunstgriff mit Effekt: Die neuen Tabportions verhalten sich nun
490 		// so, wie FlyFrms, die in der Zeile stehen - inklusive Adjustment !
491 		SetFixWidth( PrtWidth() );
492 		return sal_False;
493 	}
494 }
495 
496 /*************************************************************************
497  *                      SwTabPortion::PostFormat()
498  *************************************************************************/
499 
500 
501 
502 sal_Bool SwTabPortion::PostFormat( SwTxtFormatInfo &rInf )
503 {
504 	const KSHORT nRight = Min( GetTabPos(), rInf.Width() );
505 	const SwLinePortion *pPor = GetPortion();
506 
507     KSHORT nPorWidth = 0;
508     while( pPor )
509     {
510    		DBG_LOOP;
511 	    nPorWidth = nPorWidth + pPor->Width();
512 	    pPor = pPor->GetPortion();
513     }
514 
515 	const MSHORT nWhich = GetWhichPor();
516 	ASSERT( POR_TABLEFT != nWhich, "SwTabPortion::PostFormat: already formatted" );
517     const bool bTabCompat = rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT);
518 
519     // --> FME 2005-12-19 #127428# Abandon dec. tab position if line is full:
520     if ( bTabCompat && POR_TABDECIMAL == nWhich )
521     {
522         KSHORT nPrePorWidth = static_cast<const SwTabDecimalPortion*>(this)->GetWidthOfPortionsUpToDecimalPosition();
523 
524         // no value was set => no decimal character was found
525         if ( USHRT_MAX != nPrePorWidth )
526         {
527             if ( nPrePorWidth && nPorWidth - nPrePorWidth > rInf.Width() - nRight )
528             {
529                 nPrePorWidth += nPorWidth - nPrePorWidth - ( rInf.Width() - nRight );
530             }
531 
532             nPorWidth = nPrePorWidth - 1;
533         }
534     }
535     // <--
536 
537     if( POR_TABCENTER == nWhich )
538 	{
539 		// zentrierte Tabs bereiten Probleme:
540 		// Wir muessen den Anteil herausfinden, der noch auf die Zeile passt.
541 		KSHORT nNewWidth = nPorWidth /2;
542 		if( nNewWidth > rInf.Width() - nRight )
543 			nNewWidth = nPorWidth - (rInf.Width() - nRight);
544 		nPorWidth = nNewWidth;
545 	}
546 
547 	const KSHORT nDiffWidth = nRight - Fix();
548 
549 	if( nDiffWidth > nPorWidth )
550 	{
551 		const KSHORT nOldWidth = GetFixWidth();
552 		const KSHORT nAdjDiff = nDiffWidth - nPorWidth;
553 		if( nAdjDiff > GetFixWidth() )
554 			PrtWidth( nAdjDiff );
555 		// Nicht erschrecken: wir muessen rInf weiterschieben.
556 		// Immerhin waren wir als Rechtstab bislang nur ein Blank breit.
557 		// Da wir uns jetzt aufgespannt haben, muss der Differenzbetrag
558 		// auf rInf.X() addiert werden !
559 		rInf.X( rInf.X() + PrtWidth() - nOldWidth );
560 	}
561 	SetFixWidth( PrtWidth() );
562 	// letzte Werte zuruecksetzen
563 	rInf.SetLastTab(0);
564 	if( POR_TABDECIMAL == nWhich )
565 		rInf.SetTabDecimal(0);
566 
567 	return rInf.Width() <= rInf.X();
568 }
569 
570 /*************************************************************************
571  *                virtual SwTabPortion::Paint()
572  *
573  * Ex: LineIter::DrawTab()
574  *************************************************************************/
575 
576 void SwTabPortion::Paint( const SwTxtPaintInfo &rInf ) const
577 {
578 #ifdef DBG_UTIL
579 	// Wir wollen uns die Fixbreite anzeigen
580     if( rInf.OnWin() && OPTDBG( rInf ) &&
581         !rInf.GetOpt().IsPagePreview() && \
582         !rInf.GetOpt().IsReadonly() && \
583         SwViewOption::IsFieldShadings()    )
584 	{
585 		const KSHORT nTmpWidth = PrtWidth();
586 		((SwTabPortion*)this)->PrtWidth( GetFixWidth() );
587 		rInf.DrawViewOpt( *this, POR_TAB );
588 		((SwTabPortion*)this)->PrtWidth( nTmpWidth );
589 	}
590 #endif
591 
592     // --> OD 2008-06-05 #i89179#
593     // tab portion representing the list tab of a list label gets the
594     // same font as the corresponding number portion
595     std::auto_ptr< SwFontSave > pSave( 0 );
596     if ( GetLen() == 0 )
597     {
598         const SwLinePortion* pPrevPortion =
599             const_cast<SwTabPortion*>(this)->FindPrevPortion( rInf.GetParaPortion() );
600         if ( pPrevPortion &&
601              pPrevPortion->InNumberGrp() &&
602              static_cast<const SwNumberPortion*>(pPrevPortion)->HasFont() )
603         {
604             const SwFont* pNumberPortionFont =
605                     static_cast<const SwNumberPortion*>(pPrevPortion)->GetFont();
606             pSave.reset( new SwFontSave( rInf, const_cast<SwFont*>(pNumberPortionFont) ) );
607         }
608     }
609     // <--
610 	rInf.DrawBackBrush( *this );
611 
612     // do we have to repaint a post it portion?
613     if( rInf.OnWin() && pPortion && !pPortion->Width() )
614         pPortion->PrePaint( rInf, this );
615 
616     // Darstellung von Sonderzeichen
617 	if( rInf.OnWin() && rInf.GetOpt().IsTab() )
618 	{
619 		// gefuellte Tabs werden grau hinterlegt.
620 		if( IsFilled() )
621 			rInf.DrawViewOpt( *this, POR_TAB );
622 		else
623 			rInf.DrawTab( *this );
624 	}
625 
626 	// 6842: Tabs sollen auf einmal wieder unterstrichen werden.
627 	if( rInf.GetFont()->IsPaintBlank() )
628 	{
629 		// Tabs mit Fuellung
630 		XubString aTxt( ' ' );
631 		const KSHORT nCharWidth = rInf.GetTxtSize( aTxt ).Width();
632 		// robust:
633 		if( nCharWidth )
634 		{
635 			// 6864: immer mit Kerning, auch auf dem Drucker!
636 			KSHORT nChar = Width() / nCharWidth;
637 			rInf.DrawText( aTxt.Fill( nChar, ' ' ), *this, 0, nChar, sal_True );
638 		}
639 	}
640 
641 	// Ausgabe von Fuellzeichen
642 	if( IsFilled() )
643 	{
644 		// Tabs mit Fuellung
645 		XubString aTxt( cFill );
646 		const KSHORT nCharWidth = rInf.GetTxtSize( aTxt ).Width();
647 #if OSL_DEBUG_LEVEL > 1
648 		ASSERT( nCharWidth, "!SwTabPortion::Paint: sophisticated tabchar" );
649 #endif
650 		// robust:
651 		if( nCharWidth )
652 		{
653 			// 6864: immer mit Kerning, auch auf dem Drucker!
654 			KSHORT nChar = Width() / nCharWidth;
655 			if ( cFill == '_' )
656 				++nChar; // damit keine Luecken entstehen (Bug 13430)
657 			rInf.DrawText( aTxt.Fill( nChar, cFill ), *this, 0, nChar, sal_True );
658 		}
659 	}
660 }
661 
662 /*************************************************************************
663  *                virtual SwAutoTabDecimalPortion::Paint()
664  *************************************************************************/
665 
666 void SwAutoTabDecimalPortion::Paint( const SwTxtPaintInfo & ) const
667 {
668 }
669 
670 /*************************************************************************
671  *              virtual SwTabPortion::HandlePortion()
672  *************************************************************************/
673 
674 void SwTabPortion::HandlePortion( SwPortionHandler& rPH ) const
675 {
676     rPH.Text( GetLen(), GetWhichPor() );
677 }
678 
679