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