merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / text / porfld.cxx
blob8fcdbca8e7f6494b73e8617742b34a6cbea3b430
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: porfld.cxx,v $
10 * $Revision: 1.62.110.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <hintids.hxx>
37 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
38 #include <com/sun/star/i18n/ScriptType.hdl>
39 #endif
41 #ifndef _GRAPH_HXX //autogen
42 #include <vcl/graph.hxx>
43 #endif
44 #include <svx/brshitem.hxx>
45 #ifndef _METRIC_HXX //autogen
46 #include <vcl/metric.hxx>
47 #endif
48 #ifndef _OUTDEV_HXX //autogen
49 #include <vcl/outdev.hxx>
50 #endif
51 #include <viewopt.hxx> // SwViewOptions
52 #include <txtcfg.hxx>
53 #include <SwPortionHandler.hxx>
54 #include <porlay.hxx>
55 #include <porfld.hxx>
56 #include <inftxt.hxx>
57 #include <blink.hxx> // pBlink
58 #include <frmtool.hxx> // DrawGraphic
59 #include <viewsh.hxx>
60 #ifndef _DOCSH_HXX
61 #include <docsh.hxx>
62 #endif
63 #include <doc.hxx>
64 #include <breakit.hxx>
65 #include <porrst.hxx>
66 #include <porftn.hxx> // SwFtnPortion
67 #include <accessibilityoptions.hxx>
68 #include <svx/lrspitem.hxx>
70 #include <unicode/ubidi.h>
72 using namespace ::com::sun::star;
74 /*************************************************************************
75 * class SwFldPortion
76 *************************************************************************/
78 SwLinePortion *SwFldPortion::Compress()
79 { return (GetLen() || aExpand.Len() || SwLinePortion::Compress()) ? this : 0; }
81 SwFldPortion *SwFldPortion::Clone( const XubString &rExpand ) const
83 SwFont *pNewFnt;
84 if( 0 != ( pNewFnt = pFnt ) )
85 pNewFnt = new SwFont( *pFnt );
86 SwFldPortion* pClone = new SwFldPortion( rExpand, pNewFnt );
87 pClone->SetNextOffset( nNextOffset );
88 pClone->m_bNoLength = this->m_bNoLength;
89 return pClone;
92 void SwFldPortion::TakeNextOffset( const SwFldPortion* pFld )
94 ASSERT( pFld, "TakeNextOffset: Missing Source" );
95 nNextOffset = pFld->GetNextOffset();
96 aExpand.Erase( 0, nNextOffset );
97 bFollow = sal_True;
100 SwFldPortion::SwFldPortion( const XubString &rExpand, SwFont *pFont, sal_Bool bPlaceHold )
101 : aExpand(rExpand), pFnt(pFont), nNextOffset(0), nNextScriptChg(STRING_LEN), nViewWidth(0),
102 bFollow( sal_False ), bHasFollow( sal_False ), bPlaceHolder( bPlaceHold )
103 , m_bNoLength( sal_False )
105 SetWhichPor( POR_FLD );
108 SwFldPortion::SwFldPortion( const SwFldPortion& rFld )
109 : SwExpandPortion( rFld ),
110 aExpand( rFld.GetExp() ),
111 nNextOffset( rFld.GetNextOffset() ),
112 nNextScriptChg( rFld.GetNextScriptChg() ),
113 bFollow( rFld.IsFollow() ),
114 bLeft( rFld.IsLeft() ),
115 bHide( rFld.IsHide() ),
116 bCenter( rFld.IsCenter() ),
117 bHasFollow( rFld.HasFollow() ),
118 bPlaceHolder( rFld.bPlaceHolder )
119 , m_bNoLength( rFld.m_bNoLength )
121 if ( rFld.HasFont() )
122 pFnt = new SwFont( *rFld.GetFont() );
123 else
124 pFnt = 0;
126 SetWhichPor( POR_FLD );
129 SwFldPortion::~SwFldPortion()
131 delete pFnt;
132 if( pBlink )
133 pBlink->Delete( this );
136 /*************************************************************************
137 * virtual SwFldPortion::GetViewWidth()
138 *************************************************************************/
140 KSHORT SwFldPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
142 // Wir stehen zwar im const, aber nViewWidth sollte erst im letzten
143 // Moment errechnet werden:
144 SwFldPortion* pThis = (SwFldPortion*)this;
145 if( !Width() && rInf.OnWin() && !rInf.GetOpt().IsPagePreview() &&
146 !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
148 if( !nViewWidth )
149 pThis->nViewWidth = rInf.GetTxtSize( ' ' ).Width();
151 else
152 pThis->nViewWidth = 0;
153 return nViewWidth;
156 /*************************************************************************
157 * virtual SwFldPortion::Format()
158 *************************************************************************/
160 // 8653: in keinem Fall nur SetLen(0);
162 /*************************************************************************
163 * Hilfsklasse SwFldSlot
164 **************************************************************************/
166 class SwFldSlot
168 const XubString *pOldTxt;
169 XubString aTxt;
170 xub_StrLen nIdx;
171 xub_StrLen nLen;
172 sal_Bool bOn;
173 SwTxtFormatInfo *pInf;
174 public:
175 SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor );
176 ~SwFldSlot();
179 SwFldSlot::SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor )
181 bOn = pPor->GetExpTxt( *pNew, aTxt );
183 // Der Text wird ausgetauscht...
184 if( bOn )
186 pInf = (SwTxtFormatInfo*)pNew;
187 nIdx = pInf->GetIdx();
188 nLen = pInf->GetLen();
189 pOldTxt = &(pInf->GetTxt());
190 pInf->SetLen( aTxt.Len() );
191 if( pPor->IsFollow() )
193 pInf->SetFakeLineStart( nIdx > pInf->GetLineStart() );
194 pInf->SetIdx( 0 );
196 else
198 XubString aTmp( aTxt );
199 aTxt = *pOldTxt;
200 aTxt.Erase( nIdx, 1 );
201 aTxt.Insert( aTmp, nIdx );
203 pInf->SetTxt( aTxt );
207 SwFldSlot::~SwFldSlot()
209 if( bOn )
211 pInf->SetTxt( *pOldTxt );
212 pInf->SetIdx( nIdx );
213 pInf->SetLen( nLen );
214 pInf->SetFakeLineStart( sal_False );
218 void SwFldPortion::CheckScript( const SwTxtSizeInfo &rInf )
220 String aTxt;
221 if( GetExpTxt( rInf, aTxt ) && aTxt.Len() && pBreakIt->GetBreakIter().is() )
223 BYTE nActual = pFnt ? pFnt->GetActual() : rInf.GetFont()->GetActual();
224 USHORT nScript;
226 nScript = pBreakIt->GetBreakIter()->getScriptType( aTxt, 0 );
227 xub_StrLen nChg = 0;
228 if( i18n::ScriptType::WEAK == nScript )
230 nChg =(xub_StrLen)pBreakIt->GetBreakIter()->endOfScript(aTxt,0,nScript);
231 if( nChg < aTxt.Len() )
232 nScript = pBreakIt->GetBreakIter()->getScriptType( aTxt, nChg );
236 // nNextScriptChg will be evaluated during SwFldPortion::Format()
238 if ( nChg < aTxt.Len() )
239 nNextScriptChg = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( aTxt, nChg, nScript );
240 else
241 nNextScriptChg = aTxt.Len();
244 BYTE nTmp;
245 switch ( nScript ) {
246 case i18n::ScriptType::LATIN : nTmp = SW_LATIN; break;
247 case i18n::ScriptType::ASIAN : nTmp = SW_CJK; break;
248 case i18n::ScriptType::COMPLEX : nTmp = SW_CTL; break;
249 default: nTmp = nActual;
252 // #i16354# Change script type for RTL text to CTL.
253 const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo();
254 // --> OD 2009-01-29 #i98418#
255 // const BYTE nFldDir = IsNumberPortion() ?
256 const BYTE nFldDir = ( IsNumberPortion() || IsFtnNumPortion() ) ?
257 rSI.GetDefaultDir() :
258 rSI.DirType( IsFollow() ? rInf.GetIdx() - 1 : rInf.GetIdx() );
259 // <--
260 if ( UBIDI_RTL == nFldDir )
262 UErrorCode nError = U_ZERO_ERROR;
263 UBiDi* pBidi = ubidi_openSized( aTxt.Len(), 0, &nError );
264 ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aTxt.GetBuffer()), aTxt.Len(), nFldDir, NULL, &nError );
265 int32_t nEnd;
266 UBiDiLevel nCurrDir;
267 ubidi_getLogicalRun( pBidi, 0, &nEnd, &nCurrDir );
268 ubidi_close( pBidi );
269 const xub_StrLen nNextDirChg = (xub_StrLen)nEnd;
270 nNextScriptChg = Min( nNextScriptChg, nNextDirChg );
272 // #i89825# change the script type also to CTL
273 // if there is no strong LTR char in the LTR run (numbers)
274 if ( nCurrDir != UBIDI_RTL )
276 nCurrDir = UBIDI_RTL;
277 for ( xub_StrLen nCharIdx = 0; nCharIdx < nEnd; ++nCharIdx )
279 UCharDirection nCharDir = u_charDirection ( aTxt.GetChar ( nCharIdx ));
280 if ( nCharDir == U_LEFT_TO_RIGHT ||
281 nCharDir == U_LEFT_TO_RIGHT_EMBEDDING ||
282 nCharDir == U_LEFT_TO_RIGHT_OVERRIDE )
284 nCurrDir = UBIDI_LTR;
285 break;
290 if ( nCurrDir == UBIDI_RTL )
291 nTmp = SW_CTL;
294 // --> OD 2009-01-29 #i98418#
295 // keep determined script type for footnote portions as preferred script type.
296 // For footnote portions a font can not be created directly - see footnote
297 // portion format method.
298 // if( !IsFtnPortion() && nTmp != nActual )
299 if ( IsFtnPortion() )
301 dynamic_cast<SwFtnPortion*>(this)->SetPreferredScriptType( nTmp );
303 else if ( nTmp != nActual )
305 if( !pFnt )
306 pFnt = new SwFont( *rInf.GetFont() );
307 pFnt->SetActual( nTmp );
309 // <--
313 sal_Bool SwFldPortion::Format( SwTxtFormatInfo &rInf )
315 // Scope wegen aDiffTxt::DTOR!
316 xub_StrLen nRest;
317 sal_Bool bFull;
318 sal_Bool bEOL = sal_False;
319 long nTxtRest = rInf.GetTxt().Len() - rInf.GetIdx();
321 SwFldSlot aDiffTxt( &rInf, this );
322 SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
323 aLayoutModeModifier.SetAuto();
325 // Field portion has to be split in several parts if
326 // 1. There are script/direction changes inside the field
327 // 2. There are portion breaks (tab, break) inside the field:
328 const xub_StrLen nOldFullLen = rInf.GetLen();
329 xub_StrLen nFullLen = rInf.ScanPortionEnd( rInf.GetIdx(), rInf.GetIdx() + nOldFullLen ) - rInf.GetIdx();
330 if ( nNextScriptChg < nFullLen )
332 nFullLen = nNextScriptChg;
333 rInf.SetHookChar( 0 );
335 rInf.SetLen( nFullLen );
337 if ( STRING_LEN != rInf.GetUnderScorePos() &&
338 rInf.GetUnderScorePos() > rInf.GetIdx() )
339 rInf.SetUnderScorePos( rInf.GetIdx() );
341 if( pFnt )
342 pFnt->GoMagic( rInf.GetVsh(), pFnt->GetActual() );
344 SwFontSave aSave( rInf, pFnt );
346 // 8674: Laenge muss 0 sein, bei bFull nach Format ist die Laenge
347 // gesetzt und wird in nRest uebertragen. Ansonsten bleibt die
348 // Laenge erhalten und wuerde auch in nRest einfliessen!
349 SetLen(0);
350 const MSHORT nFollow = IsFollow() ? 0 : 1;
352 // So komisch es aussieht, die Abfrage auf GetLen() muss wegen der
353 // ExpandPortions _hinter_ aDiffTxt (vgl. SoftHyphs)
354 // sal_False returnen wegen SetFull ...
355 if( !nFullLen )
357 // nicht Init(), weil wir Hoehe und Ascent brauchen
358 Width(0);
359 bFull = rInf.Width() <= rInf.GetPos().X();
361 else
363 xub_StrLen nOldLineStart = rInf.GetLineStart();
364 if( IsFollow() )
365 rInf.SetLineStart( 0 );
366 rInf.SetNotEOL( nFullLen == nOldFullLen && nTxtRest > nFollow );
368 // the height depending on the fields font is set,
369 // this is required for SwTxtGuess::Guess
370 Height( rInf.GetTxtHeight() );
371 // If a kerning portion is inserted after our field portion,
372 // the ascent and height must be known
373 SetAscent( rInf.GetAscent() );
374 bFull = SwTxtPortion::Format( rInf );
375 rInf.SetNotEOL( sal_False );
376 rInf.SetLineStart( nOldLineStart );
378 xub_StrLen nTmpLen = GetLen();
379 bEOL = !nTmpLen && nFollow && bFull;
380 nRest = nOldFullLen - nTmpLen;
382 // Das Zeichen wird in der ersten Portion gehalten.
383 // Unbedingt nach Format!
384 SetLen( (m_bNoLength) ? 0 : nFollow );
386 if( nRest )
388 // aExpand ist noch nicht gekuerzt worden, der neue Ofst
389 // ergibt sich durch nRest.
390 xub_StrLen nNextOfst = aExpand.Len() - nRest;
392 if ( IsQuoVadisPortion() )
393 nNextOfst = nNextOfst + ((SwQuoVadisPortion*)this)->GetContTxt().Len();
395 XubString aNew( aExpand, nNextOfst, STRING_LEN );
396 aExpand.Erase( nNextOfst, STRING_LEN );
398 // These characters should not be contained in the follow
399 // field portion. They are handled via the HookChar mechanism.
400 switch( aNew.GetChar( 0 ))
402 case CH_BREAK : bFull = sal_True;
403 // kein break;
404 case ' ' :
405 case CH_TAB :
406 case CHAR_HARDHYPHEN: // non-breaking hyphen
407 case CHAR_SOFTHYPHEN:
408 case CHAR_HARDBLANK:
409 // --> FME 2006-01-11 #i59759# Erase additional control
410 // characters from field string, otherwise we get stuck in
411 // a loop.
412 case CHAR_ZWSP :
413 case CHAR_ZWNBSP :
414 // case CHAR_RLM :
415 // case CHAR_LRM :
416 // <--
418 aNew.Erase( 0, 1 );
419 ++nNextOfst;
420 break;
422 default: ;
425 // Even if there is no more text left for a follow field,
426 // we have to build a follow field portion (without font),
427 // otherwise the HookChar mechanism would not work.
428 SwFldPortion *pFld = Clone( aNew );
429 if( aNew.Len() && !pFld->GetFont() )
431 SwFont *pNewFnt = new SwFont( *rInf.GetFont() );
432 pFld->SetFont( pNewFnt );
434 pFld->SetFollow( sal_True );
435 SetHasFollow( sal_True );
436 // In nNextOffset steht bei einem neuangelegten Feld zunaechst
437 // der Offset, an dem es selbst im Originalstring beginnt.
438 // Wenn beim Formatieren ein FollowFeld angelegt wird, wird
439 // der Offset dieses FollowFelds in nNextOffset festgehalten.
440 nNextOffset = nNextOffset + nNextOfst;
441 pFld->SetNextOffset( nNextOffset );
442 rInf.SetRest( pFld );
446 if( bEOL && rInf.GetLast() && !rInf.GetUnderFlow() )
447 rInf.GetLast()->FormatEOL( rInf );
448 return bFull;
451 /*************************************************************************
452 * virtual SwFldPortion::Paint()
453 *************************************************************************/
455 void SwFldPortion::Paint( const SwTxtPaintInfo &rInf ) const
457 SwFontSave aSave( rInf, pFnt );
459 ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" );
460 if( Width() && ( !bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) )
462 // Dies ist eine freizuegige Auslegung der Hintergrundbelegung ...
463 rInf.DrawViewOpt( *this, POR_FLD );
464 SwExpandPortion::Paint( rInf );
468 /*************************************************************************
469 * virtual SwFldPortion::GetExpTxt()
470 *************************************************************************/
472 sal_Bool SwFldPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
474 rTxt = aExpand;
475 if( !rTxt.Len() && rInf.OnWin() &&
476 !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() &&
477 SwViewOption::IsFieldShadings() &&
478 !HasFollow() )
479 rTxt = ' ';
480 return sal_True;
483 /*************************************************************************
484 * virtual SwFldPortion::HandlePortion()
485 *************************************************************************/
487 void SwFldPortion::HandlePortion( SwPortionHandler& rPH ) const
489 rPH.Special( GetLen(), aExpand, GetWhichPor() );
492 /*************************************************************************
493 * virtual SwFldPortion::GetTxtSize()
494 *************************************************************************/
496 SwPosSize SwFldPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
498 SwFontSave aSave( rInf, pFnt );
499 SwPosSize aSize( SwExpandPortion::GetTxtSize( rInf ) );
500 return aSize;
503 /*************************************************************************
504 * class SwHiddenPortion
505 *************************************************************************/
507 SwFldPortion *SwHiddenPortion::Clone(const XubString &rExpand ) const
509 SwFont *pNewFnt;
510 if( 0 != ( pNewFnt = pFnt ) )
511 pNewFnt = new SwFont( *pFnt );
512 return new SwHiddenPortion( rExpand, pNewFnt );
515 /*************************************************************************
516 * virtual SwHiddenPortion::Paint()
517 *************************************************************************/
519 void SwHiddenPortion::Paint( const SwTxtPaintInfo &rInf ) const
521 if( Width() )
523 SwFontSave aSave( rInf, pFnt );
524 rInf.DrawViewOpt( *this, POR_HIDDEN );
525 SwExpandPortion::Paint( rInf );
529 /*************************************************************************
530 * virtual SwHiddenPortion::GetExpTxt()
531 *************************************************************************/
533 sal_Bool SwHiddenPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
535 // Nicht auf IsHidden() abfragen !
536 return SwFldPortion::GetExpTxt( rInf, rTxt );
539 /*************************************************************************
540 * class SwNumberPortion
541 *************************************************************************/
543 // --> OD 2008-01-23 #newlistlevelattrs#
544 SwNumberPortion::SwNumberPortion( const XubString &rExpand,
545 SwFont *pFont,
546 const sal_Bool bLft,
547 const sal_Bool bCntr,
548 const KSHORT nMinDst,
549 const bool bLabelAlignmentPosAndSpaceModeActive )
550 : SwFldPortion( rExpand, pFont ),
551 nFixWidth(0),
552 nMinDist( nMinDst ),
553 // --> OD 2008-01-23 #newlistlevelattrs#
554 mbLabelAlignmentPosAndSpaceModeActive( bLabelAlignmentPosAndSpaceModeActive )
555 // <--
557 SetWhichPor( POR_NUMBER );
558 SetLeft( bLft );
559 SetHide( sal_False );
560 SetCenter( bCntr );
563 xub_StrLen SwNumberPortion::GetCrsrOfst( const MSHORT ) const
565 return 0;
568 SwFldPortion *SwNumberPortion::Clone( const XubString &rExpand ) const
570 SwFont *pNewFnt;
571 if( 0 != ( pNewFnt = pFnt ) )
572 pNewFnt = new SwFont( *pFnt );
573 // --> OD 2008-01-23 #newlistlevelattrs#
574 return new SwNumberPortion( rExpand, pNewFnt, IsLeft(), IsCenter(),
575 nMinDist, mbLabelAlignmentPosAndSpaceModeActive );
576 // <--
579 /*************************************************************************
580 * virtual SwNumberPortion::Format()
581 *************************************************************************/
583 // 5010: Wir sind in der Lage, mehrzeilige NumFelder anzulegen!
584 // 3689: Fies ist, wenn man in der Dialogbox soviel Davor-Text
585 // eingibt, bis die Zeile ueberlaeuft.
586 // Man muss die Fly-Ausweichmanoever beachten!
588 sal_Bool SwNumberPortion::Format( SwTxtFormatInfo &rInf )
590 SetHide( sal_False );
591 const sal_Bool bFull = SwFldPortion::Format( rInf );
592 SetLen( 0 );
593 // a numbering portion can be contained in a rotated portion!!!
594 nFixWidth = rInf.IsMulti() ? Height() : Width();
595 rInf.SetNumDone( !rInf.GetRest() );
596 if( rInf.IsNumDone() )
598 // SetAscent( rInf.GetAscent() );
599 ASSERT( Height() && nAscent, "NumberPortions without Height | Ascent" );
601 long nDiff( 0 );
602 // --> OD 2008-01-23 #newlistlevelattrs#
603 if ( !mbLabelAlignmentPosAndSpaceModeActive )
605 if ( !rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) &&
606 // --> FME 2004-08-13 #i32902#
607 !IsFtnNumPortion() )
608 // <--
610 nDiff = rInf.Left()
611 + rInf.GetTxtFrm()->GetTxtNode()->
612 GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst()
613 - rInf.First()
614 + rInf.ForcedLeftMargin();
616 else
618 nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
621 // <--
622 // Ein Vorschlag von Juergen und Volkmar:
623 // Der Textteil hinter der Numerierung sollte immer
624 // mindestens beim linken Rand beginnen.
625 if( nDiff < 0 )
626 nDiff = 0;
627 else if ( nDiff > rInf.X() )
628 nDiff -= rInf.X();
629 else
630 nDiff = 0;
632 if( nDiff < nFixWidth + nMinDist )
633 nDiff = nFixWidth + nMinDist;
634 // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde
635 // fieser Sonderfall: FlyFrm liegt in dem Bereich,
636 // den wir uns gerade unter den Nagel reissen wollen.
637 // Die NumberPortion wird als verborgen markiert.
638 const sal_Bool bFly = rInf.GetFly() ||
639 ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() );
640 if( nDiff > rInf.Width() )
642 nDiff = rInf.Width();
643 if ( bFly )
644 SetHide( sal_True );
647 // A numbering portion can be inside a SwRotatedPortion. Then the
648 // Height has to be changed
649 if ( rInf.IsMulti() )
651 if ( Height() < nDiff )
652 Height( KSHORT( nDiff ) );
654 else if( Width() < nDiff )
655 Width( KSHORT(nDiff) );
657 return bFull;
660 void SwNumberPortion::FormatEOL( SwTxtFormatInfo& )
662 /* Ein FormatEOL deutet daraufhin, dass der folgende Text
663 * nicht mit auf die Zeile passte. Damit die Numerierung mitwandert,
664 * wird diese NumberPortion verborgen.
667 // This caused trouble with flys anchored as characters.
668 // If one of these is numbered but does not fit to the line,
669 // it calls this function, causing a loop because both the number
670 // portion and the fly portion go to the next line
671 // SetHide( sal_True );
674 /*************************************************************************
675 * virtual SwNumberPortion::Paint()
676 *************************************************************************/
678 void SwNumberPortion::Paint( const SwTxtPaintInfo &rInf ) const
680 /* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt
681 * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile.
684 if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() )
686 SwLinePortion *pTmp = GetPortion();
687 while ( pTmp && !pTmp->InTxtGrp() )
688 pTmp = pTmp->GetPortion();
689 if ( !pTmp )
690 return;
693 // calculate the width of the number portion, including follows
694 const KSHORT nOldWidth = Width();
695 USHORT nSumWidth = 0;
696 USHORT nOffset = 0;
698 const SwLinePortion* pTmp = this;
699 while ( pTmp && pTmp->InNumberGrp() )
701 nSumWidth = nSumWidth + pTmp->Width();
702 if ( ((SwNumberPortion*)pTmp)->HasFollow() )
703 pTmp = pTmp->GetPortion();
704 else
706 nOffset = pTmp->Width() - ((SwNumberPortion*)pTmp)->nFixWidth;
707 break;
711 // The master portion takes care for painting the background of the
712 // follow field portions
713 if ( ! IsFollow() )
715 SwLinePortion *pThis = (SwLinePortion*)this;
716 pThis->Width( nSumWidth );
717 rInf.DrawViewOpt( *this, POR_NUMBER );
718 pThis->Width( nOldWidth );
721 if( aExpand.Len() )
723 const SwFont *pTmpFnt = rInf.GetFont();
724 sal_Bool bPaintSpace = ( UNDERLINE_NONE != pTmpFnt->GetUnderline() ||
725 UNDERLINE_NONE != pTmpFnt->GetOverline() ||
726 STRIKEOUT_NONE != pTmpFnt->GetStrikeout() ) &&
727 !pTmpFnt->IsWordLineMode();
728 if( bPaintSpace && pFnt )
729 bPaintSpace = ( UNDERLINE_NONE != pFnt->GetUnderline() ||
730 UNDERLINE_NONE != pFnt->GetOverline() ||
731 STRIKEOUT_NONE != pFnt->GetStrikeout() ) &&
732 !pFnt->IsWordLineMode();
734 SwFontSave aSave( rInf, pFnt );
736 if( nFixWidth == Width() && ! HasFollow() )
737 SwExpandPortion::Paint( rInf );
738 else
740 // logisches const: Width wird wieder zurueckgesetzt
741 SwLinePortion *pThis = (SwLinePortion*)this;
742 bPaintSpace = bPaintSpace && nFixWidth < nOldWidth;
743 KSHORT nSpaceOffs = nFixWidth;
744 pThis->Width( nFixWidth );
746 if( ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) ||
747 ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() ) )
748 SwExpandPortion::Paint( rInf );
749 else
751 SwTxtPaintInfo aInf( rInf );
752 if( nOffset < nMinDist )
753 nOffset = 0;
754 else
756 if( IsCenter() )
758 /* #110778# a / 2 * 2 == a is not a tautology */
759 KSHORT nTmpOffset = nOffset;
760 nOffset /= 2;
761 if( nOffset < nMinDist )
762 nOffset = nTmpOffset - nMinDist;
764 else
765 nOffset = nOffset - nMinDist;
767 aInf.X( aInf.X() + nOffset );
768 SwExpandPortion::Paint( aInf );
769 if( bPaintSpace )
770 nSpaceOffs = nSpaceOffs + nOffset;
772 if( bPaintSpace && nOldWidth > nSpaceOffs )
774 SwTxtPaintInfo aInf( rInf );
775 static sal_Char __READONLY_DATA sDoubleSpace[] = " ";
776 aInf.X( aInf.X() + nSpaceOffs );
778 // --> FME 2005-08-12 #i53199# Adjust position of underline:
779 if ( rInf.GetUnderFnt() )
781 const Point aNewPos( aInf.GetPos().X(), rInf.GetUnderFnt()->GetPos().Y() );
782 rInf.GetUnderFnt()->SetPos( aNewPos );
784 // <--
786 pThis->Width( nOldWidth - nSpaceOffs + 12 );
788 SwTxtSlot aDiffTxt( &aInf, this, true, false, sDoubleSpace );
789 aInf.DrawText( *this, aInf.GetLen(), sal_True );
792 pThis->Width( nOldWidth );
798 /*************************************************************************
799 * class SwBulletPortion
800 *************************************************************************/
802 // --> OD 2008-01-23 #newlistlevelattrs#
803 SwBulletPortion::SwBulletPortion( const xub_Unicode cBullet,
804 const XubString& rBulletFollowedBy,
805 SwFont *pFont,
806 const sal_Bool bLft,
807 const sal_Bool bCntr,
808 const KSHORT nMinDst,
809 const bool bLabelAlignmentPosAndSpaceModeActive )
810 : SwNumberPortion( XubString( rBulletFollowedBy ).Insert( cBullet, 0 ) ,
811 pFont, bLft, bCntr, nMinDst,
812 bLabelAlignmentPosAndSpaceModeActive )
813 // <--
815 SetWhichPor( POR_BULLET );
818 /*************************************************************************
819 * class SwGrfNumPortion
820 *************************************************************************/
822 #define GRFNUM_SECURE 10
824 // --> OD 2008-01-23 #newlistlevelattrs#
825 SwGrfNumPortion::SwGrfNumPortion(
826 SwFrm *pFrm,
827 const XubString& rGraphicFollowedBy,
828 const SvxBrushItem* pGrfBrush,
829 const SwFmtVertOrient* pGrfOrient, const Size& rGrfSize,
830 const sal_Bool bLft, const sal_Bool bCntr, const KSHORT nMinDst,
831 const bool bLabelAlignmentPosAndSpaceModeActive ) :
832 SwNumberPortion( rGraphicFollowedBy, NULL, bLft, bCntr, nMinDst,
833 bLabelAlignmentPosAndSpaceModeActive ),
834 // <--
835 pBrush( new SvxBrushItem(RES_BACKGROUND) ), nId( 0 )
837 SetWhichPor( POR_GRFNUM );
838 SetAnimated( sal_False );
839 bReplace = sal_False;
840 if( pGrfBrush )
842 *pBrush = *pGrfBrush;
843 SwDocShell *pSh = pFrm->GetShell()->GetDoc()->GetDocShell();
844 const Graphic* pGraph = pGrfBrush->GetGraphic( pSh );
845 if( pGraph )
846 SetAnimated( pGraph->IsAnimated() );
847 else
848 bReplace = sal_True;
850 if( pGrfOrient )
852 nYPos = pGrfOrient->GetPos();
853 eOrient = pGrfOrient->GetVertOrient();
855 else
857 nYPos = 0;
858 eOrient = text::VertOrientation::TOP;
860 Width( static_cast<USHORT>(rGrfSize.Width() + 2 * GRFNUM_SECURE) );
861 nFixWidth = Width();
862 nGrfHeight = rGrfSize.Height() + 2 * GRFNUM_SECURE;
863 Height( KSHORT(nGrfHeight) );
864 bNoPaint = sal_False;
867 SwGrfNumPortion::~SwGrfNumPortion()
869 if ( IsAnimated() )
870 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId );
871 delete pBrush;
874 void SwGrfNumPortion::StopAnimation( OutputDevice* pOut )
876 if ( IsAnimated() )
877 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( pOut, nId );
880 sal_Bool SwGrfNumPortion::Format( SwTxtFormatInfo &rInf )
882 SetHide( sal_False );
883 // --> OD 2008-01-29 #newlistlevelattrs#
884 // Width( nFixWidth );
885 KSHORT nFollowedByWidth( 0 );
886 if ( mbLabelAlignmentPosAndSpaceModeActive )
888 SwFldPortion::Format( rInf );
889 nFollowedByWidth = Width();
890 SetLen( 0 );
892 Width( nFixWidth + nFollowedByWidth );
893 // <--
894 const sal_Bool bFull = rInf.Width() < rInf.X() + Width();
895 const sal_Bool bFly = rInf.GetFly() ||
896 ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() );
897 SetAscent( static_cast<USHORT>(GetRelPos() > 0 ? GetRelPos() : 0) );
898 if( GetAscent() > Height() )
899 Height( GetAscent() );
901 if( bFull )
903 Width( rInf.Width() - (KSHORT)rInf.X() );
904 if( bFly )
906 SetLen( 0 );
907 SetNoPaint( sal_True );
908 rInf.SetNumDone( sal_False );
909 return sal_True;
912 rInf.SetNumDone( sal_True );
913 // --> OD 2008-01-23 #newlistlevelattrs#
914 // long nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
915 long nDiff = mbLabelAlignmentPosAndSpaceModeActive
917 : rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
918 // <--
919 // Ein Vorschlag von Juergen und Volkmar:
920 // Der Textteil hinter der Numerierung sollte immer
921 // mindestens beim linken Rand beginnen.
922 if( nDiff < 0 )
923 nDiff = 0;
924 else if ( nDiff > rInf.X() )
925 nDiff -= rInf.X();
926 if( nDiff < nFixWidth + nMinDist )
927 nDiff = nFixWidth + nMinDist;
928 // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde
929 // fieser Sonderfall: FlyFrm liegt in dem Bereich,
930 // den wir uns gerade unter den Nagel reissen wollen.
931 // Die NumberPortion wird als verborgen markiert.
932 if( nDiff > rInf.Width() )
934 nDiff = rInf.Width();
935 if( bFly )
936 SetHide( sal_True );
939 if( Width() < nDiff )
940 Width( KSHORT(nDiff) );
941 return bFull;
944 void SwGrfNumPortion::Paint( const SwTxtPaintInfo &rInf ) const
946 if( DontPaint() )
947 return;
948 /* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt
949 * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile.
951 if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() )
953 SwLinePortion *pTmp = GetPortion();
954 while ( pTmp && !pTmp->InTxtGrp() )
955 pTmp = pTmp->GetPortion();
956 if ( !pTmp )
957 return;
959 Point aPos( rInf.X() + GRFNUM_SECURE, rInf.Y() - GetRelPos() + GRFNUM_SECURE );
960 long nTmpWidth = Max( (long)0, (long)(nFixWidth - 2 * GRFNUM_SECURE) );
961 Size aSize( nTmpWidth, GetGrfHeight() - 2 * GRFNUM_SECURE );
963 // --> OD 2008-02-05 #newlistlevelattrs#
964 const sal_Bool bTmpLeft = mbLabelAlignmentPosAndSpaceModeActive ||
965 ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) ||
966 ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() );
967 // <--
969 if( nFixWidth < Width() && !bTmpLeft )
971 KSHORT nOffset = Width() - nFixWidth;
972 if( nOffset < nMinDist )
973 nOffset = 0;
974 else
976 if( IsCenter() )
978 nOffset /= 2;
979 if( nOffset < nMinDist )
980 nOffset = Width() - nFixWidth - nMinDist;
982 else
983 nOffset = nOffset - nMinDist;
985 aPos.X() += nOffset;
988 if( bReplace )
990 KSHORT nTmpH = GetPortion() ? GetPortion()->GetAscent() : 120;
991 aSize = Size( nTmpH, nTmpH );
992 aPos.Y() = rInf.Y() - nTmpH;
994 SwRect aTmp( aPos, aSize );
996 sal_Bool bDraw = sal_True;
998 if ( IsAnimated() )
1000 bDraw = !rInf.GetOpt().IsGraphic();
1001 if( !nId )
1003 SetId( long( rInf.GetTxtFrm() ) );
1004 rInf.GetTxtFrm()->SetAnimation();
1006 if( aTmp.IsOver( rInf.GetPaintRect() ) && !bDraw )
1008 rInf.NoteAnimation();
1009 const ViewShell* pViewShell = rInf.GetVsh();
1011 // virtual device, not pdf export
1012 if( OUTDEV_VIRDEV == rInf.GetOut()->GetOutDevType() &&
1013 pViewShell && pViewShell->GetWin() )
1015 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation(0,nId);
1016 rInf.GetTxtFrm()->GetShell()->InvalidateWindows( aTmp );
1020 else if ( pViewShell &&
1021 !pViewShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() &&
1022 !pViewShell->IsPreView() &&
1023 // --> FME 2004-06-21 #i9684# Stop animation during printing/pdf export.
1024 pViewShell->GetWin() )
1025 // <--
1027 ( (Graphic*) pBrush->GetGraphic() )->StartAnimation(
1028 (OutputDevice*)rInf.GetOut(), aPos, aSize, nId );
1031 // pdf export, printing, preview, stop animations...
1032 else
1033 bDraw = sal_True;
1035 if( bDraw )
1036 ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId );
1039 SwRect aRepaint( rInf.GetPaintRect() );
1040 const SwTxtFrm& rFrm = *rInf.GetTxtFrm();
1041 if( rFrm.IsVertical() )
1043 rFrm.SwitchHorizontalToVertical( aTmp );
1044 rFrm.SwitchHorizontalToVertical( aRepaint );
1047 if( rFrm.IsRightToLeft() )
1049 rFrm.SwitchLTRtoRTL( aTmp );
1050 rFrm.SwitchLTRtoRTL( aRepaint );
1053 if( bDraw && aTmp.HasArea() )
1054 DrawGraphic( pBrush, (OutputDevice*)rInf.GetOut(),
1055 aTmp, aRepaint, bReplace ? GRFNUM_REPLACE : GRFNUM_YES );
1058 void SwGrfNumPortion::SetBase( long nLnAscent, long nLnDescent,
1059 long nFlyAsc, long nFlyDesc )
1061 if ( GetOrient() != text::VertOrientation::NONE )
1063 SetRelPos( 0 );
1064 if ( GetOrient() == text::VertOrientation::CENTER )
1065 SetRelPos( GetGrfHeight() / 2 );
1066 else if ( GetOrient() == text::VertOrientation::TOP )
1067 SetRelPos( GetGrfHeight() - GRFNUM_SECURE );
1068 else if ( GetOrient() == text::VertOrientation::BOTTOM )
1070 else if ( GetOrient() == text::VertOrientation::CHAR_CENTER )
1071 SetRelPos( ( GetGrfHeight() + nLnAscent - nLnDescent ) / 2 );
1072 else if ( GetOrient() == text::VertOrientation::CHAR_TOP )
1073 SetRelPos( nLnAscent );
1074 else if ( GetOrient() == text::VertOrientation::CHAR_BOTTOM )
1075 SetRelPos( GetGrfHeight() - nLnDescent );
1076 else
1078 if( GetGrfHeight() >= nFlyAsc + nFlyDesc )
1080 // wenn ich genauso gross bin wie die Zeile, brauche ich mich
1081 // nicht an der Zeile nicht weiter ausrichten, ich lasse
1082 // dann auch den max. Ascent der Zeile unveraendert
1084 SetRelPos( nFlyAsc );
1086 else if ( GetOrient() == text::VertOrientation::LINE_CENTER )
1087 SetRelPos( ( GetGrfHeight() + nFlyAsc - nFlyDesc ) / 2 );
1088 else if ( GetOrient() == text::VertOrientation::LINE_TOP )
1089 SetRelPos( nFlyAsc );
1090 else if ( GetOrient() == text::VertOrientation::LINE_BOTTOM )
1091 SetRelPos( GetGrfHeight() - nFlyDesc );
1096 void SwTxtFrm::StopAnimation( OutputDevice* pOut )
1098 ASSERT( HasAnimation(), "SwTxtFrm::StopAnimation: Which Animation?" );
1099 if( HasPara() )
1101 SwLineLayout *pLine = GetPara();
1102 while( pLine )
1104 SwLinePortion *pPor = pLine->GetPortion();
1105 while( pPor )
1107 if( pPor->IsGrfNumPortion() )
1108 ((SwGrfNumPortion*)pPor)->StopAnimation( pOut );
1109 // Die Numerierungsportion sitzt immer vor dem ersten Zeichen,
1110 // deshalb koennen wir abbrechen, sobald wir eine Portion mit
1111 // einer Laenge > 0 erreicht haben.
1112 pPor = pPor->GetLen() ? 0 : pPor->GetPortion();
1114 pLine = pLine->GetLen() ? 0 : pLine->GetNext();
1119 /*************************************************************************
1120 * SwCombinedPortion::SwCombinedPortion(..)
1121 * initializes the script array and clears the width array
1122 *************************************************************************/
1124 SwCombinedPortion::SwCombinedPortion( const XubString &rTxt )
1125 : SwFldPortion( rTxt )
1127 SetLen(1);
1128 SetWhichPor( POR_COMBINED );
1129 if( aExpand.Len() > 6 )
1130 aExpand.Erase( 6 );
1131 // Initialization of the scripttype array,
1132 // the arrays of width and position are filled by the format function
1133 if( pBreakIt->GetBreakIter().is() )
1135 BYTE nScr = SW_SCRIPTS;
1136 for( USHORT i = 0; i < rTxt.Len(); ++i )
1138 USHORT nScript = pBreakIt->GetBreakIter()->getScriptType( rTxt, i );
1139 switch ( nScript ) {
1140 case i18n::ScriptType::LATIN : nScr = SW_LATIN; break;
1141 case i18n::ScriptType::ASIAN : nScr = SW_CJK; break;
1142 case i18n::ScriptType::COMPLEX : nScr = SW_CTL; break;
1144 aScrType[i] = nScr;
1147 else
1149 for( USHORT i = 0; i < 6; aScrType[i++] = 0 )
1150 ; // nothing
1152 memset( &aWidth, 0, sizeof(aWidth) );
1155 /*************************************************************************
1156 * SwCombinedPortion::Paint(..)
1157 *************************************************************************/
1159 void SwCombinedPortion::Paint( const SwTxtPaintInfo &rInf ) const
1161 ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" );
1162 if( Width() )
1164 rInf.DrawBackBrush( *this );
1165 rInf.DrawViewOpt( *this, POR_FLD );
1167 // do we have to repaint a post it portion?
1168 if( rInf.OnWin() && pPortion && !pPortion->Width() )
1169 pPortion->PrePaint( rInf, this );
1171 USHORT nCount = aExpand.Len();
1172 if( !nCount )
1173 return;
1174 ASSERT( nCount < 7, "Too much combined characters" );
1176 // the first character of the second row
1177 USHORT nTop = ( nCount + 1 ) / 2;
1179 SwFont aTmpFont( *rInf.GetFont() );
1180 aTmpFont.SetProportion( nProportion ); // a smaller font
1181 SwFontSave aFontSave( rInf, &aTmpFont );
1183 USHORT i = 0;
1184 Point aOldPos = rInf.GetPos();
1185 Point aOutPos( aOldPos.X(), aOldPos.Y() - nUpPos );// Y of the first row
1186 while( i < nCount )
1188 if( i == nTop ) // change the row
1189 aOutPos.Y() = aOldPos.Y() + nLowPos; // Y of the second row
1190 aOutPos.X() = aOldPos.X() + aPos[i]; // X position
1191 const BYTE nAct = aScrType[i]; // script type
1192 aTmpFont.SetActual( nAct );
1193 // if there're more than 4 characters to display, we choose fonts
1194 // with 2/3 of the original font width.
1195 if( aWidth[ nAct ] )
1197 Size aTmpSz = aTmpFont.GetSize( nAct );
1198 if( aTmpSz.Width() != aWidth[ nAct ] )
1200 aTmpSz.Width() = aWidth[ nAct ];
1201 aTmpFont.SetSize( aTmpSz, nAct );
1204 ((SwTxtPaintInfo&)rInf).SetPos( aOutPos );
1205 rInf.DrawText( aExpand, *this, i, 1 );
1206 ++i;
1208 // rInf is const, so we have to take back our manipulations
1209 ((SwTxtPaintInfo&)rInf).SetPos( aOldPos );
1213 /*************************************************************************
1214 * SwCombinedPortion::Format(..)
1215 *************************************************************************/
1217 sal_Bool SwCombinedPortion::Format( SwTxtFormatInfo &rInf )
1219 USHORT nCount = aExpand.Len();
1220 if( !nCount )
1222 Width( 0 );
1223 return sal_False;
1226 ASSERT( nCount < 7, "Too much combined characters" );
1227 // If there are leading "weak"-scripttyped characters in this portion,
1228 // they get the actual scripttype.
1229 USHORT i = 0;
1230 while( i < nCount && SW_SCRIPTS == aScrType[i] )
1231 aScrType[i++] = rInf.GetFont()->GetActual();
1232 if( nCount > 4 )
1234 // more than four? Ok, then we need the 2/3 font width
1235 i = 0;
1236 while( i < aExpand.Len() )
1238 ASSERT( aScrType[i] < SW_SCRIPTS, "Combined: Script fault" );
1239 if( !aWidth[ aScrType[i] ] )
1241 rInf.GetOut()->SetFont( rInf.GetFont()->GetFnt( aScrType[i] ) );
1242 aWidth[ aScrType[i] ] =
1243 static_cast<USHORT>(2 * rInf.GetOut()->GetFontMetric().GetSize().Width() / 3);
1245 ++i;
1249 USHORT nTop = ( nCount + 1 ) / 2; // the first character of the second line
1250 ViewShell *pSh = rInf.GetTxtFrm()->GetShell();
1251 SwFont aTmpFont( *rInf.GetFont() );
1252 SwFontSave aFontSave( rInf, &aTmpFont );
1253 nProportion = 55;
1254 // In nMainAscent/Descent we store the ascent and descent
1255 // of the original surrounding font
1256 USHORT nMaxDescent, nMaxAscent, nMaxWidth;
1257 USHORT nMainDescent = rInf.GetFont()->GetHeight( pSh, *rInf.GetOut() );
1258 const USHORT nMainAscent = rInf.GetFont()->GetAscent( pSh, *rInf.GetOut() );
1259 nMainDescent = nMainDescent - nMainAscent;
1260 // we start with a 50% font, but if we notice that the combined portion
1261 // becomes bigger than the surrounding font, we check 45% and maybe 40%.
1264 nProportion -= 5;
1265 aTmpFont.SetProportion( nProportion );
1266 i = 0;
1267 memset( &aPos, 0, sizeof(aPos) );
1268 nMaxDescent = 0;
1269 nMaxAscent = 0;
1270 nMaxWidth = 0;
1271 nUpPos = nLowPos = 0;
1273 // Now we get the width of all characters.
1274 // The ascent and the width of the first line are stored in the
1275 // ascent member of the portion, the descent in nLowPos.
1276 // The ascent, descent and width of the second line are stored in the
1277 // local nMaxAscent, nMaxDescent and nMaxWidth variables.
1278 while( i < nCount )
1280 BYTE nScrp = aScrType[i];
1281 aTmpFont.SetActual( nScrp );
1282 if( aWidth[ nScrp ] )
1284 Size aFontSize( aTmpFont.GetSize( nScrp ) );
1285 aFontSize.Width() = aWidth[ nScrp ];
1286 aTmpFont.SetSize( aFontSize, nScrp );
1289 SwDrawTextInfo aDrawInf( pSh, *rInf.GetOut(), 0, aExpand, i, 1 );
1290 Size aSize = aTmpFont._GetTxtSize( aDrawInf );
1291 USHORT nAsc = aTmpFont.GetAscent( pSh, *rInf.GetOut() );
1292 aPos[ i ] = (USHORT)aSize.Width();
1293 if( i == nTop ) // enter the second line
1295 nLowPos = nMaxDescent;
1296 Height( nMaxDescent + nMaxAscent );
1297 Width( nMaxWidth );
1298 SetAscent( nMaxAscent );
1299 nMaxAscent = 0;
1300 nMaxDescent = 0;
1301 nMaxWidth = 0;
1303 nMaxWidth = nMaxWidth + aPos[ i++ ];
1304 if( nAsc > nMaxAscent )
1305 nMaxAscent = nAsc;
1306 if( aSize.Height() - nAsc > nMaxDescent )
1307 nMaxDescent = static_cast<USHORT>(aSize.Height() - nAsc);
1309 // for one or two characters we double the width of the portion
1310 if( nCount < 3 )
1312 nMaxWidth *= 2;
1313 Width( 2*Width() );
1314 if( nCount < 2 )
1316 Height( nMaxAscent + nMaxDescent );
1317 nLowPos = nMaxDescent;
1320 Height( Height() + nMaxDescent + nMaxAscent );
1321 nUpPos = nMaxAscent;
1322 SetAscent( Height() - nMaxDescent - nLowPos );
1323 } while( nProportion > 40 && ( GetAscent() > nMainAscent ||
1324 Height() - GetAscent() > nMainDescent ) );
1325 // if the combined portion is smaller than the surrounding text,
1326 // the portion grows. This looks better, if there's a character background.
1327 if( GetAscent() < nMainAscent )
1329 Height( Height() + nMainAscent - GetAscent() );
1330 SetAscent( nMainAscent );
1332 if( Height() < nMainAscent + nMainDescent )
1333 Height( nMainAscent + nMainDescent );
1335 // We calculate the x positions of the characters in both lines..
1336 USHORT nTopDiff = 0;
1337 USHORT nBotDiff = 0;
1338 if( nMaxWidth > Width() )
1340 nTopDiff = ( nMaxWidth - Width() ) / 2;
1341 Width( nMaxWidth );
1343 else
1344 nBotDiff = ( Width() - nMaxWidth ) / 2;
1345 switch( nTop)
1347 case 3: aPos[1] = aPos[0] + nTopDiff; // no break
1348 case 2: aPos[nTop-1] = Width() - aPos[nTop-1];
1350 aPos[0] = 0;
1351 switch( nCount )
1353 case 5: aPos[4] = aPos[3] + nBotDiff; // no break
1354 case 3: aPos[nTop] = nBotDiff; break;
1355 case 6: aPos[4] = aPos[3] + nBotDiff; // no break
1356 case 4: aPos[nTop] = 0; // no break
1357 case 2: aPos[nCount-1] = Width() - aPos[nCount-1];
1360 // Does the combined portion fit the line?
1361 const sal_Bool bFull = rInf.Width() < rInf.X() + Width();
1362 if( bFull )
1364 if( rInf.GetLineStart() == rInf.GetIdx() && (!rInf.GetLast()->InFldGrp()
1365 || !((SwFldPortion*)rInf.GetLast())->IsFollow() ) )
1366 Width( (USHORT)( rInf.Width() - rInf.X() ) );
1367 else
1369 Truncate();
1370 Width( 0 );
1371 SetLen( 0 );
1372 if( rInf.GetLast() )
1373 rInf.GetLast()->FormatEOL( rInf );
1376 return bFull;
1379 /*************************************************************************
1380 * SwCombinedPortion::GetViewWidth(..)
1381 *************************************************************************/
1383 KSHORT SwCombinedPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
1385 if( !GetLen() ) // for the dummy part at the end of the line, where
1386 return 0; // the combined portion doesn't fit.
1387 return SwFldPortion::GetViewWidth( rInf );