xref: /AOO41X/main/sw/source/core/text/porfld.cxx (revision 0deba7fbda3d9908785c25a443701a293b6f4e71)
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 
28 #include <hintids.hxx>
29 
30 #include <com/sun/star/i18n/ScriptType.hdl>
31 #include <vcl/graph.hxx>
32 #include <editeng/brshitem.hxx>
33 #include <vcl/metric.hxx>
34 #include <vcl/outdev.hxx>
35 #include <viewopt.hxx>	// SwViewOptions
36 #include <txtcfg.hxx>
37 #include <SwPortionHandler.hxx>
38 #include <porlay.hxx>
39 #include <porfld.hxx>
40 #include <inftxt.hxx>
41 #include <blink.hxx>	// pBlink
42 #include <frmtool.hxx>  // DrawGraphic
43 #include <viewsh.hxx>
44 #include <docsh.hxx>
45 #include <doc.hxx>
46 #include "rootfrm.hxx"
47 #include <breakit.hxx>
48 #include <porrst.hxx>
49 #include <porftn.hxx>   // SwFtnPortion
50 #include <accessibilityoptions.hxx>
51 #include <editeng/lrspitem.hxx>
52 
53 #include <unicode/ubidi.h>
54 
55 using namespace ::com::sun::star;
56 
57 /*************************************************************************
58  *                      class SwFldPortion
59  *************************************************************************/
60 
61 SwLinePortion *SwFldPortion::Compress()
62 { return (GetLen() || aExpand.Len() || SwLinePortion::Compress()) ? this : 0; }
63 
64 SwFldPortion *SwFldPortion::Clone( const XubString &rExpand ) const
65 {
66     SwFont *pNewFnt;
67     if( 0 != ( pNewFnt = pFnt ) )
68     {
69         pNewFnt = new SwFont( *pFnt );
70     }
71     // --> OD 2009-11-25 #i107143#
72     // pass placeholder property to created <SwFldPortion> instance.
73     SwFldPortion* pClone = new SwFldPortion( rExpand, pNewFnt, bPlaceHolder );
74     // <--
75     pClone->SetNextOffset( nNextOffset );
76     pClone->m_bNoLength = this->m_bNoLength;
77     return pClone;
78 }
79 
80 void SwFldPortion::TakeNextOffset( const SwFldPortion* pFld )
81 {
82 	ASSERT( pFld, "TakeNextOffset: Missing Source" );
83 	nNextOffset = pFld->GetNextOffset();
84 	aExpand.Erase( 0, nNextOffset );
85 	bFollow = sal_True;
86 }
87 
88 SwFldPortion::SwFldPortion( const XubString &rExpand, SwFont *pFont, sal_Bool bPlaceHold )
89     : aExpand(rExpand), pFnt(pFont), nNextOffset(0), nNextScriptChg(STRING_LEN), nViewWidth(0),
90       bFollow( sal_False ), bHasFollow( sal_False ), bPlaceHolder( bPlaceHold )
91     , m_bNoLength( sal_False )
92 {
93     SetWhichPor( POR_FLD );
94 	//IAccessibility2 Implementation 2009-----
95 	m_nAttrFldType = 0;
96 	//-----IAccessibility2 Implementation 2009
97 }
98 
99 SwFldPortion::SwFldPortion( const SwFldPortion& rFld )
100     : SwExpandPortion( rFld ),
101       aExpand( rFld.GetExp() ),
102       nNextOffset( rFld.GetNextOffset() ),
103       nNextScriptChg( rFld.GetNextScriptChg() ),
104       bFollow( rFld.IsFollow() ),
105       bLeft( rFld.IsLeft() ),
106       bHide( rFld.IsHide() ),
107       bCenter( rFld.IsCenter() ),
108       bHasFollow( rFld.HasFollow() ),
109       bPlaceHolder( rFld.bPlaceHolder )
110     , m_bNoLength( rFld.m_bNoLength )
111 {
112     if ( rFld.HasFont() )
113         pFnt = new SwFont( *rFld.GetFont() );
114     else
115         pFnt = 0;
116 
117     SetWhichPor( POR_FLD );
118 }
119 
120 SwFldPortion::~SwFldPortion()
121 {
122 	delete pFnt;
123 	if( pBlink )
124 		pBlink->Delete( this );
125 }
126 
127 /*************************************************************************
128  *               virtual SwFldPortion::GetViewWidth()
129  *************************************************************************/
130 
131 KSHORT SwFldPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
132 {
133 	// Wir stehen zwar im const, aber nViewWidth sollte erst im letzten
134 	// Moment errechnet werden:
135 	SwFldPortion* pThis = (SwFldPortion*)this;
136     if( !Width() && rInf.OnWin() && !rInf.GetOpt().IsPagePreview() &&
137             !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
138 	{
139 		if( !nViewWidth )
140 			pThis->nViewWidth = rInf.GetTxtSize( ' ' ).Width();
141 	}
142 	else
143 		pThis->nViewWidth = 0;
144 	return nViewWidth;
145 }
146 
147 /*************************************************************************
148  *                 virtual SwFldPortion::Format()
149  *************************************************************************/
150 
151 // 8653: in keinem Fall nur SetLen(0);
152 
153 /*************************************************************************
154  *	 Hilfsklasse SwFldSlot
155  **************************************************************************/
156 
157 class SwFldSlot
158 {
159 	const XubString *pOldTxt;
160 	XubString aTxt;
161 	xub_StrLen nIdx;
162 	xub_StrLen nLen;
163 	sal_Bool bOn;
164     SwTxtFormatInfo *pInf;
165 public:
166     SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor );
167 	~SwFldSlot();
168 };
169 
170 SwFldSlot::SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor )
171 {
172 	bOn = pPor->GetExpTxt( *pNew, aTxt );
173 
174 	// Der Text wird ausgetauscht...
175 	if( bOn )
176 	{
177         pInf = (SwTxtFormatInfo*)pNew;
178 		nIdx = pInf->GetIdx();
179 		nLen = pInf->GetLen();
180 		pOldTxt = &(pInf->GetTxt());
181 		pInf->SetLen( aTxt.Len() );
182 		if( pPor->IsFollow() )
183         {
184             pInf->SetFakeLineStart( nIdx > pInf->GetLineStart() );
185             pInf->SetIdx( 0 );
186         }
187 		else
188 		{
189 			XubString aTmp( aTxt );
190 			aTxt = *pOldTxt;
191 			aTxt.Erase( nIdx, 1 );
192 			aTxt.Insert( aTmp, nIdx );
193 		}
194 		pInf->SetTxt( aTxt );
195 	}
196 }
197 
198 SwFldSlot::~SwFldSlot()
199 {
200 	if( bOn )
201 	{
202 		pInf->SetTxt( *pOldTxt );
203 		pInf->SetIdx( nIdx );
204 		pInf->SetLen( nLen );
205         pInf->SetFakeLineStart( sal_False );
206 	}
207 }
208 
209 void SwFldPortion::CheckScript( const SwTxtSizeInfo &rInf )
210 {
211 	String aTxt;
212     if( GetExpTxt( rInf, aTxt ) && aTxt.Len() && pBreakIt->GetBreakIter().is() )
213 	{
214 		sal_uInt8 nActual = pFnt ? pFnt->GetActual() : rInf.GetFont()->GetActual();
215 		sal_uInt16 nScript;
216 		{
217 			nScript = pBreakIt->GetBreakIter()->getScriptType( aTxt, 0 );
218 			xub_StrLen nChg = 0;
219             if( i18n::ScriptType::WEAK == nScript )
220 			{
221 				nChg =(xub_StrLen)pBreakIt->GetBreakIter()->endOfScript(aTxt,0,nScript);
222 				if( nChg < aTxt.Len() )
223 					nScript = pBreakIt->GetBreakIter()->getScriptType( aTxt, nChg );
224 			}
225 
226             //
227             // nNextScriptChg will be evaluated during SwFldPortion::Format()
228             //
229             if ( nChg < aTxt.Len() )
230                 nNextScriptChg = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( aTxt, nChg, nScript );
231             else
232                 nNextScriptChg = aTxt.Len();
233 
234         }
235 		sal_uInt8 nTmp;
236 		switch ( nScript ) {
237 			case i18n::ScriptType::LATIN : nTmp = SW_LATIN; break;
238 			case i18n::ScriptType::ASIAN : nTmp = SW_CJK; break;
239 			case i18n::ScriptType::COMPLEX : nTmp = SW_CTL; break;
240 			default: nTmp = nActual;
241 		}
242 
243         // #i16354# Change script type for RTL text to CTL.
244         const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo();
245         // --> OD 2009-01-29 #i98418#
246 //        const sal_uInt8 nFldDir = IsNumberPortion() ?
247         const sal_uInt8 nFldDir = ( IsNumberPortion() || IsFtnNumPortion() ) ?
248                              rSI.GetDefaultDir() :
249                              rSI.DirType( IsFollow() ? rInf.GetIdx() - 1 : rInf.GetIdx() );
250         // <--
251         if ( UBIDI_RTL == nFldDir )
252         {
253             UErrorCode nError = U_ZERO_ERROR;
254             UBiDi* pBidi = ubidi_openSized( aTxt.Len(), 0, &nError );
255             ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aTxt.GetBuffer()), aTxt.Len(), nFldDir, NULL, &nError );
256             int32_t nEnd;
257             UBiDiLevel nCurrDir;
258             ubidi_getLogicalRun( pBidi, 0, &nEnd, &nCurrDir );
259             ubidi_close( pBidi );
260             const xub_StrLen nNextDirChg = (xub_StrLen)nEnd;
261             nNextScriptChg = Min( nNextScriptChg, nNextDirChg );
262 
263             // #i89825# change the script type also to CTL
264             // if there is no strong LTR char in the LTR run (numbers)
265             if ( nCurrDir != UBIDI_RTL )
266             {
267                 nCurrDir = UBIDI_RTL;
268                 for ( xub_StrLen nCharIdx = 0; nCharIdx < nEnd; ++nCharIdx )
269                 {
270                     UCharDirection nCharDir = u_charDirection ( aTxt.GetChar ( nCharIdx ));
271                     if ( nCharDir == U_LEFT_TO_RIGHT ||
272                          nCharDir == U_LEFT_TO_RIGHT_EMBEDDING ||
273                          nCharDir == U_LEFT_TO_RIGHT_OVERRIDE )
274                     {
275                         nCurrDir = UBIDI_LTR;
276                         break;
277                     }
278                 }
279             }
280 
281             if ( nCurrDir == UBIDI_RTL )
282                 nTmp = SW_CTL;
283         }
284 
285         // --> OD 2009-01-29 #i98418#
286         // keep determined script type for footnote portions as preferred script type.
287         // For footnote portions a font can not be created directly - see footnote
288         // portion format method.
289 //         if( !IsFtnPortion() && nTmp != nActual )
290         if ( IsFtnPortion() )
291         {
292             dynamic_cast<SwFtnPortion*>(this)->SetPreferredScriptType( nTmp );
293         }
294         else if ( nTmp != nActual )
295         {
296     	    if( !pFnt )
297                 pFnt = new SwFont( *rInf.GetFont() );
298             pFnt->SetActual( nTmp );
299         }
300         // <--
301     }
302 }
303 
304 sal_Bool SwFldPortion::Format( SwTxtFormatInfo &rInf )
305 {
306 	// Scope wegen aDiffTxt::DTOR!
307 	xub_StrLen nRest;
308 	sal_Bool bFull;
309 	sal_Bool bEOL = sal_False;
310 	long nTxtRest = rInf.GetTxt().Len() - rInf.GetIdx();
311 	{
312         SwFldSlot aDiffTxt( &rInf, this );
313         SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
314         aLayoutModeModifier.SetAuto();
315 
316         // Field portion has to be split in several parts if
317         // 1. There are script/direction changes inside the field
318         // 2. There are portion breaks (tab, break) inside the field:
319 		const xub_StrLen nOldFullLen = rInf.GetLen();
320         xub_StrLen nFullLen = rInf.ScanPortionEnd( rInf.GetIdx(), rInf.GetIdx() + nOldFullLen ) - rInf.GetIdx();
321         if ( nNextScriptChg < nFullLen )
322         {
323             nFullLen = nNextScriptChg;
324             rInf.SetHookChar( 0 );
325         }
326 		rInf.SetLen( nFullLen );
327 
328         if ( STRING_LEN != rInf.GetUnderScorePos() &&
329              rInf.GetUnderScorePos() > rInf.GetIdx() )
330              rInf.SetUnderScorePos( rInf.GetIdx() );
331 
332 		if( pFnt )
333 			pFnt->GoMagic( rInf.GetVsh(), pFnt->GetActual() );
334 
335 		SwFontSave aSave( rInf, pFnt );
336 
337 		// 8674: Laenge muss 0 sein, bei bFull nach Format ist die Laenge
338 		// gesetzt und wird in nRest uebertragen. Ansonsten bleibt die
339 		// Laenge erhalten und wuerde auch in nRest einfliessen!
340 		SetLen(0);
341    		const MSHORT nFollow = IsFollow() ? 0 : 1;
342 
343 		// So komisch es aussieht, die Abfrage auf GetLen() muss wegen der
344 		// ExpandPortions _hinter_ aDiffTxt (vgl. SoftHyphs)
345 		// sal_False returnen wegen SetFull ...
346 		if( !nFullLen )
347 		{
348 			// nicht Init(), weil wir Hoehe und Ascent brauchen
349 			Width(0);
350 			bFull = rInf.Width() <= rInf.GetPos().X();
351 		}
352 		else
353 		{
354 			xub_StrLen nOldLineStart = rInf.GetLineStart();
355 			if( IsFollow() )
356 				rInf.SetLineStart( 0 );
357 			rInf.SetNotEOL( nFullLen == nOldFullLen && nTxtRest > nFollow );
358 
359             // the height depending on the fields font is set,
360             // this is required for SwTxtGuess::Guess
361             Height( rInf.GetTxtHeight() );
362             // If a kerning portion is inserted after our field portion,
363             // the ascent and height must be known
364             SetAscent( rInf.GetAscent() );
365             bFull = SwTxtPortion::Format( rInf );
366 			rInf.SetNotEOL( sal_False );
367 			rInf.SetLineStart( nOldLineStart );
368 		}
369 		xub_StrLen nTmpLen = GetLen();
370 		bEOL = !nTmpLen && nFollow && bFull;
371 		nRest = nOldFullLen - nTmpLen;
372 
373         // Das Zeichen wird in der ersten Portion gehalten.
374 		// Unbedingt nach Format!
375 		SetLen( (m_bNoLength) ? 0 : nFollow );
376 
377         if( nRest )
378 		{
379 			// aExpand ist noch nicht gekuerzt worden, der neue Ofst
380 			// ergibt sich durch nRest.
381             xub_StrLen nNextOfst = aExpand.Len() - nRest;
382 
383             if ( IsQuoVadisPortion() )
384                 nNextOfst = nNextOfst + ((SwQuoVadisPortion*)this)->GetContTxt().Len();
385 
386 			XubString aNew( aExpand, nNextOfst, STRING_LEN );
387 			aExpand.Erase( nNextOfst, STRING_LEN );
388 
389 			// These characters should not be contained in the follow
390             // field portion. They are handled via the HookChar mechanism.
391 			switch( aNew.GetChar( 0 ))
392 			{
393 				case CH_BREAK  : bFull = sal_True;
394 							// kein break;
395 				case ' ' :
396 				case CH_TAB    :
397                 case CHAR_HARDHYPHEN:               // non-breaking hyphen
398                 case CHAR_SOFTHYPHEN:
399                 case CHAR_HARDBLANK:
400                 // --> FME 2006-01-11 #i59759# Erase additional control
401                 // characters from field string, otherwise we get stuck in
402                 // a loop.
403                 case CHAR_ZWSP :
404                 case CHAR_ZWNBSP :
405         //        case CHAR_RLM :
406         //        case CHAR_LRM :
407                 // <--
408                 // --> OD 2010-06-03 #i111750#
409                 // - Erasing further control characters from field string in
410                 // to avoid loop.
411                 case CH_TXTATR_BREAKWORD:
412                 case CH_TXTATR_INWORD:
413                 // <--
414 				{
415 					aNew.Erase( 0, 1 );
416 					++nNextOfst;
417 					break;
418 				}
419                 default: ;
420 			}
421 
422             // Even if there is no more text left for a follow field,
423             // we have to build a follow field portion (without font),
424             // otherwise the HookChar mechanism would not work.
425             SwFldPortion *pFld = Clone( aNew );
426 			if( aNew.Len() && !pFld->GetFont() )
427 			{
428 				SwFont *pNewFnt = new SwFont( *rInf.GetFont() );
429 				pFld->SetFont( pNewFnt );
430 			}
431 			pFld->SetFollow( sal_True );
432 			SetHasFollow( sal_True );
433 			// In nNextOffset steht bei einem neuangelegten Feld zunaechst
434 			// der Offset, an dem es selbst im Originalstring beginnt.
435 			// Wenn beim Formatieren ein FollowFeld angelegt wird, wird
436 			// der Offset dieses FollowFelds in nNextOffset festgehalten.
437 			nNextOffset = nNextOffset + nNextOfst;
438 			pFld->SetNextOffset( nNextOffset );
439 			rInf.SetRest( pFld );
440 		}
441 	}
442 
443 	if( bEOL && rInf.GetLast() && !rInf.GetUnderFlow() )
444 		rInf.GetLast()->FormatEOL( rInf );
445 	return bFull;
446 }
447 
448 /*************************************************************************
449  *               virtual SwFldPortion::Paint()
450  *************************************************************************/
451 
452 void SwFldPortion::Paint( const SwTxtPaintInfo &rInf ) const
453 {
454 	SwFontSave aSave( rInf, pFnt );
455 
456 	ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" );
457     if( Width() && ( !bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) )
458 	{
459 		// Dies ist eine freizuegige Auslegung der Hintergrundbelegung ...
460 		rInf.DrawViewOpt( *this, POR_FLD );
461 		SwExpandPortion::Paint( rInf );
462 	}
463 }
464 
465 /*************************************************************************
466  *              virtual SwFldPortion::GetExpTxt()
467  *************************************************************************/
468 
469 sal_Bool SwFldPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
470 {
471 	rTxt = aExpand;
472     if( !rTxt.Len() && rInf.OnWin() &&
473         !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() &&
474             SwViewOption::IsFieldShadings() &&
475             !HasFollow() )
476 		rTxt = ' ';
477 	return sal_True;
478 }
479 
480 /*************************************************************************
481  *              virtual SwFldPortion::HandlePortion()
482  *************************************************************************/
483 
484 void SwFldPortion::HandlePortion( SwPortionHandler& rPH ) const
485 {
486     rPH.Special( GetLen(), aExpand, GetWhichPor() );
487     //IAccessibility2 Implementation 2009-----
488     if( GetWhichPor() == POR_FLD )
489     {
490     	rPH.SetAttrFieldType(m_nAttrFldType);
491     }
492     //-----IAccessibility2 Implementation 2009
493 }
494 
495 /*************************************************************************
496  *                virtual SwFldPortion::GetTxtSize()
497  *************************************************************************/
498 
499 SwPosSize SwFldPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
500 {
501 	SwFontSave aSave( rInf, pFnt );
502 	SwPosSize aSize( SwExpandPortion::GetTxtSize( rInf ) );
503 	return aSize;
504 }
505 
506 /*************************************************************************
507  *                      class SwHiddenPortion
508  *************************************************************************/
509 
510 SwFldPortion *SwHiddenPortion::Clone(const XubString &rExpand ) const
511 {
512 	SwFont *pNewFnt;
513 	if( 0 != ( pNewFnt = pFnt ) )
514 		pNewFnt = new SwFont( *pFnt );
515 	return new SwHiddenPortion( rExpand, pNewFnt );
516 }
517 
518 /*************************************************************************
519  *               virtual SwHiddenPortion::Paint()
520  *************************************************************************/
521 
522 void SwHiddenPortion::Paint( const SwTxtPaintInfo &rInf ) const
523 {
524 	if( Width() )
525 	{
526 		SwFontSave aSave( rInf, pFnt );
527 		rInf.DrawViewOpt( *this, POR_HIDDEN );
528 		SwExpandPortion::Paint( rInf );
529 	}
530 }
531 
532 /*************************************************************************
533  *              virtual SwHiddenPortion::GetExpTxt()
534  *************************************************************************/
535 
536 sal_Bool SwHiddenPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
537 {
538 	// Nicht auf IsHidden() abfragen !
539 	return SwFldPortion::GetExpTxt( rInf, rTxt );
540 }
541 
542 /*************************************************************************
543  *                      class SwNumberPortion
544  *************************************************************************/
545 
546 // --> OD 2008-01-23 #newlistlevelattrs#
547 SwNumberPortion::SwNumberPortion( const XubString &rExpand,
548                                   SwFont *pFont,
549                                   const sal_Bool bLft,
550                                   const sal_Bool bCntr,
551                                   const KSHORT nMinDst,
552                                   const bool bLabelAlignmentPosAndSpaceModeActive )
553         : SwFldPortion( rExpand, pFont ),
554           nFixWidth(0),
555           nMinDist( nMinDst ),
556           // --> OD 2008-01-23 #newlistlevelattrs#
557           mbLabelAlignmentPosAndSpaceModeActive( bLabelAlignmentPosAndSpaceModeActive )
558           // <--
559 {
560 	SetWhichPor( POR_NUMBER );
561 	SetLeft( bLft );
562 	SetHide( sal_False );
563 	SetCenter( bCntr );
564 }
565 
566 xub_StrLen SwNumberPortion::GetCrsrOfst( const MSHORT ) const
567 {
568 	return 0;
569 }
570 
571 SwFldPortion *SwNumberPortion::Clone( const XubString &rExpand ) const
572 {
573 	SwFont *pNewFnt;
574 	if( 0 != ( pNewFnt = pFnt ) )
575 		pNewFnt = new SwFont( *pFnt );
576     // --> OD 2008-01-23 #newlistlevelattrs#
577 	return new SwNumberPortion( rExpand, pNewFnt, IsLeft(), IsCenter(),
578                                 nMinDist, mbLabelAlignmentPosAndSpaceModeActive );
579     // <--
580 }
581 
582 /*************************************************************************
583  *                 virtual SwNumberPortion::Format()
584  *************************************************************************/
585 
586 // 5010: Wir sind in der Lage, mehrzeilige NumFelder anzulegen!
587 // 3689: Fies ist, wenn man in der Dialogbox soviel Davor-Text
588 // eingibt, bis die Zeile ueberlaeuft.
589 // Man muss die Fly-Ausweichmanoever beachten!
590 
591 sal_Bool SwNumberPortion::Format( SwTxtFormatInfo &rInf )
592 {
593 	SetHide( sal_False );
594 	const sal_Bool bFull = SwFldPortion::Format( rInf );
595 	SetLen( 0 );
596     // a numbering portion can be contained in a rotated portion!!!
597     nFixWidth = rInf.IsMulti() ? Height() : Width();
598 	rInf.SetNumDone( !rInf.GetRest() );
599 	if( rInf.IsNumDone() )
600 	{
601 //        SetAscent( rInf.GetAscent() );
602         ASSERT( Height() && nAscent, "NumberPortions without Height | Ascent" );
603 
604         long nDiff( 0 );
605         // --> OD 2008-01-23 #newlistlevelattrs#
606         if ( !mbLabelAlignmentPosAndSpaceModeActive )
607         {
608             if ( !rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) &&
609                  // --> FME 2004-08-13 #i32902#
610                  !IsFtnNumPortion() )
611                  // <--
612             {
613                 nDiff = rInf.Left()
614                     + rInf.GetTxtFrm()->GetTxtNode()->
615                     GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst()
616                     - rInf.First()
617                     + rInf.ForcedLeftMargin();
618             }
619             else
620             {
621                 nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
622             }
623         }
624         // <--
625         // Ein Vorschlag von Juergen und Volkmar:
626         // Der Textteil hinter der Numerierung sollte immer
627         // mindestens beim linken Rand beginnen.
628         if( nDiff < 0 )
629             nDiff = 0;
630         else if ( nDiff > rInf.X() )
631             nDiff -= rInf.X();
632         else
633             nDiff = 0;
634 
635 		if( nDiff < nFixWidth + nMinDist )
636 			nDiff = nFixWidth + nMinDist;
637 		// 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde
638 		// fieser Sonderfall: FlyFrm liegt in dem Bereich,
639 		// den wir uns gerade unter den Nagel reissen wollen.
640 		// Die NumberPortion wird als verborgen markiert.
641         const sal_Bool bFly = rInf.GetFly() ||
642             ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() );
643         if( nDiff > rInf.Width() )
644 		{
645 			nDiff = rInf.Width();
646             if ( bFly )
647                 SetHide( sal_True );
648 		}
649 
650         // A numbering portion can be inside a SwRotatedPortion. Then the
651         // Height has to be changed
652         if ( rInf.IsMulti() )
653         {
654             if ( Height() < nDiff )
655                 Height( KSHORT( nDiff ) );
656         }
657         else if( Width() < nDiff )
658             Width( KSHORT(nDiff) );
659 	}
660 	return bFull;
661 }
662 
663 void SwNumberPortion::FormatEOL( SwTxtFormatInfo& )
664 {
665 /*	Ein FormatEOL deutet daraufhin, dass der folgende Text
666  *	nicht mit auf die Zeile passte. Damit die Numerierung mitwandert,
667  *  wird diese NumberPortion verborgen.
668  */
669 
670     // This caused trouble with flys anchored as characters.
671     // If one of these is numbered but does not fit to the line,
672     // it calls this function, causing a loop because both the number
673     // portion and the fly portion go to the next line
674 //    SetHide( sal_True );
675 }
676 
677 /*************************************************************************
678  *               virtual SwNumberPortion::Paint()
679  *************************************************************************/
680 
681 void SwNumberPortion::Paint( const SwTxtPaintInfo &rInf ) const
682 {
683 /*	Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt
684  * 	Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile.
685  */
686 
687 	if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() )
688 	{
689 		SwLinePortion *pTmp = GetPortion();
690 		while ( pTmp && !pTmp->InTxtGrp() )
691 			pTmp = pTmp->GetPortion();
692 		if ( !pTmp )
693 			return;
694 	}
695 
696     // calculate the width of the number portion, including follows
697     const KSHORT nOldWidth = Width();
698     sal_uInt16 nSumWidth = 0;
699     sal_uInt16 nOffset = 0;
700 
701     const SwLinePortion* pTmp = this;
702     while ( pTmp && pTmp->InNumberGrp() )
703     {
704         nSumWidth = nSumWidth + pTmp->Width();
705         if ( ((SwNumberPortion*)pTmp)->HasFollow() )
706             pTmp = pTmp->GetPortion();
707         else
708         {
709             nOffset = pTmp->Width() - ((SwNumberPortion*)pTmp)->nFixWidth;
710             break;
711         }
712     }
713 
714     // The master portion takes care for painting the background of the
715     // follow field portions
716     if ( ! IsFollow() )
717     {
718         SwLinePortion *pThis = (SwLinePortion*)this;
719         pThis->Width( nSumWidth );
720         rInf.DrawViewOpt( *this, POR_NUMBER );
721         pThis->Width( nOldWidth );
722     }
723 
724 	if( aExpand.Len() )
725 	{
726 		const SwFont *pTmpFnt = rInf.GetFont();
727 		sal_Bool bPaintSpace = ( UNDERLINE_NONE != pTmpFnt->GetUnderline() ||
728 							     UNDERLINE_NONE != pTmpFnt->GetOverline()  ||
729 							     STRIKEOUT_NONE != pTmpFnt->GetStrikeout() ) &&
730 							     !pTmpFnt->IsWordLineMode();
731 		if( bPaintSpace && pFnt )
732 			bPaintSpace = ( UNDERLINE_NONE != pFnt->GetUnderline() ||
733 							UNDERLINE_NONE != pFnt->GetOverline()  ||
734 							STRIKEOUT_NONE != pFnt->GetStrikeout() ) &&
735 							!pFnt->IsWordLineMode();
736 
737 		SwFontSave aSave( rInf, pFnt );
738 
739         if( nFixWidth == Width() && ! HasFollow() )
740 			SwExpandPortion::Paint( rInf );
741 		else
742 		{
743 			// logisches const: Width wird wieder zurueckgesetzt
744 			SwLinePortion *pThis = (SwLinePortion*)this;
745 			bPaintSpace = bPaintSpace && nFixWidth < nOldWidth;
746 			KSHORT nSpaceOffs = nFixWidth;
747 			pThis->Width( nFixWidth );
748 
749 			if( ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) ||
750                 ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() ) )
751 				SwExpandPortion::Paint( rInf );
752 			else
753 			{
754 				SwTxtPaintInfo aInf( rInf );
755 				if( nOffset < nMinDist )
756 					nOffset = 0;
757 				else
758 				{
759 					if( IsCenter() )
760 					{
761                         /* #110778# a / 2 * 2 == a is not a tautology */
762                         KSHORT nTmpOffset = nOffset;
763 						nOffset /= 2;
764 						if( nOffset < nMinDist )
765 							nOffset = nTmpOffset - nMinDist;
766 					}
767 					else
768 						nOffset = nOffset - nMinDist;
769 				}
770 				aInf.X( aInf.X() + nOffset );
771 				SwExpandPortion::Paint( aInf );
772 				if( bPaintSpace )
773 					nSpaceOffs = nSpaceOffs + nOffset;
774 			}
775 			if( bPaintSpace && nOldWidth > nSpaceOffs )
776 			{
777 				SwTxtPaintInfo aInf( rInf );
778 static sal_Char __READONLY_DATA sDoubleSpace[] = "  ";
779 				aInf.X( aInf.X() + nSpaceOffs );
780 
781                 // --> FME 2005-08-12 #i53199# Adjust position of underline:
782                 if ( rInf.GetUnderFnt() )
783                 {
784                     const Point aNewPos( aInf.GetPos().X(), rInf.GetUnderFnt()->GetPos().Y() );
785                     rInf.GetUnderFnt()->SetPos( aNewPos );
786                 }
787                 // <--
788 
789 				pThis->Width( nOldWidth - nSpaceOffs + 12 );
790 				{
791                     SwTxtSlot aDiffTxt( &aInf, this, true, false, sDoubleSpace );
792 					aInf.DrawText( *this, aInf.GetLen(), sal_True );
793 				}
794 			}
795 			pThis->Width( nOldWidth );
796 		}
797 	}
798 }
799 
800 
801 /*************************************************************************
802  *                      class SwBulletPortion
803  *************************************************************************/
804 
805 // --> OD 2008-01-23 #newlistlevelattrs#
806 SwBulletPortion::SwBulletPortion( const xub_Unicode cBullet,
807                                   const XubString& rBulletFollowedBy,
808                                   SwFont *pFont,
809                                   const sal_Bool bLft,
810                                   const sal_Bool bCntr,
811                                   const KSHORT nMinDst,
812                                   const bool bLabelAlignmentPosAndSpaceModeActive )
813     : SwNumberPortion( XubString( rBulletFollowedBy ).Insert( cBullet, 0 ) ,
814                        pFont, bLft, bCntr, nMinDst,
815                        bLabelAlignmentPosAndSpaceModeActive )
816 // <--
817 {
818 	SetWhichPor( POR_BULLET );
819 }
820 
821 /*************************************************************************
822  *                      class SwGrfNumPortion
823  *************************************************************************/
824 
825 #define GRFNUM_SECURE 10
826 
827 // --> OD 2008-01-23 #newlistlevelattrs#
828 SwGrfNumPortion::SwGrfNumPortion(
829 		SwFrm*,
830         const XubString& rGraphicFollowedBy,
831 		const SvxBrushItem* pGrfBrush,
832 		const SwFmtVertOrient* pGrfOrient, const Size& rGrfSize,
833         const sal_Bool bLft, const sal_Bool bCntr, const KSHORT nMinDst,
834         const bool bLabelAlignmentPosAndSpaceModeActive ) :
835     SwNumberPortion( rGraphicFollowedBy, NULL, bLft, bCntr, nMinDst,
836                      bLabelAlignmentPosAndSpaceModeActive ),
837 // <--
838     pBrush( new SvxBrushItem(RES_BACKGROUND) ), nId( 0 )
839 {
840 	SetWhichPor( POR_GRFNUM );
841 	SetAnimated( sal_False );
842 	bReplace = sal_False;
843 	if( pGrfBrush )
844 	{
845 		*pBrush = *pGrfBrush;
846 		const Graphic* pGraph = pGrfBrush->GetGraphic();
847 		if( pGraph )
848 			SetAnimated( pGraph->IsAnimated() );
849 		else
850 			bReplace = sal_True;
851 	}
852 	if( pGrfOrient )
853 	{
854 		nYPos = pGrfOrient->GetPos();
855 		eOrient = pGrfOrient->GetVertOrient();
856 	}
857 	else
858 	{
859 		nYPos = 0;
860         eOrient = text::VertOrientation::TOP;
861 	}
862     Width( static_cast<sal_uInt16>(rGrfSize.Width() + 2 * GRFNUM_SECURE) );
863 	nFixWidth = Width();
864 	nGrfHeight = rGrfSize.Height() + 2 * GRFNUM_SECURE;
865 	Height( KSHORT(nGrfHeight) );
866 	bNoPaint = sal_False;
867 }
868 
869 SwGrfNumPortion::~SwGrfNumPortion()
870 {
871 	if ( IsAnimated() )
872 		( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId );
873 	delete pBrush;
874 }
875 
876 void SwGrfNumPortion::StopAnimation( OutputDevice* pOut )
877 {
878 	if ( IsAnimated() )
879 		( (Graphic*) pBrush->GetGraphic() )->StopAnimation( pOut, nId );
880 }
881 
882 sal_Bool SwGrfNumPortion::Format( SwTxtFormatInfo &rInf )
883 {
884 	SetHide( sal_False );
885     // --> OD 2008-01-29 #newlistlevelattrs#
886 //    Width( nFixWidth );
887     KSHORT nFollowedByWidth( 0 );
888     if ( mbLabelAlignmentPosAndSpaceModeActive )
889     {
890         SwFldPortion::Format( rInf );
891         nFollowedByWidth = Width();
892         SetLen( 0 );
893     }
894     Width( nFixWidth + nFollowedByWidth );
895     // <--
896 	const sal_Bool bFull = rInf.Width() < rInf.X() + Width();
897 	const sal_Bool bFly = rInf.GetFly() ||
898 		( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() );
899     SetAscent( static_cast<sal_uInt16>(GetRelPos() > 0 ? GetRelPos() : 0) );
900 	if( GetAscent() > Height() )
901 		Height( GetAscent() );
902 
903 	if( bFull )
904 	{
905 		Width( rInf.Width() - (KSHORT)rInf.X() );
906 		if( bFly )
907 		{
908 			SetLen( 0 );
909 			SetNoPaint( sal_True );
910 			rInf.SetNumDone( sal_False );
911 			return sal_True;
912 		}
913 	}
914 	rInf.SetNumDone( sal_True );
915     // --> OD 2008-01-23 #newlistlevelattrs#
916 //    long nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
917     long nDiff = mbLabelAlignmentPosAndSpaceModeActive
918                  ? 0
919                  : rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
920     // <--
921 	// Ein Vorschlag von Juergen und Volkmar:
922 	// Der Textteil hinter der Numerierung sollte immer
923 	// mindestens beim linken Rand beginnen.
924 	if( nDiff < 0 )
925 		nDiff = 0;
926 	else if ( nDiff > rInf.X() )
927 		nDiff -= rInf.X();
928 	if( nDiff < nFixWidth + nMinDist )
929 		nDiff = nFixWidth + nMinDist;
930 	// 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde
931 	// fieser Sonderfall: FlyFrm liegt in dem Bereich,
932 	// den wir uns gerade unter den Nagel reissen wollen.
933 	// Die NumberPortion wird als verborgen markiert.
934 	if( nDiff > rInf.Width() )
935 	{
936 		nDiff = rInf.Width();
937 		if( bFly )
938 			SetHide( sal_True );
939 	}
940 
941 	if( Width() < nDiff )
942 		Width( KSHORT(nDiff) );
943 	return bFull;
944 }
945 
946 void SwGrfNumPortion::Paint( const SwTxtPaintInfo &rInf ) const
947 {
948 	if( DontPaint() )
949 		return;
950 /*	Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt
951  * 	Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile.
952  */
953 	if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() )
954 	{
955 		SwLinePortion *pTmp = GetPortion();
956 		while ( pTmp && !pTmp->InTxtGrp() )
957 			pTmp = pTmp->GetPortion();
958 		if ( !pTmp )
959 			return;
960 	}
961 	Point aPos( rInf.X() + GRFNUM_SECURE, rInf.Y() - GetRelPos() + GRFNUM_SECURE );
962 	long nTmpWidth = Max( (long)0, (long)(nFixWidth - 2 * GRFNUM_SECURE) );
963 	Size aSize( nTmpWidth, GetGrfHeight() - 2 * GRFNUM_SECURE );
964 
965     // --> OD 2008-02-05 #newlistlevelattrs#
966     const sal_Bool bTmpLeft = mbLabelAlignmentPosAndSpaceModeActive ||
967                               ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) ||
968                               ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() );
969     // <--
970 
971     if( nFixWidth < Width() && !bTmpLeft )
972 	{
973 		KSHORT nOffset = Width() - nFixWidth;
974 		if( nOffset < nMinDist )
975 			nOffset = 0;
976 		else
977 		{
978 			if( IsCenter() )
979 			{
980 				nOffset /= 2;
981 				if( nOffset < nMinDist )
982 					nOffset = Width() - nFixWidth - nMinDist;
983 			}
984 			else
985 				nOffset = nOffset - nMinDist;
986 		}
987 		aPos.X() += nOffset;
988 	}
989 
990 	if( bReplace )
991 	{
992 		KSHORT nTmpH = GetPortion() ? GetPortion()->GetAscent() : 120;
993 		aSize = Size( nTmpH, nTmpH );
994 		aPos.Y() = rInf.Y() - nTmpH;
995 	}
996 	SwRect aTmp( aPos, aSize );
997 
998 	sal_Bool bDraw = sal_True;
999 
1000 	if ( IsAnimated() )
1001 	{
1002 		bDraw = !rInf.GetOpt().IsGraphic();
1003 		if( !nId )
1004 		{
1005 			SetId( long( rInf.GetTxtFrm() ) );
1006 			rInf.GetTxtFrm()->SetAnimation();
1007 		}
1008 		if( aTmp.IsOver( rInf.GetPaintRect() ) && !bDraw )
1009 		{
1010 			rInf.NoteAnimation();
1011             const ViewShell* pViewShell = rInf.GetVsh();
1012 
1013             // virtual device, not pdf export
1014             if( OUTDEV_VIRDEV == rInf.GetOut()->GetOutDevType() &&
1015                 pViewShell && pViewShell->GetWin()  )
1016             {
1017 				( (Graphic*) pBrush->GetGraphic() )->StopAnimation(0,nId);
1018 				rInf.GetTxtFrm()->getRootFrm()->GetCurrShell()->InvalidateWindows( aTmp );
1019 			}
1020 
1021 
1022             else if ( pViewShell &&
1023                      !pViewShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() &&
1024                      !pViewShell->IsPreView() &&
1025                       // --> FME 2004-06-21 #i9684# Stop animation during printing/pdf export.
1026                       pViewShell->GetWin() )
1027                       // <--
1028             {
1029 				( (Graphic*) pBrush->GetGraphic() )->StartAnimation(
1030 					(OutputDevice*)rInf.GetOut(), aPos, aSize, nId );
1031             }
1032 
1033             // pdf export, printing, preview, stop animations...
1034             else
1035                 bDraw = sal_True;
1036 		}
1037 		if( bDraw )
1038 			( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId );
1039 	}
1040 
1041     SwRect aRepaint( rInf.GetPaintRect() );
1042 	const SwTxtFrm& rFrm = *rInf.GetTxtFrm();
1043     if( rFrm.IsVertical() )
1044     {
1045         rFrm.SwitchHorizontalToVertical( aTmp );
1046         rFrm.SwitchHorizontalToVertical( aRepaint );
1047     }
1048 
1049     if( rFrm.IsRightToLeft() )
1050     {
1051         rFrm.SwitchLTRtoRTL( aTmp );
1052         rFrm.SwitchLTRtoRTL( aRepaint );
1053     }
1054 
1055 	if( bDraw && aTmp.HasArea() )
1056 		DrawGraphic( pBrush, (OutputDevice*)rInf.GetOut(),
1057             aTmp, aRepaint, bReplace ? GRFNUM_REPLACE : GRFNUM_YES );
1058 }
1059 
1060 void SwGrfNumPortion::SetBase( long nLnAscent, long nLnDescent,
1061 							   long nFlyAsc, long nFlyDesc )
1062 {
1063     if ( GetOrient() != text::VertOrientation::NONE )
1064 	{
1065 		SetRelPos( 0 );
1066         if ( GetOrient() == text::VertOrientation::CENTER )
1067 			SetRelPos( GetGrfHeight() / 2 );
1068         else if ( GetOrient() == text::VertOrientation::TOP )
1069 			SetRelPos( GetGrfHeight() - GRFNUM_SECURE );
1070         else if ( GetOrient() == text::VertOrientation::BOTTOM )
1071 			;
1072         else if ( GetOrient() == text::VertOrientation::CHAR_CENTER )
1073 			SetRelPos( ( GetGrfHeight() + nLnAscent - nLnDescent ) / 2 );
1074         else if ( GetOrient() == text::VertOrientation::CHAR_TOP )
1075 			SetRelPos( nLnAscent );
1076         else if ( GetOrient() == text::VertOrientation::CHAR_BOTTOM )
1077 			SetRelPos( GetGrfHeight() - nLnDescent );
1078 		else
1079 		{
1080 			if( GetGrfHeight() >= nFlyAsc + nFlyDesc )
1081 			{
1082 				// wenn ich genauso gross bin wie die Zeile, brauche ich mich
1083 				// nicht an der Zeile nicht weiter ausrichten, ich lasse
1084 				// dann auch den max. Ascent der Zeile unveraendert
1085 
1086 				SetRelPos( nFlyAsc );
1087 			}
1088             else if ( GetOrient() == text::VertOrientation::LINE_CENTER )
1089 				SetRelPos( ( GetGrfHeight() + nFlyAsc - nFlyDesc ) / 2 );
1090             else if ( GetOrient() == text::VertOrientation::LINE_TOP )
1091 				SetRelPos( nFlyAsc );
1092             else if ( GetOrient() == text::VertOrientation::LINE_BOTTOM )
1093 				SetRelPos( GetGrfHeight() - nFlyDesc );
1094 		}
1095 	}
1096 }
1097 
1098 void SwTxtFrm::StopAnimation( OutputDevice* pOut )
1099 {
1100 	ASSERT( HasAnimation(), "SwTxtFrm::StopAnimation: Which Animation?" );
1101 	if( HasPara() )
1102 	{
1103 		SwLineLayout *pLine = GetPara();
1104 		while( pLine )
1105 		{
1106 			SwLinePortion *pPor = pLine->GetPortion();
1107 			while( pPor )
1108 			{
1109 				if( pPor->IsGrfNumPortion() )
1110 					((SwGrfNumPortion*)pPor)->StopAnimation( pOut );
1111 				// Die Numerierungsportion sitzt immer vor dem ersten Zeichen,
1112 				// deshalb koennen wir abbrechen, sobald wir eine Portion mit
1113 				// einer Laenge > 0 erreicht haben.
1114 				pPor = pPor->GetLen() ? 0 : pPor->GetPortion();
1115 			}
1116 			pLine = pLine->GetLen() ? 0 : pLine->GetNext();
1117 		}
1118 	}
1119 }
1120 
1121 /*************************************************************************
1122  * SwCombinedPortion::SwCombinedPortion(..)
1123  * initializes the script array and clears the width array
1124  *************************************************************************/
1125 
1126 SwCombinedPortion::SwCombinedPortion( const XubString &rTxt )
1127 	 : SwFldPortion( rTxt )
1128 {
1129 	SetLen(1);
1130 	SetWhichPor( POR_COMBINED );
1131 	if( aExpand.Len() > 6 )
1132 		aExpand.Erase( 6 );
1133 	// Initialization of the scripttype array,
1134 	// the arrays of width and position are filled by the format function
1135 	if(	pBreakIt->GetBreakIter().is() )
1136 	{
1137 		sal_uInt8 nScr = SW_SCRIPTS;
1138 		for( sal_uInt16 i = 0; i < rTxt.Len(); ++i )
1139 		{
1140 			sal_uInt16 nScript = pBreakIt->GetBreakIter()->getScriptType( rTxt, i );
1141 			switch ( nScript ) {
1142 				case i18n::ScriptType::LATIN : nScr = SW_LATIN; break;
1143 				case i18n::ScriptType::ASIAN : nScr = SW_CJK; break;
1144 				case i18n::ScriptType::COMPLEX : nScr = SW_CTL; break;
1145 			}
1146 			aScrType[i] = nScr;
1147 		}
1148 	}
1149 	else
1150 	{
1151 		for( sal_uInt16 i = 0; i < 6; aScrType[i++] = 0 )
1152 			; // nothing
1153 	}
1154 	memset( &aWidth, 0, sizeof(aWidth) );
1155 }
1156 
1157 /*************************************************************************
1158  * SwCombinedPortion::Paint(..)
1159  *************************************************************************/
1160 
1161 void SwCombinedPortion::Paint( const SwTxtPaintInfo &rInf ) const
1162 {
1163 	ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" );
1164 	if( Width() )
1165 	{
1166 		rInf.DrawBackBrush( *this );
1167 		rInf.DrawViewOpt( *this, POR_FLD );
1168 
1169         // do we have to repaint a post it portion?
1170         if( rInf.OnWin() && pPortion && !pPortion->Width() )
1171             pPortion->PrePaint( rInf, this );
1172 
1173 		sal_uInt16 nCount = aExpand.Len();
1174 		if( !nCount )
1175 			return;
1176 		ASSERT( nCount < 7, "Too much combined characters" );
1177 
1178 		// the first character of the second row
1179 		sal_uInt16 nTop = ( nCount + 1 ) / 2;
1180 
1181 		SwFont aTmpFont( *rInf.GetFont() );
1182 		aTmpFont.SetProportion( nProportion );	// a smaller font
1183 		SwFontSave aFontSave( rInf, &aTmpFont );
1184 
1185 		sal_uInt16 i = 0;
1186 		Point aOldPos = rInf.GetPos();
1187 		Point aOutPos( aOldPos.X(), aOldPos.Y() - nUpPos );// Y of the first row
1188 		while( i < nCount )
1189 		{
1190 			if( i == nTop ) // change the row
1191 				aOutPos.Y() = aOldPos.Y() + nLowPos;	// Y of the second row
1192 			aOutPos.X() = aOldPos.X() + aPos[i];		// X position
1193 			const sal_uInt8 nAct = aScrType[i];				// script type
1194 			aTmpFont.SetActual( nAct );
1195 			// if there're more than 4 characters to display, we choose fonts
1196 			// with 2/3 of the original font width.
1197 			if( aWidth[ nAct ] )
1198 			{
1199 				Size aTmpSz = aTmpFont.GetSize( nAct );
1200 				if( aTmpSz.Width() != aWidth[ nAct ] )
1201 				{
1202 					aTmpSz.Width() = aWidth[ nAct ];
1203 					aTmpFont.SetSize( aTmpSz, nAct );
1204 				}
1205 			}
1206 			((SwTxtPaintInfo&)rInf).SetPos( aOutPos );
1207 			rInf.DrawText( aExpand, *this, i, 1 );
1208 			++i;
1209 		}
1210 		// rInf is const, so we have to take back our manipulations
1211 		((SwTxtPaintInfo&)rInf).SetPos( aOldPos );
1212 	}
1213 }
1214 
1215 /*************************************************************************
1216  * SwCombinedPortion::Format(..)
1217  *************************************************************************/
1218 
1219 sal_Bool SwCombinedPortion::Format( SwTxtFormatInfo &rInf )
1220 {
1221 	sal_uInt16 nCount = aExpand.Len();
1222 	if( !nCount )
1223 	{
1224 		Width( 0 );
1225 		return sal_False;
1226 	}
1227 
1228 	ASSERT( nCount < 7, "Too much combined characters" );
1229 	// If there are leading "weak"-scripttyped characters in this portion,
1230 	// they get the actual scripttype.
1231 	sal_uInt16 i = 0;
1232 	while( i < nCount && SW_SCRIPTS == aScrType[i] )
1233 		aScrType[i++] = rInf.GetFont()->GetActual();
1234 	if( nCount > 4 )
1235 	{
1236 		// more than four? Ok, then we need the 2/3 font width
1237 		i = 0;
1238 		while( i < aExpand.Len() )
1239 		{
1240 			ASSERT( aScrType[i] < SW_SCRIPTS, "Combined: Script fault" );
1241 			if( !aWidth[ aScrType[i] ] )
1242 			{
1243 				rInf.GetOut()->SetFont( rInf.GetFont()->GetFnt( aScrType[i] ) );
1244                 aWidth[ aScrType[i] ] =
1245                         static_cast<sal_uInt16>(2 * rInf.GetOut()->GetFontMetric().GetSize().Width() / 3);
1246 			}
1247 			++i;
1248 		}
1249 	}
1250 
1251 	sal_uInt16 nTop = ( nCount + 1 ) / 2; // the first character of the second line
1252 	ViewShell *pSh = rInf.GetTxtFrm()->getRootFrm()->GetCurrShell();
1253 	SwFont aTmpFont( *rInf.GetFont() );
1254 	SwFontSave aFontSave( rInf, &aTmpFont );
1255 	nProportion = 55;
1256 	// In nMainAscent/Descent we store the ascent and descent
1257 	// of the original surrounding font
1258 	sal_uInt16 nMaxDescent, nMaxAscent, nMaxWidth;
1259     sal_uInt16 nMainDescent = rInf.GetFont()->GetHeight( pSh, *rInf.GetOut() );
1260     const sal_uInt16 nMainAscent = rInf.GetFont()->GetAscent( pSh, *rInf.GetOut() );
1261 	nMainDescent = nMainDescent - nMainAscent;
1262 	// we start with a 50% font, but if we notice that the combined portion
1263 	// becomes bigger than the surrounding font, we check 45% and maybe 40%.
1264 	do
1265 	{
1266 		nProportion -= 5;
1267 		aTmpFont.SetProportion( nProportion );
1268 		i = 0;
1269 		memset( &aPos, 0, sizeof(aPos) );
1270 		nMaxDescent = 0;
1271 		nMaxAscent = 0;
1272 		nMaxWidth = 0;
1273 		nUpPos = nLowPos = 0;
1274 
1275 		// Now we get the width of all characters.
1276 		// The ascent and the width of the first line are stored in the
1277 		// ascent member of the portion, the descent in nLowPos.
1278 		// The ascent, descent and width of the second line are stored in the
1279 		// local nMaxAscent, nMaxDescent and nMaxWidth variables.
1280 		while( i < nCount )
1281 		{
1282 			sal_uInt8 nScrp = aScrType[i];
1283 			aTmpFont.SetActual( nScrp );
1284 			if( aWidth[ nScrp ] )
1285 			{
1286 				Size aFontSize( aTmpFont.GetSize( nScrp ) );
1287 				aFontSize.Width() = aWidth[ nScrp ];
1288 				aTmpFont.SetSize( aFontSize, nScrp );
1289 			}
1290 
1291             SwDrawTextInfo aDrawInf( pSh, *rInf.GetOut(), 0, aExpand, i, 1 );
1292             Size aSize = aTmpFont._GetTxtSize( aDrawInf );
1293             sal_uInt16 nAsc = aTmpFont.GetAscent( pSh, *rInf.GetOut() );
1294             aPos[ i ] = (sal_uInt16)aSize.Width();
1295 			if( i == nTop ) // enter the second line
1296 			{
1297 				nLowPos = nMaxDescent;
1298 				Height( nMaxDescent + nMaxAscent );
1299 				Width( nMaxWidth );
1300 				SetAscent( nMaxAscent );
1301 				nMaxAscent = 0;
1302 				nMaxDescent = 0;
1303 				nMaxWidth = 0;
1304 			}
1305 			nMaxWidth = nMaxWidth + aPos[ i++ ];
1306 			if( nAsc > nMaxAscent )
1307 				nMaxAscent = nAsc;
1308 			if( aSize.Height() - nAsc > nMaxDescent )
1309                 nMaxDescent = static_cast<sal_uInt16>(aSize.Height() - nAsc);
1310 		}
1311 		// for one or two characters we double the width of the portion
1312 		if( nCount < 3 )
1313 		{
1314 			nMaxWidth *= 2;
1315 			Width( 2*Width() );
1316 			if( nCount < 2 )
1317 			{
1318 				Height( nMaxAscent + nMaxDescent );
1319 				nLowPos = nMaxDescent;
1320 			}
1321 		}
1322 		Height( Height() + nMaxDescent + nMaxAscent );
1323 		nUpPos = nMaxAscent;
1324 		SetAscent( Height() - nMaxDescent - nLowPos );
1325 	} while( nProportion > 40 && ( GetAscent() > nMainAscent ||
1326 									Height() - GetAscent() > nMainDescent ) );
1327 	// if the combined portion is smaller than the surrounding text,
1328 	// the portion grows. This looks better, if there's a character background.
1329 	if( GetAscent() < nMainAscent )
1330 	{
1331 		Height( Height() + nMainAscent - GetAscent() );
1332 		SetAscent( nMainAscent );
1333 	}
1334 	if( Height() < nMainAscent + nMainDescent )
1335 		Height( nMainAscent + nMainDescent );
1336 
1337 	// We calculate the x positions of the characters in both lines..
1338 	sal_uInt16 nTopDiff = 0;
1339 	sal_uInt16 nBotDiff = 0;
1340 	if( nMaxWidth > Width() )
1341 	{
1342 		nTopDiff = ( nMaxWidth - Width() ) / 2;
1343 		Width( nMaxWidth );
1344 	}
1345 	else
1346 		nBotDiff = ( Width() - nMaxWidth ) / 2;
1347 	switch( nTop)
1348 	{
1349 		case 3: aPos[1] = aPos[0] + nTopDiff;  // no break
1350 		case 2: aPos[nTop-1] = Width() - aPos[nTop-1];
1351 	}
1352 	aPos[0] = 0;
1353 	switch( nCount )
1354 	{
1355 		case 5: aPos[4] = aPos[3] + nBotDiff;	// no break
1356 		case 3: aPos[nTop] = nBotDiff;			break;
1357 		case 6: aPos[4] = aPos[3] + nBotDiff;	// no break
1358 		case 4: aPos[nTop] = 0;					// no break
1359 		case 2: aPos[nCount-1] = Width() - aPos[nCount-1];
1360 	}
1361 
1362 	// Does the combined portion fit the line?
1363 	const sal_Bool bFull = rInf.Width() < rInf.X() + Width();
1364 	if( bFull )
1365 	{
1366 		if( rInf.GetLineStart() == rInf.GetIdx() &&	(!rInf.GetLast()->InFldGrp()
1367 			|| !((SwFldPortion*)rInf.GetLast())->IsFollow() ) )
1368             Width( (sal_uInt16)( rInf.Width() - rInf.X() ) );
1369 		else
1370 		{
1371 			Truncate();
1372 			Width( 0 );
1373 			SetLen( 0 );
1374 			if( rInf.GetLast() )
1375 				rInf.GetLast()->FormatEOL( rInf );
1376 		}
1377 	}
1378 	return bFull;
1379 }
1380 
1381 /*************************************************************************
1382  * SwCombinedPortion::GetViewWidth(..)
1383  *************************************************************************/
1384 
1385 KSHORT SwCombinedPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
1386 {
1387 	if( !GetLen() )	// for the dummy part at the end of the line, where
1388 		return 0;	// the combined portion doesn't fit.
1389 	return SwFldPortion::GetViewWidth( rInf );
1390 }
1391