xref: /AOO41X/main/sw/source/core/text/porfld.cxx (revision 4d7c9de063a797b8b4f3d45e3561e82ad1f8ef1f)
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