summaryrefslogtreecommitdiff
path: root/sw/source/core/text/porfld.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/text/porfld.cxx')
-rw-r--r--sw/source/core/text/porfld.cxx1385
1 files changed, 1385 insertions, 0 deletions
diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx
new file mode 100644
index 000000000000..1555fca79192
--- /dev/null
+++ b/sw/source/core/text/porfld.cxx
@@ -0,0 +1,1385 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+
+#include <hintids.hxx>
+
+#include <com/sun/star/i18n/ScriptType.hdl>
+#include <vcl/graph.hxx>
+#include <editeng/brshitem.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/outdev.hxx>
+#include <viewopt.hxx> // SwViewOptions
+#include <txtcfg.hxx>
+#include <SwPortionHandler.hxx>
+#include <porlay.hxx>
+#include <porfld.hxx>
+#include <inftxt.hxx>
+#include <blink.hxx> // pBlink
+#include <frmtool.hxx> // DrawGraphic
+#include <viewsh.hxx>
+#include <docsh.hxx>
+#include <doc.hxx>
+#include "rootfrm.hxx"
+#include <breakit.hxx>
+#include <porrst.hxx>
+#include <porftn.hxx> // SwFtnPortion
+#include <accessibilityoptions.hxx>
+#include <editeng/lrspitem.hxx>
+
+#include <unicode/ubidi.h>
+
+using namespace ::com::sun::star;
+
+/*************************************************************************
+ * class SwFldPortion
+ *************************************************************************/
+
+SwLinePortion *SwFldPortion::Compress()
+{ return (GetLen() || aExpand.Len() || SwLinePortion::Compress()) ? this : 0; }
+
+SwFldPortion *SwFldPortion::Clone( const XubString &rExpand ) const
+{
+ SwFont *pNewFnt;
+ if( 0 != ( pNewFnt = pFnt ) )
+ {
+ pNewFnt = new SwFont( *pFnt );
+ }
+ // --> OD 2009-11-25 #i107143#
+ // pass placeholder property to created <SwFldPortion> instance.
+ SwFldPortion* pClone = new SwFldPortion( rExpand, pNewFnt, bPlaceHolder );
+ // <--
+ pClone->SetNextOffset( nNextOffset );
+ pClone->m_bNoLength = this->m_bNoLength;
+ return pClone;
+}
+
+void SwFldPortion::TakeNextOffset( const SwFldPortion* pFld )
+{
+ ASSERT( pFld, "TakeNextOffset: Missing Source" );
+ nNextOffset = pFld->GetNextOffset();
+ aExpand.Erase( 0, nNextOffset );
+ bFollow = sal_True;
+}
+
+SwFldPortion::SwFldPortion( const XubString &rExpand, SwFont *pFont, sal_Bool bPlaceHold )
+ : aExpand(rExpand), pFnt(pFont), nNextOffset(0), nNextScriptChg(STRING_LEN), nViewWidth(0),
+ bFollow( sal_False ), bHasFollow( sal_False ), bPlaceHolder( bPlaceHold )
+ , m_bNoLength( sal_False )
+{
+ SetWhichPor( POR_FLD );
+}
+
+SwFldPortion::SwFldPortion( const SwFldPortion& rFld )
+ : SwExpandPortion( rFld ),
+ aExpand( rFld.GetExp() ),
+ nNextOffset( rFld.GetNextOffset() ),
+ nNextScriptChg( rFld.GetNextScriptChg() ),
+ bFollow( rFld.IsFollow() ),
+ bLeft( rFld.IsLeft() ),
+ bHide( rFld.IsHide() ),
+ bCenter( rFld.IsCenter() ),
+ bHasFollow( rFld.HasFollow() ),
+ bPlaceHolder( rFld.bPlaceHolder )
+ , m_bNoLength( rFld.m_bNoLength )
+{
+ if ( rFld.HasFont() )
+ pFnt = new SwFont( *rFld.GetFont() );
+ else
+ pFnt = 0;
+
+ SetWhichPor( POR_FLD );
+}
+
+SwFldPortion::~SwFldPortion()
+{
+ delete pFnt;
+ if( pBlink )
+ pBlink->Delete( this );
+}
+
+/*************************************************************************
+ * virtual SwFldPortion::GetViewWidth()
+ *************************************************************************/
+
+KSHORT SwFldPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
+{
+ // Wir stehen zwar im const, aber nViewWidth sollte erst im letzten
+ // Moment errechnet werden:
+ SwFldPortion* pThis = (SwFldPortion*)this;
+ if( !Width() && rInf.OnWin() && !rInf.GetOpt().IsPagePreview() &&
+ !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
+ {
+ if( !nViewWidth )
+ pThis->nViewWidth = rInf.GetTxtSize( ' ' ).Width();
+ }
+ else
+ pThis->nViewWidth = 0;
+ return nViewWidth;
+}
+
+/*************************************************************************
+ * virtual SwFldPortion::Format()
+ *************************************************************************/
+
+// 8653: in keinem Fall nur SetLen(0);
+
+/*************************************************************************
+ * Hilfsklasse SwFldSlot
+ **************************************************************************/
+
+class SwFldSlot
+{
+ const XubString *pOldTxt;
+ XubString aTxt;
+ xub_StrLen nIdx;
+ xub_StrLen nLen;
+ sal_Bool bOn;
+ SwTxtFormatInfo *pInf;
+public:
+ SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor );
+ ~SwFldSlot();
+};
+
+SwFldSlot::SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor )
+{
+ bOn = pPor->GetExpTxt( *pNew, aTxt );
+
+ // Der Text wird ausgetauscht...
+ if( bOn )
+ {
+ pInf = (SwTxtFormatInfo*)pNew;
+ nIdx = pInf->GetIdx();
+ nLen = pInf->GetLen();
+ pOldTxt = &(pInf->GetTxt());
+ pInf->SetLen( aTxt.Len() );
+ if( pPor->IsFollow() )
+ {
+ pInf->SetFakeLineStart( nIdx > pInf->GetLineStart() );
+ pInf->SetIdx( 0 );
+ }
+ else
+ {
+ XubString aTmp( aTxt );
+ aTxt = *pOldTxt;
+ aTxt.Erase( nIdx, 1 );
+ aTxt.Insert( aTmp, nIdx );
+ }
+ pInf->SetTxt( aTxt );
+ }
+}
+
+SwFldSlot::~SwFldSlot()
+{
+ if( bOn )
+ {
+ pInf->SetTxt( *pOldTxt );
+ pInf->SetIdx( nIdx );
+ pInf->SetLen( nLen );
+ pInf->SetFakeLineStart( sal_False );
+ }
+}
+
+void SwFldPortion::CheckScript( const SwTxtSizeInfo &rInf )
+{
+ String aTxt;
+ if( GetExpTxt( rInf, aTxt ) && aTxt.Len() && pBreakIt->GetBreakIter().is() )
+ {
+ sal_uInt8 nActual = pFnt ? pFnt->GetActual() : rInf.GetFont()->GetActual();
+ sal_uInt16 nScript;
+ {
+ nScript = pBreakIt->GetBreakIter()->getScriptType( aTxt, 0 );
+ xub_StrLen nChg = 0;
+ if( i18n::ScriptType::WEAK == nScript )
+ {
+ nChg =(xub_StrLen)pBreakIt->GetBreakIter()->endOfScript(aTxt,0,nScript);
+ if( nChg < aTxt.Len() )
+ nScript = pBreakIt->GetBreakIter()->getScriptType( aTxt, nChg );
+ }
+
+ //
+ // nNextScriptChg will be evaluated during SwFldPortion::Format()
+ //
+ if ( nChg < aTxt.Len() )
+ nNextScriptChg = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( aTxt, nChg, nScript );
+ else
+ nNextScriptChg = aTxt.Len();
+
+ }
+ sal_uInt8 nTmp;
+ switch ( nScript ) {
+ case i18n::ScriptType::LATIN : nTmp = SW_LATIN; break;
+ case i18n::ScriptType::ASIAN : nTmp = SW_CJK; break;
+ case i18n::ScriptType::COMPLEX : nTmp = SW_CTL; break;
+ default: nTmp = nActual;
+ }
+
+ // #i16354# Change script type for RTL text to CTL.
+ const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo();
+ // --> OD 2009-01-29 #i98418#
+// const sal_uInt8 nFldDir = IsNumberPortion() ?
+ const sal_uInt8 nFldDir = ( IsNumberPortion() || IsFtnNumPortion() ) ?
+ rSI.GetDefaultDir() :
+ rSI.DirType( IsFollow() ? rInf.GetIdx() - 1 : rInf.GetIdx() );
+ // <--
+ if ( UBIDI_RTL == nFldDir )
+ {
+ UErrorCode nError = U_ZERO_ERROR;
+ UBiDi* pBidi = ubidi_openSized( aTxt.Len(), 0, &nError );
+ ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aTxt.GetBuffer()), aTxt.Len(), nFldDir, NULL, &nError );
+ int32_t nEnd;
+ UBiDiLevel nCurrDir;
+ ubidi_getLogicalRun( pBidi, 0, &nEnd, &nCurrDir );
+ ubidi_close( pBidi );
+ const xub_StrLen nNextDirChg = (xub_StrLen)nEnd;
+ nNextScriptChg = Min( nNextScriptChg, nNextDirChg );
+
+ // #i89825# change the script type also to CTL
+ // if there is no strong LTR char in the LTR run (numbers)
+ if ( nCurrDir != UBIDI_RTL )
+ {
+ nCurrDir = UBIDI_RTL;
+ for ( xub_StrLen nCharIdx = 0; nCharIdx < nEnd; ++nCharIdx )
+ {
+ UCharDirection nCharDir = u_charDirection ( aTxt.GetChar ( nCharIdx ));
+ if ( nCharDir == U_LEFT_TO_RIGHT ||
+ nCharDir == U_LEFT_TO_RIGHT_EMBEDDING ||
+ nCharDir == U_LEFT_TO_RIGHT_OVERRIDE )
+ {
+ nCurrDir = UBIDI_LTR;
+ break;
+ }
+ }
+ }
+
+ if ( nCurrDir == UBIDI_RTL )
+ nTmp = SW_CTL;
+ }
+
+ // --> OD 2009-01-29 #i98418#
+ // keep determined script type for footnote portions as preferred script type.
+ // For footnote portions a font can not be created directly - see footnote
+ // portion format method.
+// if( !IsFtnPortion() && nTmp != nActual )
+ if ( IsFtnPortion() )
+ {
+ dynamic_cast<SwFtnPortion*>(this)->SetPreferredScriptType( nTmp );
+ }
+ else if ( nTmp != nActual )
+ {
+ if( !pFnt )
+ pFnt = new SwFont( *rInf.GetFont() );
+ pFnt->SetActual( nTmp );
+ }
+ // <--
+ }
+}
+
+sal_Bool SwFldPortion::Format( SwTxtFormatInfo &rInf )
+{
+ // Scope wegen aDiffTxt::DTOR!
+ xub_StrLen nRest;
+ sal_Bool bFull;
+ sal_Bool bEOL = sal_False;
+ long nTxtRest = rInf.GetTxt().Len() - rInf.GetIdx();
+ {
+ SwFldSlot aDiffTxt( &rInf, this );
+ SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
+ aLayoutModeModifier.SetAuto();
+
+ // Field portion has to be split in several parts if
+ // 1. There are script/direction changes inside the field
+ // 2. There are portion breaks (tab, break) inside the field:
+ const xub_StrLen nOldFullLen = rInf.GetLen();
+ xub_StrLen nFullLen = rInf.ScanPortionEnd( rInf.GetIdx(), rInf.GetIdx() + nOldFullLen ) - rInf.GetIdx();
+ if ( nNextScriptChg < nFullLen )
+ {
+ nFullLen = nNextScriptChg;
+ rInf.SetHookChar( 0 );
+ }
+ rInf.SetLen( nFullLen );
+
+ if ( STRING_LEN != rInf.GetUnderScorePos() &&
+ rInf.GetUnderScorePos() > rInf.GetIdx() )
+ rInf.SetUnderScorePos( rInf.GetIdx() );
+
+ if( pFnt )
+ pFnt->GoMagic( rInf.GetVsh(), pFnt->GetActual() );
+
+ SwFontSave aSave( rInf, pFnt );
+
+ // 8674: Laenge muss 0 sein, bei bFull nach Format ist die Laenge
+ // gesetzt und wird in nRest uebertragen. Ansonsten bleibt die
+ // Laenge erhalten und wuerde auch in nRest einfliessen!
+ SetLen(0);
+ const MSHORT nFollow = IsFollow() ? 0 : 1;
+
+ // So komisch es aussieht, die Abfrage auf GetLen() muss wegen der
+ // ExpandPortions _hinter_ aDiffTxt (vgl. SoftHyphs)
+ // sal_False returnen wegen SetFull ...
+ if( !nFullLen )
+ {
+ // nicht Init(), weil wir Hoehe und Ascent brauchen
+ Width(0);
+ bFull = rInf.Width() <= rInf.GetPos().X();
+ }
+ else
+ {
+ xub_StrLen nOldLineStart = rInf.GetLineStart();
+ if( IsFollow() )
+ rInf.SetLineStart( 0 );
+ rInf.SetNotEOL( nFullLen == nOldFullLen && nTxtRest > nFollow );
+
+ // the height depending on the fields font is set,
+ // this is required for SwTxtGuess::Guess
+ Height( rInf.GetTxtHeight() );
+ // If a kerning portion is inserted after our field portion,
+ // the ascent and height must be known
+ SetAscent( rInf.GetAscent() );
+ bFull = SwTxtPortion::Format( rInf );
+ rInf.SetNotEOL( sal_False );
+ rInf.SetLineStart( nOldLineStart );
+ }
+ xub_StrLen nTmpLen = GetLen();
+ bEOL = !nTmpLen && nFollow && bFull;
+ nRest = nOldFullLen - nTmpLen;
+
+ // Das Zeichen wird in der ersten Portion gehalten.
+ // Unbedingt nach Format!
+ SetLen( (m_bNoLength) ? 0 : nFollow );
+
+ if( nRest )
+ {
+ // aExpand ist noch nicht gekuerzt worden, der neue Ofst
+ // ergibt sich durch nRest.
+ xub_StrLen nNextOfst = aExpand.Len() - nRest;
+
+ if ( IsQuoVadisPortion() )
+ nNextOfst = nNextOfst + ((SwQuoVadisPortion*)this)->GetContTxt().Len();
+
+ XubString aNew( aExpand, nNextOfst, STRING_LEN );
+ aExpand.Erase( nNextOfst, STRING_LEN );
+
+ // These characters should not be contained in the follow
+ // field portion. They are handled via the HookChar mechanism.
+ switch( aNew.GetChar( 0 ))
+ {
+ case CH_BREAK : bFull = sal_True;
+ // kein break;
+ case ' ' :
+ case CH_TAB :
+ case CHAR_HARDHYPHEN: // non-breaking hyphen
+ case CHAR_SOFTHYPHEN:
+ case CHAR_HARDBLANK:
+ // --> FME 2006-01-11 #i59759# Erase additional control
+ // characters from field string, otherwise we get stuck in
+ // a loop.
+ case CHAR_ZWSP :
+ case CHAR_ZWNBSP :
+ // case CHAR_RLM :
+ // case CHAR_LRM :
+ // <--
+ // --> OD 2010-06-03 #i111750#
+ // - Erasing further control characters from field string in
+ // to avoid loop.
+ case CH_TXTATR_BREAKWORD:
+ case CH_TXTATR_INWORD:
+ // <--
+ {
+ aNew.Erase( 0, 1 );
+ ++nNextOfst;
+ break;
+ }
+ default: ;
+ }
+
+ // Even if there is no more text left for a follow field,
+ // we have to build a follow field portion (without font),
+ // otherwise the HookChar mechanism would not work.
+ SwFldPortion *pFld = Clone( aNew );
+ if( aNew.Len() && !pFld->GetFont() )
+ {
+ SwFont *pNewFnt = new SwFont( *rInf.GetFont() );
+ pFld->SetFont( pNewFnt );
+ }
+ pFld->SetFollow( sal_True );
+ SetHasFollow( sal_True );
+ // In nNextOffset steht bei einem neuangelegten Feld zunaechst
+ // der Offset, an dem es selbst im Originalstring beginnt.
+ // Wenn beim Formatieren ein FollowFeld angelegt wird, wird
+ // der Offset dieses FollowFelds in nNextOffset festgehalten.
+ nNextOffset = nNextOffset + nNextOfst;
+ pFld->SetNextOffset( nNextOffset );
+ rInf.SetRest( pFld );
+ }
+ }
+
+ if( bEOL && rInf.GetLast() && !rInf.GetUnderFlow() )
+ rInf.GetLast()->FormatEOL( rInf );
+ return bFull;
+}
+
+/*************************************************************************
+ * virtual SwFldPortion::Paint()
+ *************************************************************************/
+
+void SwFldPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ SwFontSave aSave( rInf, pFnt );
+
+ ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" );
+ if( Width() && ( !bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) )
+ {
+ // Dies ist eine freizuegige Auslegung der Hintergrundbelegung ...
+ rInf.DrawViewOpt( *this, POR_FLD );
+ SwExpandPortion::Paint( rInf );
+ }
+}
+
+/*************************************************************************
+ * virtual SwFldPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwFldPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
+{
+ rTxt = aExpand;
+ if( !rTxt.Len() && rInf.OnWin() &&
+ !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() &&
+ SwViewOption::IsFieldShadings() &&
+ !HasFollow() )
+ rTxt = ' ';
+ return sal_True;
+}
+
+/*************************************************************************
+ * virtual SwFldPortion::HandlePortion()
+ *************************************************************************/
+
+void SwFldPortion::HandlePortion( SwPortionHandler& rPH ) const
+{
+ rPH.Special( GetLen(), aExpand, GetWhichPor() );
+}
+
+/*************************************************************************
+ * virtual SwFldPortion::GetTxtSize()
+ *************************************************************************/
+
+SwPosSize SwFldPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
+{
+ SwFontSave aSave( rInf, pFnt );
+ SwPosSize aSize( SwExpandPortion::GetTxtSize( rInf ) );
+ return aSize;
+}
+
+/*************************************************************************
+ * class SwHiddenPortion
+ *************************************************************************/
+
+SwFldPortion *SwHiddenPortion::Clone(const XubString &rExpand ) const
+{
+ SwFont *pNewFnt;
+ if( 0 != ( pNewFnt = pFnt ) )
+ pNewFnt = new SwFont( *pFnt );
+ return new SwHiddenPortion( rExpand, pNewFnt );
+}
+
+/*************************************************************************
+ * virtual SwHiddenPortion::Paint()
+ *************************************************************************/
+
+void SwHiddenPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( Width() )
+ {
+ SwFontSave aSave( rInf, pFnt );
+ rInf.DrawViewOpt( *this, POR_HIDDEN );
+ SwExpandPortion::Paint( rInf );
+ }
+}
+
+/*************************************************************************
+ * virtual SwHiddenPortion::GetExpTxt()
+ *************************************************************************/
+
+sal_Bool SwHiddenPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const
+{
+ // Nicht auf IsHidden() abfragen !
+ return SwFldPortion::GetExpTxt( rInf, rTxt );
+}
+
+/*************************************************************************
+ * class SwNumberPortion
+ *************************************************************************/
+
+// --> OD 2008-01-23 #newlistlevelattrs#
+SwNumberPortion::SwNumberPortion( const XubString &rExpand,
+ SwFont *pFont,
+ const sal_Bool bLft,
+ const sal_Bool bCntr,
+ const KSHORT nMinDst,
+ const bool bLabelAlignmentPosAndSpaceModeActive )
+ : SwFldPortion( rExpand, pFont ),
+ nFixWidth(0),
+ nMinDist( nMinDst ),
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ mbLabelAlignmentPosAndSpaceModeActive( bLabelAlignmentPosAndSpaceModeActive )
+ // <--
+{
+ SetWhichPor( POR_NUMBER );
+ SetLeft( bLft );
+ SetHide( sal_False );
+ SetCenter( bCntr );
+}
+
+xub_StrLen SwNumberPortion::GetCrsrOfst( const MSHORT ) const
+{
+ return 0;
+}
+
+SwFldPortion *SwNumberPortion::Clone( const XubString &rExpand ) const
+{
+ SwFont *pNewFnt;
+ if( 0 != ( pNewFnt = pFnt ) )
+ pNewFnt = new SwFont( *pFnt );
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ return new SwNumberPortion( rExpand, pNewFnt, IsLeft(), IsCenter(),
+ nMinDist, mbLabelAlignmentPosAndSpaceModeActive );
+ // <--
+}
+
+/*************************************************************************
+ * virtual SwNumberPortion::Format()
+ *************************************************************************/
+
+// 5010: Wir sind in der Lage, mehrzeilige NumFelder anzulegen!
+// 3689: Fies ist, wenn man in der Dialogbox soviel Davor-Text
+// eingibt, bis die Zeile ueberlaeuft.
+// Man muss die Fly-Ausweichmanoever beachten!
+
+sal_Bool SwNumberPortion::Format( SwTxtFormatInfo &rInf )
+{
+ SetHide( sal_False );
+ const sal_Bool bFull = SwFldPortion::Format( rInf );
+ SetLen( 0 );
+ // a numbering portion can be contained in a rotated portion!!!
+ nFixWidth = rInf.IsMulti() ? Height() : Width();
+ rInf.SetNumDone( !rInf.GetRest() );
+ if( rInf.IsNumDone() )
+ {
+// SetAscent( rInf.GetAscent() );
+ ASSERT( Height() && nAscent, "NumberPortions without Height | Ascent" );
+
+ long nDiff( 0 );
+ // --> OD 2008-01-23 #newlistlevelattrs#
+ if ( !mbLabelAlignmentPosAndSpaceModeActive )
+ {
+ if ( !rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) &&
+ // --> FME 2004-08-13 #i32902#
+ !IsFtnNumPortion() )
+ // <--
+ {
+ nDiff = rInf.Left()
+ + rInf.GetTxtFrm()->GetTxtNode()->
+ GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst()
+ - rInf.First()
+ + rInf.ForcedLeftMargin();
+ }
+ else
+ {
+ nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
+ }
+ }
+ // <--
+ // Ein Vorschlag von Juergen und Volkmar:
+ // Der Textteil hinter der Numerierung sollte immer
+ // mindestens beim linken Rand beginnen.
+ if( nDiff < 0 )
+ nDiff = 0;
+ else if ( nDiff > rInf.X() )
+ nDiff -= rInf.X();
+ else
+ nDiff = 0;
+
+ if( nDiff < nFixWidth + nMinDist )
+ nDiff = nFixWidth + nMinDist;
+ // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde
+ // fieser Sonderfall: FlyFrm liegt in dem Bereich,
+ // den wir uns gerade unter den Nagel reissen wollen.
+ // Die NumberPortion wird als verborgen markiert.
+ const sal_Bool bFly = rInf.GetFly() ||
+ ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() );
+ if( nDiff > rInf.Width() )
+ {
+ nDiff = rInf.Width();
+ if ( bFly )
+ SetHide( sal_True );
+ }
+
+ // A numbering portion can be inside a SwRotatedPortion. Then the
+ // Height has to be changed
+ if ( rInf.IsMulti() )
+ {
+ if ( Height() < nDiff )
+ Height( KSHORT( nDiff ) );
+ }
+ else if( Width() < nDiff )
+ Width( KSHORT(nDiff) );
+ }
+ return bFull;
+}
+
+void SwNumberPortion::FormatEOL( SwTxtFormatInfo& )
+{
+/* Ein FormatEOL deutet daraufhin, dass der folgende Text
+ * nicht mit auf die Zeile passte. Damit die Numerierung mitwandert,
+ * wird diese NumberPortion verborgen.
+ */
+
+ // This caused trouble with flys anchored as characters.
+ // If one of these is numbered but does not fit to the line,
+ // it calls this function, causing a loop because both the number
+ // portion and the fly portion go to the next line
+// SetHide( sal_True );
+}
+
+/*************************************************************************
+ * virtual SwNumberPortion::Paint()
+ *************************************************************************/
+
+void SwNumberPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+/* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt
+ * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile.
+ */
+
+ if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() )
+ {
+ SwLinePortion *pTmp = GetPortion();
+ while ( pTmp && !pTmp->InTxtGrp() )
+ pTmp = pTmp->GetPortion();
+ if ( !pTmp )
+ return;
+ }
+
+ // calculate the width of the number portion, including follows
+ const KSHORT nOldWidth = Width();
+ sal_uInt16 nSumWidth = 0;
+ sal_uInt16 nOffset = 0;
+
+ const SwLinePortion* pTmp = this;
+ while ( pTmp && pTmp->InNumberGrp() )
+ {
+ nSumWidth = nSumWidth + pTmp->Width();
+ if ( ((SwNumberPortion*)pTmp)->HasFollow() )
+ pTmp = pTmp->GetPortion();
+ else
+ {
+ nOffset = pTmp->Width() - ((SwNumberPortion*)pTmp)->nFixWidth;
+ break;
+ }
+ }
+
+ // The master portion takes care for painting the background of the
+ // follow field portions
+ if ( ! IsFollow() )
+ {
+ SwLinePortion *pThis = (SwLinePortion*)this;
+ pThis->Width( nSumWidth );
+ rInf.DrawViewOpt( *this, POR_NUMBER );
+ pThis->Width( nOldWidth );
+ }
+
+ if( aExpand.Len() )
+ {
+ const SwFont *pTmpFnt = rInf.GetFont();
+ sal_Bool bPaintSpace = ( UNDERLINE_NONE != pTmpFnt->GetUnderline() ||
+ UNDERLINE_NONE != pTmpFnt->GetOverline() ||
+ STRIKEOUT_NONE != pTmpFnt->GetStrikeout() ) &&
+ !pTmpFnt->IsWordLineMode();
+ if( bPaintSpace && pFnt )
+ bPaintSpace = ( UNDERLINE_NONE != pFnt->GetUnderline() ||
+ UNDERLINE_NONE != pFnt->GetOverline() ||
+ STRIKEOUT_NONE != pFnt->GetStrikeout() ) &&
+ !pFnt->IsWordLineMode();
+
+ SwFontSave aSave( rInf, pFnt );
+
+ if( nFixWidth == Width() && ! HasFollow() )
+ SwExpandPortion::Paint( rInf );
+ else
+ {
+ // logisches const: Width wird wieder zurueckgesetzt
+ SwLinePortion *pThis = (SwLinePortion*)this;
+ bPaintSpace = bPaintSpace && nFixWidth < nOldWidth;
+ KSHORT nSpaceOffs = nFixWidth;
+ pThis->Width( nFixWidth );
+
+ if( ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) ||
+ ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() ) )
+ SwExpandPortion::Paint( rInf );
+ else
+ {
+ SwTxtPaintInfo aInf( rInf );
+ if( nOffset < nMinDist )
+ nOffset = 0;
+ else
+ {
+ if( IsCenter() )
+ {
+ /* #110778# a / 2 * 2 == a is not a tautology */
+ KSHORT nTmpOffset = nOffset;
+ nOffset /= 2;
+ if( nOffset < nMinDist )
+ nOffset = nTmpOffset - nMinDist;
+ }
+ else
+ nOffset = nOffset - nMinDist;
+ }
+ aInf.X( aInf.X() + nOffset );
+ SwExpandPortion::Paint( aInf );
+ if( bPaintSpace )
+ nSpaceOffs = nSpaceOffs + nOffset;
+ }
+ if( bPaintSpace && nOldWidth > nSpaceOffs )
+ {
+ SwTxtPaintInfo aInf( rInf );
+static sal_Char __READONLY_DATA sDoubleSpace[] = " ";
+ aInf.X( aInf.X() + nSpaceOffs );
+
+ // --> FME 2005-08-12 #i53199# Adjust position of underline:
+ if ( rInf.GetUnderFnt() )
+ {
+ const Point aNewPos( aInf.GetPos().X(), rInf.GetUnderFnt()->GetPos().Y() );
+ rInf.GetUnderFnt()->SetPos( aNewPos );
+ }
+ // <--
+
+ pThis->Width( nOldWidth - nSpaceOffs + 12 );
+ {
+ SwTxtSlot aDiffTxt( &aInf, this, true, false, sDoubleSpace );
+ aInf.DrawText( *this, aInf.GetLen(), sal_True );
+ }
+ }
+ pThis->Width( nOldWidth );
+ }
+ }
+}
+
+
+/*************************************************************************
+ * class SwBulletPortion
+ *************************************************************************/
+
+// --> OD 2008-01-23 #newlistlevelattrs#
+SwBulletPortion::SwBulletPortion( const xub_Unicode cBullet,
+ const XubString& rBulletFollowedBy,
+ SwFont *pFont,
+ const sal_Bool bLft,
+ const sal_Bool bCntr,
+ const KSHORT nMinDst,
+ const bool bLabelAlignmentPosAndSpaceModeActive )
+ : SwNumberPortion( XubString( rBulletFollowedBy ).Insert( cBullet, 0 ) ,
+ pFont, bLft, bCntr, nMinDst,
+ bLabelAlignmentPosAndSpaceModeActive )
+// <--
+{
+ SetWhichPor( POR_BULLET );
+}
+
+/*************************************************************************
+ * class SwGrfNumPortion
+ *************************************************************************/
+
+#define GRFNUM_SECURE 10
+
+// --> OD 2008-01-23 #newlistlevelattrs#
+SwGrfNumPortion::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 ) :
+ SwNumberPortion( rGraphicFollowedBy, NULL, bLft, bCntr, nMinDst,
+ bLabelAlignmentPosAndSpaceModeActive ),
+// <--
+ pBrush( new SvxBrushItem(RES_BACKGROUND) ), nId( 0 )
+{
+ SetWhichPor( POR_GRFNUM );
+ SetAnimated( sal_False );
+ bReplace = sal_False;
+ if( pGrfBrush )
+ {
+ *pBrush = *pGrfBrush;
+ const Graphic* pGraph = pGrfBrush->GetGraphic();
+ if( pGraph )
+ SetAnimated( pGraph->IsAnimated() );
+ else
+ bReplace = sal_True;
+ }
+ if( pGrfOrient )
+ {
+ nYPos = pGrfOrient->GetPos();
+ eOrient = pGrfOrient->GetVertOrient();
+ }
+ else
+ {
+ nYPos = 0;
+ eOrient = text::VertOrientation::TOP;
+ }
+ Width( static_cast<sal_uInt16>(rGrfSize.Width() + 2 * GRFNUM_SECURE) );
+ nFixWidth = Width();
+ nGrfHeight = rGrfSize.Height() + 2 * GRFNUM_SECURE;
+ Height( KSHORT(nGrfHeight) );
+ bNoPaint = sal_False;
+}
+
+SwGrfNumPortion::~SwGrfNumPortion()
+{
+ if ( IsAnimated() )
+ ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId );
+ delete pBrush;
+}
+
+void SwGrfNumPortion::StopAnimation( OutputDevice* pOut )
+{
+ if ( IsAnimated() )
+ ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( pOut, nId );
+}
+
+sal_Bool SwGrfNumPortion::Format( SwTxtFormatInfo &rInf )
+{
+ SetHide( sal_False );
+ // --> OD 2008-01-29 #newlistlevelattrs#
+// Width( nFixWidth );
+ KSHORT nFollowedByWidth( 0 );
+ if ( mbLabelAlignmentPosAndSpaceModeActive )
+ {
+ SwFldPortion::Format( rInf );
+ nFollowedByWidth = Width();
+ SetLen( 0 );
+ }
+ Width( nFixWidth + nFollowedByWidth );
+ // <--
+ const sal_Bool bFull = rInf.Width() < rInf.X() + Width();
+ const sal_Bool bFly = rInf.GetFly() ||
+ ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() );
+ SetAscent( static_cast<sal_uInt16>(GetRelPos() > 0 ? GetRelPos() : 0) );
+ if( GetAscent() > Height() )
+ Height( GetAscent() );
+
+ if( bFull )
+ {
+ Width( rInf.Width() - (KSHORT)rInf.X() );
+ if( bFly )
+ {
+ SetLen( 0 );
+ SetNoPaint( sal_True );
+ rInf.SetNumDone( sal_False );
+ return sal_True;
+ }
+ }
+ rInf.SetNumDone( sal_True );
+ // --> OD 2008-01-23 #newlistlevelattrs#
+// long nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
+ long nDiff = mbLabelAlignmentPosAndSpaceModeActive
+ ? 0
+ : rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
+ // <--
+ // Ein Vorschlag von Juergen und Volkmar:
+ // Der Textteil hinter der Numerierung sollte immer
+ // mindestens beim linken Rand beginnen.
+ if( nDiff < 0 )
+ nDiff = 0;
+ else if ( nDiff > rInf.X() )
+ nDiff -= rInf.X();
+ if( nDiff < nFixWidth + nMinDist )
+ nDiff = nFixWidth + nMinDist;
+ // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde
+ // fieser Sonderfall: FlyFrm liegt in dem Bereich,
+ // den wir uns gerade unter den Nagel reissen wollen.
+ // Die NumberPortion wird als verborgen markiert.
+ if( nDiff > rInf.Width() )
+ {
+ nDiff = rInf.Width();
+ if( bFly )
+ SetHide( sal_True );
+ }
+
+ if( Width() < nDiff )
+ Width( KSHORT(nDiff) );
+ return bFull;
+}
+
+void SwGrfNumPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ if( DontPaint() )
+ return;
+/* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt
+ * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile.
+ */
+ if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() )
+ {
+ SwLinePortion *pTmp = GetPortion();
+ while ( pTmp && !pTmp->InTxtGrp() )
+ pTmp = pTmp->GetPortion();
+ if ( !pTmp )
+ return;
+ }
+ Point aPos( rInf.X() + GRFNUM_SECURE, rInf.Y() - GetRelPos() + GRFNUM_SECURE );
+ long nTmpWidth = Max( (long)0, (long)(nFixWidth - 2 * GRFNUM_SECURE) );
+ Size aSize( nTmpWidth, GetGrfHeight() - 2 * GRFNUM_SECURE );
+
+ // --> OD 2008-02-05 #newlistlevelattrs#
+ const sal_Bool bTmpLeft = mbLabelAlignmentPosAndSpaceModeActive ||
+ ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) ||
+ ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() );
+ // <--
+
+ if( nFixWidth < Width() && !bTmpLeft )
+ {
+ KSHORT nOffset = Width() - nFixWidth;
+ if( nOffset < nMinDist )
+ nOffset = 0;
+ else
+ {
+ if( IsCenter() )
+ {
+ nOffset /= 2;
+ if( nOffset < nMinDist )
+ nOffset = Width() - nFixWidth - nMinDist;
+ }
+ else
+ nOffset = nOffset - nMinDist;
+ }
+ aPos.X() += nOffset;
+ }
+
+ if( bReplace )
+ {
+ KSHORT nTmpH = GetPortion() ? GetPortion()->GetAscent() : 120;
+ aSize = Size( nTmpH, nTmpH );
+ aPos.Y() = rInf.Y() - nTmpH;
+ }
+ SwRect aTmp( aPos, aSize );
+
+ sal_Bool bDraw = sal_True;
+
+ if ( IsAnimated() )
+ {
+ bDraw = !rInf.GetOpt().IsGraphic();
+ if( !nId )
+ {
+ SetId( long( rInf.GetTxtFrm() ) );
+ rInf.GetTxtFrm()->SetAnimation();
+ }
+ if( aTmp.IsOver( rInf.GetPaintRect() ) && !bDraw )
+ {
+ rInf.NoteAnimation();
+ const ViewShell* pViewShell = rInf.GetVsh();
+
+ // virtual device, not pdf export
+ if( OUTDEV_VIRDEV == rInf.GetOut()->GetOutDevType() &&
+ pViewShell && pViewShell->GetWin() )
+ {
+ ( (Graphic*) pBrush->GetGraphic() )->StopAnimation(0,nId);
+ rInf.GetTxtFrm()->getRootFrm()->GetCurrShell()->InvalidateWindows( aTmp );
+ }
+
+
+ else if ( pViewShell &&
+ !pViewShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() &&
+ !pViewShell->IsPreView() &&
+ // --> FME 2004-06-21 #i9684# Stop animation during printing/pdf export.
+ pViewShell->GetWin() )
+ // <--
+ {
+ ( (Graphic*) pBrush->GetGraphic() )->StartAnimation(
+ (OutputDevice*)rInf.GetOut(), aPos, aSize, nId );
+ }
+
+ // pdf export, printing, preview, stop animations...
+ else
+ bDraw = sal_True;
+ }
+ if( bDraw )
+ ( (Graphic*) pBrush->GetGraphic() )->StopAnimation( 0, nId );
+ }
+
+ SwRect aRepaint( rInf.GetPaintRect() );
+ const SwTxtFrm& rFrm = *rInf.GetTxtFrm();
+ if( rFrm.IsVertical() )
+ {
+ rFrm.SwitchHorizontalToVertical( aTmp );
+ rFrm.SwitchHorizontalToVertical( aRepaint );
+ }
+
+ if( rFrm.IsRightToLeft() )
+ {
+ rFrm.SwitchLTRtoRTL( aTmp );
+ rFrm.SwitchLTRtoRTL( aRepaint );
+ }
+
+ if( bDraw && aTmp.HasArea() )
+ DrawGraphic( pBrush, (OutputDevice*)rInf.GetOut(),
+ aTmp, aRepaint, bReplace ? GRFNUM_REPLACE : GRFNUM_YES );
+}
+
+void SwGrfNumPortion::SetBase( long nLnAscent, long nLnDescent,
+ long nFlyAsc, long nFlyDesc )
+{
+ if ( GetOrient() != text::VertOrientation::NONE )
+ {
+ SetRelPos( 0 );
+ if ( GetOrient() == text::VertOrientation::CENTER )
+ SetRelPos( GetGrfHeight() / 2 );
+ else if ( GetOrient() == text::VertOrientation::TOP )
+ SetRelPos( GetGrfHeight() - GRFNUM_SECURE );
+ else if ( GetOrient() == text::VertOrientation::BOTTOM )
+ ;
+ else if ( GetOrient() == text::VertOrientation::CHAR_CENTER )
+ SetRelPos( ( GetGrfHeight() + nLnAscent - nLnDescent ) / 2 );
+ else if ( GetOrient() == text::VertOrientation::CHAR_TOP )
+ SetRelPos( nLnAscent );
+ else if ( GetOrient() == text::VertOrientation::CHAR_BOTTOM )
+ SetRelPos( GetGrfHeight() - nLnDescent );
+ else
+ {
+ if( GetGrfHeight() >= nFlyAsc + nFlyDesc )
+ {
+ // wenn ich genauso gross bin wie die Zeile, brauche ich mich
+ // nicht an der Zeile nicht weiter ausrichten, ich lasse
+ // dann auch den max. Ascent der Zeile unveraendert
+
+ SetRelPos( nFlyAsc );
+ }
+ else if ( GetOrient() == text::VertOrientation::LINE_CENTER )
+ SetRelPos( ( GetGrfHeight() + nFlyAsc - nFlyDesc ) / 2 );
+ else if ( GetOrient() == text::VertOrientation::LINE_TOP )
+ SetRelPos( nFlyAsc );
+ else if ( GetOrient() == text::VertOrientation::LINE_BOTTOM )
+ SetRelPos( GetGrfHeight() - nFlyDesc );
+ }
+ }
+}
+
+void SwTxtFrm::StopAnimation( OutputDevice* pOut )
+{
+ ASSERT( HasAnimation(), "SwTxtFrm::StopAnimation: Which Animation?" );
+ if( HasPara() )
+ {
+ SwLineLayout *pLine = GetPara();
+ while( pLine )
+ {
+ SwLinePortion *pPor = pLine->GetPortion();
+ while( pPor )
+ {
+ if( pPor->IsGrfNumPortion() )
+ ((SwGrfNumPortion*)pPor)->StopAnimation( pOut );
+ // Die Numerierungsportion sitzt immer vor dem ersten Zeichen,
+ // deshalb koennen wir abbrechen, sobald wir eine Portion mit
+ // einer Laenge > 0 erreicht haben.
+ pPor = pPor->GetLen() ? 0 : pPor->GetPortion();
+ }
+ pLine = pLine->GetLen() ? 0 : pLine->GetNext();
+ }
+ }
+}
+
+/*************************************************************************
+ * SwCombinedPortion::SwCombinedPortion(..)
+ * initializes the script array and clears the width array
+ *************************************************************************/
+
+SwCombinedPortion::SwCombinedPortion( const XubString &rTxt )
+ : SwFldPortion( rTxt )
+{
+ SetLen(1);
+ SetWhichPor( POR_COMBINED );
+ if( aExpand.Len() > 6 )
+ aExpand.Erase( 6 );
+ // Initialization of the scripttype array,
+ // the arrays of width and position are filled by the format function
+ if( pBreakIt->GetBreakIter().is() )
+ {
+ sal_uInt8 nScr = SW_SCRIPTS;
+ for( sal_uInt16 i = 0; i < rTxt.Len(); ++i )
+ {
+ sal_uInt16 nScript = pBreakIt->GetBreakIter()->getScriptType( rTxt, i );
+ switch ( nScript ) {
+ case i18n::ScriptType::LATIN : nScr = SW_LATIN; break;
+ case i18n::ScriptType::ASIAN : nScr = SW_CJK; break;
+ case i18n::ScriptType::COMPLEX : nScr = SW_CTL; break;
+ }
+ aScrType[i] = nScr;
+ }
+ }
+ else
+ {
+ for( sal_uInt16 i = 0; i < 6; aScrType[i++] = 0 )
+ ; // nothing
+ }
+ memset( &aWidth, 0, sizeof(aWidth) );
+}
+
+/*************************************************************************
+ * SwCombinedPortion::Paint(..)
+ *************************************************************************/
+
+void SwCombinedPortion::Paint( const SwTxtPaintInfo &rInf ) const
+{
+ ASSERT( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" );
+ if( Width() )
+ {
+ rInf.DrawBackBrush( *this );
+ rInf.DrawViewOpt( *this, POR_FLD );
+
+ // do we have to repaint a post it portion?
+ if( rInf.OnWin() && pPortion && !pPortion->Width() )
+ pPortion->PrePaint( rInf, this );
+
+ sal_uInt16 nCount = aExpand.Len();
+ if( !nCount )
+ return;
+ ASSERT( nCount < 7, "Too much combined characters" );
+
+ // the first character of the second row
+ sal_uInt16 nTop = ( nCount + 1 ) / 2;
+
+ SwFont aTmpFont( *rInf.GetFont() );
+ aTmpFont.SetProportion( nProportion ); // a smaller font
+ SwFontSave aFontSave( rInf, &aTmpFont );
+
+ sal_uInt16 i = 0;
+ Point aOldPos = rInf.GetPos();
+ Point aOutPos( aOldPos.X(), aOldPos.Y() - nUpPos );// Y of the first row
+ while( i < nCount )
+ {
+ if( i == nTop ) // change the row
+ aOutPos.Y() = aOldPos.Y() + nLowPos; // Y of the second row
+ aOutPos.X() = aOldPos.X() + aPos[i]; // X position
+ const sal_uInt8 nAct = aScrType[i]; // script type
+ aTmpFont.SetActual( nAct );
+ // if there're more than 4 characters to display, we choose fonts
+ // with 2/3 of the original font width.
+ if( aWidth[ nAct ] )
+ {
+ Size aTmpSz = aTmpFont.GetSize( nAct );
+ if( aTmpSz.Width() != aWidth[ nAct ] )
+ {
+ aTmpSz.Width() = aWidth[ nAct ];
+ aTmpFont.SetSize( aTmpSz, nAct );
+ }
+ }
+ ((SwTxtPaintInfo&)rInf).SetPos( aOutPos );
+ rInf.DrawText( aExpand, *this, i, 1 );
+ ++i;
+ }
+ // rInf is const, so we have to take back our manipulations
+ ((SwTxtPaintInfo&)rInf).SetPos( aOldPos );
+ }
+}
+
+/*************************************************************************
+ * SwCombinedPortion::Format(..)
+ *************************************************************************/
+
+sal_Bool SwCombinedPortion::Format( SwTxtFormatInfo &rInf )
+{
+ sal_uInt16 nCount = aExpand.Len();
+ if( !nCount )
+ {
+ Width( 0 );
+ return sal_False;
+ }
+
+ ASSERT( nCount < 7, "Too much combined characters" );
+ // If there are leading "weak"-scripttyped characters in this portion,
+ // they get the actual scripttype.
+ sal_uInt16 i = 0;
+ while( i < nCount && SW_SCRIPTS == aScrType[i] )
+ aScrType[i++] = rInf.GetFont()->GetActual();
+ if( nCount > 4 )
+ {
+ // more than four? Ok, then we need the 2/3 font width
+ i = 0;
+ while( i < aExpand.Len() )
+ {
+ ASSERT( aScrType[i] < SW_SCRIPTS, "Combined: Script fault" );
+ if( !aWidth[ aScrType[i] ] )
+ {
+ rInf.GetOut()->SetFont( rInf.GetFont()->GetFnt( aScrType[i] ) );
+ aWidth[ aScrType[i] ] =
+ static_cast<sal_uInt16>(2 * rInf.GetOut()->GetFontMetric().GetSize().Width() / 3);
+ }
+ ++i;
+ }
+ }
+
+ sal_uInt16 nTop = ( nCount + 1 ) / 2; // the first character of the second line
+ ViewShell *pSh = rInf.GetTxtFrm()->getRootFrm()->GetCurrShell();
+ SwFont aTmpFont( *rInf.GetFont() );
+ SwFontSave aFontSave( rInf, &aTmpFont );
+ nProportion = 55;
+ // In nMainAscent/Descent we store the ascent and descent
+ // of the original surrounding font
+ sal_uInt16 nMaxDescent, nMaxAscent, nMaxWidth;
+ sal_uInt16 nMainDescent = rInf.GetFont()->GetHeight( pSh, *rInf.GetOut() );
+ const sal_uInt16 nMainAscent = rInf.GetFont()->GetAscent( pSh, *rInf.GetOut() );
+ nMainDescent = nMainDescent - nMainAscent;
+ // we start with a 50% font, but if we notice that the combined portion
+ // becomes bigger than the surrounding font, we check 45% and maybe 40%.
+ do
+ {
+ nProportion -= 5;
+ aTmpFont.SetProportion( nProportion );
+ i = 0;
+ memset( &aPos, 0, sizeof(aPos) );
+ nMaxDescent = 0;
+ nMaxAscent = 0;
+ nMaxWidth = 0;
+ nUpPos = nLowPos = 0;
+
+ // Now we get the width of all characters.
+ // The ascent and the width of the first line are stored in the
+ // ascent member of the portion, the descent in nLowPos.
+ // The ascent, descent and width of the second line are stored in the
+ // local nMaxAscent, nMaxDescent and nMaxWidth variables.
+ while( i < nCount )
+ {
+ sal_uInt8 nScrp = aScrType[i];
+ aTmpFont.SetActual( nScrp );
+ if( aWidth[ nScrp ] )
+ {
+ Size aFontSize( aTmpFont.GetSize( nScrp ) );
+ aFontSize.Width() = aWidth[ nScrp ];
+ aTmpFont.SetSize( aFontSize, nScrp );
+ }
+
+ SwDrawTextInfo aDrawInf( pSh, *rInf.GetOut(), 0, aExpand, i, 1 );
+ Size aSize = aTmpFont._GetTxtSize( aDrawInf );
+ sal_uInt16 nAsc = aTmpFont.GetAscent( pSh, *rInf.GetOut() );
+ aPos[ i ] = (sal_uInt16)aSize.Width();
+ if( i == nTop ) // enter the second line
+ {
+ nLowPos = nMaxDescent;
+ Height( nMaxDescent + nMaxAscent );
+ Width( nMaxWidth );
+ SetAscent( nMaxAscent );
+ nMaxAscent = 0;
+ nMaxDescent = 0;
+ nMaxWidth = 0;
+ }
+ nMaxWidth = nMaxWidth + aPos[ i++ ];
+ if( nAsc > nMaxAscent )
+ nMaxAscent = nAsc;
+ if( aSize.Height() - nAsc > nMaxDescent )
+ nMaxDescent = static_cast<sal_uInt16>(aSize.Height() - nAsc);
+ }
+ // for one or two characters we double the width of the portion
+ if( nCount < 3 )
+ {
+ nMaxWidth *= 2;
+ Width( 2*Width() );
+ if( nCount < 2 )
+ {
+ Height( nMaxAscent + nMaxDescent );
+ nLowPos = nMaxDescent;
+ }
+ }
+ Height( Height() + nMaxDescent + nMaxAscent );
+ nUpPos = nMaxAscent;
+ SetAscent( Height() - nMaxDescent - nLowPos );
+ } while( nProportion > 40 && ( GetAscent() > nMainAscent ||
+ Height() - GetAscent() > nMainDescent ) );
+ // if the combined portion is smaller than the surrounding text,
+ // the portion grows. This looks better, if there's a character background.
+ if( GetAscent() < nMainAscent )
+ {
+ Height( Height() + nMainAscent - GetAscent() );
+ SetAscent( nMainAscent );
+ }
+ if( Height() < nMainAscent + nMainDescent )
+ Height( nMainAscent + nMainDescent );
+
+ // We calculate the x positions of the characters in both lines..
+ sal_uInt16 nTopDiff = 0;
+ sal_uInt16 nBotDiff = 0;
+ if( nMaxWidth > Width() )
+ {
+ nTopDiff = ( nMaxWidth - Width() ) / 2;
+ Width( nMaxWidth );
+ }
+ else
+ nBotDiff = ( Width() - nMaxWidth ) / 2;
+ switch( nTop)
+ {
+ case 3: aPos[1] = aPos[0] + nTopDiff; // no break
+ case 2: aPos[nTop-1] = Width() - aPos[nTop-1];
+ }
+ aPos[0] = 0;
+ switch( nCount )
+ {
+ case 5: aPos[4] = aPos[3] + nBotDiff; // no break
+ case 3: aPos[nTop] = nBotDiff; break;
+ case 6: aPos[4] = aPos[3] + nBotDiff; // no break
+ case 4: aPos[nTop] = 0; // no break
+ case 2: aPos[nCount-1] = Width() - aPos[nCount-1];
+ }
+
+ // Does the combined portion fit the line?
+ const sal_Bool bFull = rInf.Width() < rInf.X() + Width();
+ if( bFull )
+ {
+ if( rInf.GetLineStart() == rInf.GetIdx() && (!rInf.GetLast()->InFldGrp()
+ || !((SwFldPortion*)rInf.GetLast())->IsFollow() ) )
+ Width( (sal_uInt16)( rInf.Width() - rInf.X() ) );
+ else
+ {
+ Truncate();
+ Width( 0 );
+ SetLen( 0 );
+ if( rInf.GetLast() )
+ rInf.GetLast()->FormatEOL( rInf );
+ }
+ }
+ return bFull;
+}
+
+/*************************************************************************
+ * SwCombinedPortion::GetViewWidth(..)
+ *************************************************************************/
+
+KSHORT SwCombinedPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
+{
+ if( !GetLen() ) // for the dummy part at the end of the line, where
+ return 0; // the combined portion doesn't fit.
+ return SwFldPortion::GetViewWidth( rInf );
+}