| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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 ); |
| } |
| 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 ); |
| m_nAttrFldType = 0; |
| } |
| |
| 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: |
| case CHAR_ZWSP : |
| case CHAR_ZWNBSP : |
| 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() ); |
| if( GetWhichPor() == POR_FLD ) |
| { |
| rPH.SetAttrFieldType(m_nAttrFldType); |
| } |
| } |
| |
| /************************************************************************* |
| * 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 ); |
| } |