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