/************************************************************************* * * 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sw.hxx" #include #include #include #include #include #include #include #include #include #include #include #include // --> OD 2008-01-17 #newlistlevelattrs# #ifndef _SVX_TSTPITEM_HXX #include #endif // <-- #include #include #include #include #include #include #include #include #include #include #include // ViewShell #include // SwViewOptions #include // DrawGraphic #include #ifndef IDOCUMENTDEVICEACCESS_HXX_INCLUDED #include #endif #include // SwFmtDrop #include // SwRootFrm #include // SwTxtInfo #include // SwBlink #include // SwNoteURL #include // SwFtnPortion #include // SwHangingPortion #include #include #include #include #include #include #include // --> FME 2004-06-08 #i12836# enhanced pdf export #include // <-- #include using namespace ::com::sun::star; using namespace ::com::sun::star::linguistic2; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::beans; #define CHAR_UNDERSCORE ((sal_Unicode)0x005F) #define CHAR_LEFT_ARROW ((sal_Unicode)0x25C0) #define CHAR_RIGHT_ARROW ((sal_Unicode)0x25B6) #define CHAR_TAB ((sal_Unicode)0x2192) #define CHAR_TAB_RTL ((sal_Unicode)0x2190) #define CHAR_LINEBREAK ((sal_Unicode)0x21B5) #define CHAR_LINEBREAK_RTL ((sal_Unicode)0x21B3) #define DRAW_SPECIAL_OPTIONS_CENTER 1 #define DRAW_SPECIAL_OPTIONS_ROTATE 2 // --> OD 2006-06-27 #b6440955# // variable moved to class //extern const sal_Char __FAR_DATA sBulletFntName[]; namespace numfunc { extern const String& GetDefBulletFontname(); extern bool IsDefBulletFontUserDefined(); } // <-- #ifdef DBG_UTIL // Test2: WYSIWYG++ // Test4: WYSIWYG debug static sal_Bool bDbgLow = sal_False; #endif #ifdef DBG_UTIL sal_Bool SwTxtSizeInfo::IsOptCalm() const { return !GetOpt().IsTest3(); } sal_Bool SwTxtSizeInfo::IsOptLow() const { return bDbgLow; } sal_Bool SwTxtSizeInfo::IsOptDbg() const { return GetOpt().IsTest4(); } sal_Bool SwTxtSizeInfo::IsOptTest1() const { return GetOpt().IsTest1(); } sal_Bool SwTxtSizeInfo::IsOptTest2() const { return GetOpt().IsTest2(); } sal_Bool SwTxtSizeInfo::IsOptTest3() const { return GetOpt().IsTest3(); } sal_Bool SwTxtSizeInfo::IsOptTest4() const { return GetOpt().IsTest4(); } sal_Bool SwTxtSizeInfo::IsOptTest5() const { return GetOpt().IsTest5(); } sal_Bool SwTxtSizeInfo::IsOptTest6() const { return GetOpt().IsTest6(); } sal_Bool SwTxtSizeInfo::IsOptTest7() const { return GetOpt().IsTest7(); } sal_Bool SwTxtSizeInfo::IsOptTest8() const { return GetOpt().IsTest8(); } #endif /************************************************************************* * SwLineInfo::SwLineInfo() *************************************************************************/ // --> OD 2008-01-17 #newlistlevelattrs# SwLineInfo::SwLineInfo() : pRuler( 0 ), pSpace( 0 ), nVertAlign( 0 ), nDefTabStop( 0 ), bListTabStopIncluded( false ), nListTabStopPosition( 0 ) { } SwLineInfo::~SwLineInfo() { delete pRuler; } void SwLineInfo::CtorInitLineInfo( const SwAttrSet& rAttrSet, const SwTxtNode& rTxtNode ) // <-- { // --> OD 2008-01-17 #newlistlevelattrs# // pRuler = &rAttrSet.GetTabStops(); delete pRuler; pRuler = new SvxTabStopItem( rAttrSet.GetTabStops() ); if ( rTxtNode.GetListTabStopPosition( nListTabStopPosition ) ) { bListTabStopIncluded = true; // insert the list tab stop into SvxTabItem instance const SvxTabStop aListTabStop( nListTabStopPosition, SVX_TAB_ADJUST_LEFT ); pRuler->Insert( aListTabStop ); // remove default tab stops, which are before the inserted list tab stop for ( sal_uInt16 i = 0; i < pRuler->Count(); i++ ) { if ( (*pRuler)[i].GetTabPos() < nListTabStopPosition && (*pRuler)[i].GetAdjustment() == SVX_TAB_ADJUST_DEFAULT ) { pRuler->Remove(i); continue; } } } // <-- // --> OD 2008-02-15 #newlistlevelattrs# if ( !rTxtNode.getIDocumentSettingAccess()->get(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT) ) { // remove default tab stop at position 0 for ( sal_uInt16 i = 0; i < pRuler->Count(); i++ ) { if ( (*pRuler)[i].GetTabPos() == 0 && (*pRuler)[i].GetAdjustment() == SVX_TAB_ADJUST_DEFAULT ) { pRuler->Remove(i); break; } } } // <-- pSpace = &rAttrSet.GetLineSpacing(); nVertAlign = rAttrSet.GetParaVertAlign().GetValue(); nDefTabStop = MSHRT_MAX; } /************************************************************************* * SwTxtInfo::CtorInitTxtInfo() *************************************************************************/ void SwTxtInfo::CtorInitTxtInfo( SwTxtFrm *pFrm ) { pPara = pFrm->GetPara(); nTxtStart = pFrm->GetOfst(); if( !pPara ) { ASSERT( pPara, "+SwTxtInfo::CTOR: missing paragraph information" ); pFrm->Format(); pPara = pFrm->GetPara(); } } SwTxtInfo::SwTxtInfo( const SwTxtInfo &rInf ) : pPara( ((SwTxtInfo&)rInf).GetParaPortion() ), nTxtStart( rInf.GetTxtStart() ) { } #ifdef DBG_UTIL /************************************************************************* * ChkOutDev() *************************************************************************/ void ChkOutDev( const SwTxtSizeInfo &rInf ) { if ( !rInf.GetVsh() ) return; const OutputDevice* pOut = rInf.GetOut(); const OutputDevice* pRef = rInf.GetRefDev(); ASSERT( pOut && pRef, "ChkOutDev: invalid output devices" ) } #endif // PRODUCT inline xub_StrLen GetMinLen( const SwTxtSizeInfo &rInf ) { const xub_StrLen nInfLen = rInf.GetIdx() + rInf.GetLen(); return Min( rInf.GetTxt().Len(), nInfLen ); } SwTxtSizeInfo::SwTxtSizeInfo( const SwTxtSizeInfo &rNew ) : SwTxtInfo( rNew ), pKanaComp(((SwTxtSizeInfo&)rNew).GetpKanaComp()), pVsh(((SwTxtSizeInfo&)rNew).GetVsh()), pOut(((SwTxtSizeInfo&)rNew).GetOut()), pRef(((SwTxtSizeInfo&)rNew).GetRefDev()), pFnt(((SwTxtSizeInfo&)rNew).GetFont()), pUnderFnt(((SwTxtSizeInfo&)rNew).GetUnderFnt()), pFrm(rNew.pFrm), pOpt(&rNew.GetOpt()), pTxt(&rNew.GetTxt()), nIdx(rNew.GetIdx()), nLen(rNew.GetLen()), nKanaIdx( rNew.GetKanaIdx() ), bOnWin( rNew.OnWin() ), bNotEOL( rNew.NotEOL() ), bURLNotify( rNew.URLNotify() ), bStopUnderFlow( rNew.StopUnderFlow() ), bFtnInside( rNew.IsFtnInside() ), bOtherThanFtnInside( rNew.IsOtherThanFtnInside() ), bMulti( rNew.IsMulti() ), bFirstMulti( rNew.IsFirstMulti() ), bRuby( rNew.IsRuby() ), bHanging( rNew.IsHanging() ), bScriptSpace( rNew.HasScriptSpace() ), bForbiddenChars( rNew.HasForbiddenChars() ), bSnapToGrid( rNew.SnapToGrid() ), nDirection( rNew.GetDirection() ) { #ifdef DBG_UTIL ChkOutDev( *this ); #endif } void SwTxtSizeInfo::CtorInitTxtSizeInfo( SwTxtFrm *pFrame, SwFont *pNewFnt, const xub_StrLen nNewIdx, const xub_StrLen nNewLen ) { pKanaComp = NULL; nKanaIdx = 0; pFrm = pFrame; CtorInitTxtInfo( pFrm ); const SwTxtNode *pNd = pFrm->GetTxtNode(); pVsh = pFrm->GetShell(); // Get the output and reference device if ( pVsh ) { pOut = pVsh->GetOut(); pRef = &pVsh->GetRefDev(); bOnWin = pVsh->GetWin() || OUTDEV_WINDOW == pOut->GetOutDevType(); } else { //Zugriff ueber StarONE, es muss keine Shell existieren oder aktiv sein. if ( pNd->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) ) { //in Ermangelung eines Besseren kann hier ja wohl nur noch das //AppWin genommen werden? pOut = GetpApp()->GetDefaultDevice(); } else pOut = pNd->getIDocumentDeviceAccess()->getPrinter( false ); pRef = pOut; } #ifdef DBG_UTIL ChkOutDev( *this ); #endif // Set default layout mode ( LTR or RTL ). if ( pFrm->IsRightToLeft() ) { pOut->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL ); pRef->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL ); nDirection = DIR_RIGHT2LEFT; } else { pOut->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG ); pRef->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG ); nDirection = DIR_LEFT2RIGHT; } /* LanguageType eLang; const SvtCTLOptions& rCTLOptions = SW_MOD()->GetCTLOptions(); if ( SvtCTLOptions::NUMERALS_HINDI == rCTLOptions.GetCTLTextNumerals() ) eLang = LANGUAGE_ARABIC_SAUDI_ARABIA; else if ( SvtCTLOptions::NUMERALS_ARABIC == rCTLOptions.GetCTLTextNumerals() ) eLang = LANGUAGE_ENGLISH; else eLang = (LanguageType)::GetAppLanguage(); pOut->SetDigitLanguage( eLang ); pRef->SetDigitLanguage( eLang );*/ // // The Options // pOpt = pVsh ? pVsh->GetViewOptions() : SW_MOD()->GetViewOption( pNd->getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE) ); //Options vom Module wg. StarONE // bURLNotify wird gesetzt, wenn MakeGraphic dies vorbereitet // TODO: Aufdr?seln bURLNotify = pNoteURL && !bOnWin; SetSnapToGrid( pNd->GetSwAttrSet().GetParaGrid().GetValue() && pFrm->IsInDocBody() ); pFnt = pNewFnt; pUnderFnt = 0; pTxt = &pNd->GetTxt(); nIdx = nNewIdx; nLen = nNewLen; bNotEOL = sal_False; bStopUnderFlow = bFtnInside = bOtherThanFtnInside = sal_False; bMulti = bFirstMulti = bRuby = bHanging = bScriptSpace = bForbiddenChars = sal_False; SetLen( GetMinLen( *this ) ); } SwTxtSizeInfo::SwTxtSizeInfo( const SwTxtSizeInfo &rNew, const XubString &rTxt, const xub_StrLen nIndex, const xub_StrLen nLength ) : SwTxtInfo( rNew ), pKanaComp(((SwTxtSizeInfo&)rNew).GetpKanaComp()), pVsh(((SwTxtSizeInfo&)rNew).GetVsh()), pOut(((SwTxtSizeInfo&)rNew).GetOut()), pRef(((SwTxtSizeInfo&)rNew).GetRefDev()), pFnt(((SwTxtSizeInfo&)rNew).GetFont()), pUnderFnt(((SwTxtSizeInfo&)rNew).GetUnderFnt()), pFrm( rNew.pFrm ), pOpt(&rNew.GetOpt()), pTxt(&rTxt), nIdx(nIndex), nLen(nLength), nKanaIdx( rNew.GetKanaIdx() ), bOnWin( rNew.OnWin() ), bNotEOL( rNew.NotEOL() ), bURLNotify( rNew.URLNotify() ), bStopUnderFlow( rNew.StopUnderFlow() ), bFtnInside( rNew.IsFtnInside() ), bOtherThanFtnInside( rNew.IsOtherThanFtnInside() ), bMulti( rNew.IsMulti() ), bFirstMulti( rNew.IsFirstMulti() ), bRuby( rNew.IsRuby() ), bHanging( rNew.IsHanging() ), bScriptSpace( rNew.HasScriptSpace() ), bForbiddenChars( rNew.HasForbiddenChars() ), bSnapToGrid( rNew.SnapToGrid() ), nDirection( rNew.GetDirection() ) { #ifdef DBG_UTIL ChkOutDev( *this ); #endif SetLen( GetMinLen( *this ) ); } /************************************************************************* * SwTxtSizeInfo::SelectFont() *************************************************************************/ void SwTxtSizeInfo::SelectFont() { // 8731: Der Weg muss ueber ChgPhysFnt gehen, sonst geraet // der FontMetricCache durcheinander. In diesem Fall steht pLastMet // auf dem alten Wert. // Falsch: GetOut()->SetFont( GetFont()->GetFnt() ); GetFont()->Invalidate(); GetFont()->ChgPhysFnt( pVsh, *GetOut() ); } /************************************************************************* * SwTxtSizeInfo::NoteAnimation() *************************************************************************/ void SwTxtSizeInfo::NoteAnimation() const { if( OnWin() ) SwRootFrm::FlushVout(); ASSERT( pOut == pVsh->GetOut(), "SwTxtSizeInfo::NoteAnimation() changed pOut" ) } /************************************************************************* * SwTxtSizeInfo::GetTxtSize() *************************************************************************/ SwPosSize SwTxtSizeInfo::GetTxtSize( OutputDevice* pOutDev, const SwScriptInfo* pSI, const XubString& rTxt, const xub_StrLen nIndex, const xub_StrLen nLength, const sal_uInt16 nComp ) const { SwDrawTextInfo aDrawInf( pVsh, *pOutDev, pSI, rTxt, nIndex, nLength ); aDrawInf.SetFrm( pFrm ); aDrawInf.SetFont( pFnt ); aDrawInf.SetSnapToGrid( SnapToGrid() ); aDrawInf.SetKanaComp( nComp ); SwPosSize aSize = pFnt->_GetTxtSize( aDrawInf ); return aSize; } /************************************************************************* * SwTxtSizeInfo::GetTxtSize() *************************************************************************/ SwPosSize SwTxtSizeInfo::GetTxtSize() const { const SwScriptInfo& rSI = ( (SwParaPortion*)GetParaPortion() )->GetScriptInfo(); // in some cases, compression is not allowed or surpressed for // performance reasons sal_uInt16 nComp =( SW_CJK == GetFont()->GetActual() && rSI.CountCompChg() && ! IsMulti() ) ? GetKanaComp() : 0 ; SwDrawTextInfo aDrawInf( pVsh, *pOut, &rSI, *pTxt, nIdx, nLen ); aDrawInf.SetFrm( pFrm ); aDrawInf.SetFont( pFnt ); aDrawInf.SetSnapToGrid( SnapToGrid() ); aDrawInf.SetKanaComp( nComp ); return pFnt->_GetTxtSize( aDrawInf ); } /************************************************************************* * SwTxtSizeInfo::GetTxtSize() *************************************************************************/ void SwTxtSizeInfo::GetTxtSize( const SwScriptInfo* pSI, const xub_StrLen nIndex, const xub_StrLen nLength, const sal_uInt16 nComp, sal_uInt16& nMinSize, sal_uInt16& nMaxSizeDiff ) const { SwDrawTextInfo aDrawInf( pVsh, *pOut, pSI, *pTxt, nIndex, nLength ); aDrawInf.SetFrm( pFrm ); aDrawInf.SetFont( pFnt ); aDrawInf.SetSnapToGrid( SnapToGrid() ); aDrawInf.SetKanaComp( nComp ); SwPosSize aSize = pFnt->_GetTxtSize( aDrawInf ); nMaxSizeDiff = (sal_uInt16)aDrawInf.GetKanaDiff(); nMinSize = aSize.Width(); } /************************************************************************* * SwTxtSizeInfo::GetTxtBreak() *************************************************************************/ xub_StrLen SwTxtSizeInfo::GetTxtBreak( const long nLineWidth, const xub_StrLen nMaxLen, const sal_uInt16 nComp ) const { const SwScriptInfo& rScriptInfo = ( (SwParaPortion*)GetParaPortion() )->GetScriptInfo(); ASSERT( pRef == pOut, "GetTxtBreak is supposed to use the RefDev" ) SwDrawTextInfo aDrawInf( pVsh, *pOut, &rScriptInfo, *pTxt, GetIdx(), nMaxLen ); aDrawInf.SetFrm( pFrm ); aDrawInf.SetFont( pFnt ); aDrawInf.SetSnapToGrid( SnapToGrid() ); aDrawInf.SetKanaComp( nComp ); aDrawInf.SetHyphPos( 0 ); return pFnt->GetTxtBreak( aDrawInf, nLineWidth ); } /************************************************************************* * SwTxtSizeInfo::GetTxtBreak() *************************************************************************/ xub_StrLen SwTxtSizeInfo::GetTxtBreak( const long nLineWidth, const xub_StrLen nMaxLen, const sal_uInt16 nComp, xub_StrLen& rExtraCharPos ) const { const SwScriptInfo& rScriptInfo = ( (SwParaPortion*)GetParaPortion() )->GetScriptInfo(); ASSERT( pRef == pOut, "GetTxtBreak is supposed to use the RefDev" ) SwDrawTextInfo aDrawInf( pVsh, *pOut, &rScriptInfo, *pTxt, GetIdx(), nMaxLen ); aDrawInf.SetFrm( pFrm ); aDrawInf.SetFont( pFnt ); aDrawInf.SetSnapToGrid( SnapToGrid() ); aDrawInf.SetKanaComp( nComp ); aDrawInf.SetHyphPos( &rExtraCharPos ); return pFnt->GetTxtBreak( aDrawInf, nLineWidth ); } /************************************************************************* * SwTxtPaintInfo::CtorInitTxtPaintInfo() *************************************************************************/ void SwTxtPaintInfo::CtorInitTxtPaintInfo( SwTxtFrm *pFrame, const SwRect &rPaint ) { CtorInitTxtSizeInfo( pFrame ); aTxtFly.CtorInitTxtFly( pFrame ), aPaintRect = rPaint; nSpaceIdx = 0; pSpaceAdd = NULL; pWrongList = NULL; pGrammarCheckList = NULL; pSmartTags = NULL; // SMARTTAGS #ifndef DBG_UTIL pBrushItem = 0; #else pBrushItem = ((SvxBrushItem*)-1); #endif } SwTxtPaintInfo::SwTxtPaintInfo( const SwTxtPaintInfo &rInf, const XubString &rTxt ) : SwTxtSizeInfo( rInf, rTxt ), pWrongList( rInf.GetpWrongList() ), pGrammarCheckList( rInf.GetGrammarCheckList() ), pSmartTags( rInf.GetSmartTags() ), // SMARTTAGS pSpaceAdd( rInf.GetpSpaceAdd() ), pBrushItem( rInf.GetBrushItem() ), aTxtFly( *rInf.GetTxtFly() ), aPos( rInf.GetPos() ), aPaintRect( rInf.GetPaintRect() ), nSpaceIdx( rInf.GetSpaceIdx() ) { } SwTxtPaintInfo::SwTxtPaintInfo( const SwTxtPaintInfo &rInf ) : SwTxtSizeInfo( rInf ), pWrongList( rInf.GetpWrongList() ), pGrammarCheckList( rInf.GetGrammarCheckList() ), pSmartTags( rInf.GetSmartTags() ), // SMARTTAGS pSpaceAdd( rInf.GetpSpaceAdd() ), pBrushItem( rInf.GetBrushItem() ), aTxtFly( *rInf.GetTxtFly() ), aPos( rInf.GetPos() ), aPaintRect( rInf.GetPaintRect() ), nSpaceIdx( rInf.GetSpaceIdx() ) { } extern Color aGlobalRetoucheColor; /************************************************************************* * lcl_IsDarkBackground * * Returns if the current background color is dark. *************************************************************************/ sal_Bool lcl_IsDarkBackground( const SwTxtPaintInfo& rInf ) { const Color* pCol = rInf.GetFont()->GetBackColor(); if( ! pCol || COL_TRANSPARENT == pCol->GetColor() ) { const SvxBrushItem* pItem; SwRect aOrigBackRect; /// OD 21.08.2002 /// consider, that [GetBackgroundBrush(...)] can set /// - see implementation in /core/layout/paintfrm.cxx /// OD 21.08.2002 #99657# /// There is a background color, if there is a background brush and /// its color is *not* "no fill"/"auto fill". if( rInf.GetTxtFrm()->GetBackgroundBrush( pItem, pCol, aOrigBackRect, sal_False ) ) { if ( !pCol ) pCol = &pItem->GetColor(); /// OD 30.08.2002 #99657# /// determined color can be . Thus, check it. if ( pCol->GetColor() == COL_TRANSPARENT) pCol = NULL; } else pCol = NULL; } if( !pCol ) pCol = &aGlobalRetoucheColor; return pCol->IsDark(); } /************************************************************************* * SwTxtPaintInfo::_DrawText() *************************************************************************/ void SwTxtPaintInfo::_DrawText( const XubString &rText, const SwLinePortion &rPor, const xub_StrLen nStart, const xub_StrLen nLength, const sal_Bool bKern, const sal_Bool bWrong, const sal_Bool bSmartTag, const sal_Bool bGrammarCheck ) // SMARTTAGS { if( !nLength ) return; if( GetFont()->IsBlink() && OnWin() && rPor.Width() ) { // check if accessibility options allow blinking portions: const ViewShell* pSh = GetTxtFrm()->GetShell(); if ( pSh && ! pSh->GetAccessibilityOptions()->IsStopAnimatedText() && ! pSh->IsPreView() ) { if( !pBlink ) pBlink = new SwBlink(); Point aPoint( aPos ); if ( GetTxtFrm()->IsRightToLeft() ) GetTxtFrm()->SwitchLTRtoRTL( aPoint ); if ( TEXT_LAYOUT_BIDI_STRONG != GetOut()->GetLayoutMode() ) aPoint.X() -= rPor.Width(); if ( GetTxtFrm()->IsVertical() ) GetTxtFrm()->SwitchHorizontalToVertical( aPoint ); pBlink->Insert( aPoint, &rPor, GetTxtFrm(), pFnt->GetOrientation() ); if( !pBlink->IsVisible() ) return; } else { delete pBlink; pBlink = NULL; } } // The SwScriptInfo is useless if we are inside a field portion SwScriptInfo* pSI = 0; if ( ! rPor.InFldGrp() ) pSI = &GetParaPortion()->GetScriptInfo(); // in some cases, kana compression is not allowed or surpressed for // performance reasons sal_uInt16 nComp = 0; if ( ! IsMulti() ) nComp = GetKanaComp(); sal_Bool bCfgIsAutoGrammar = sal_False; SvtLinguConfig().GetProperty( C2U( UPN_IS_GRAMMAR_AUTO ) ) >>= bCfgIsAutoGrammar; const sal_Bool bBullet = OnWin() && GetOpt().IsBlank() && IsNoSymbol(); const sal_Bool bTmpWrong = bWrong && OnWin() && GetOpt().IsOnlineSpell(); const sal_Bool bTmpGrammarCheck = bGrammarCheck && OnWin() && bCfgIsAutoGrammar && GetOpt().IsOnlineSpell(); const sal_Bool bTmpSmart = bSmartTag && OnWin() && !GetOpt().IsPagePreview() && SwSmartTagMgr::Get().IsSmartTagsEnabled(); // SMARTTAGS ASSERT( GetParaPortion(), "No paragraph!"); SwDrawTextInfo aDrawInf( pFrm->GetShell(), *pOut, pSI, rText, nStart, nLength, rPor.Width(), bBullet ); aDrawInf.SetLeft( GetPaintRect().Left() ); aDrawInf.SetRight( GetPaintRect().Right() ); aDrawInf.SetUnderFnt( pUnderFnt ); const long nSpaceAdd = ( rPor.IsBlankPortion() || rPor.IsDropPortion() || rPor.InNumberGrp() ) ? 0 : GetSpaceAdd(); if ( nSpaceAdd ) { xub_StrLen nCharCnt; // --> FME 2005-04-04 #i41860# Thai justified alignemt needs some // additional information: aDrawInf.SetNumberOfBlanks( rPor.InTxtGrp() ? static_cast(rPor).GetSpaceCnt( *this, nCharCnt ) : 0 ); // <-- } aDrawInf.SetSpace( nSpaceAdd ); aDrawInf.SetKanaComp( nComp ); // the font is used to identify the current script via nActual aDrawInf.SetFont( pFnt ); // the frame is used to identify the orientation aDrawInf.SetFrm( GetTxtFrm() ); // we have to know if the paragraph should snap to grid aDrawInf.SetSnapToGrid( SnapToGrid() ); // for underlining we must know when not to add extra space behind // a character in justified mode aDrawInf.SetSpaceStop( ! rPor.GetPortion() || rPor.GetPortion()->InFixMargGrp() || rPor.GetPortion()->IsHolePortion() ); if( GetTxtFly()->IsOn() ) { // aPos muss als TopLeft vorliegen, weil die ClipRects sonst // nicht berechnet werden koennen. const Point aPoint( aPos.X(), aPos.Y() - rPor.GetAscent() ); const Size aSize( rPor.Width(), rPor.Height() ); aDrawInf.SetPos( aPoint ); aDrawInf.SetSize( aSize ); aDrawInf.SetAscent( rPor.GetAscent() ); aDrawInf.SetKern( bKern ? rPor.Width() : 0 ); aDrawInf.SetWrong( bTmpWrong ? pWrongList : NULL ); aDrawInf.SetGrammarCheck( bTmpGrammarCheck ? pGrammarCheckList : NULL ); aDrawInf.SetSmartTags( bTmpSmart ? pSmartTags : NULL ); // SMARTTAGS GetTxtFly()->DrawTextOpaque( aDrawInf ); } else { aDrawInf.SetPos( aPos ); if( bKern ) pFnt->_DrawStretchText( aDrawInf ); else { aDrawInf.SetWrong( bTmpWrong ? pWrongList : NULL ); aDrawInf.SetGrammarCheck( bTmpGrammarCheck ? pGrammarCheckList : NULL ); aDrawInf.SetSmartTags( bTmpSmart ? pSmartTags : NULL ); // SMARTTAGS pFnt->_DrawText( aDrawInf ); } } } /************************************************************************* * SwTxtPaintInfo::CalcRect() *************************************************************************/ void SwTxtPaintInfo::CalcRect( const SwLinePortion& rPor, SwRect* pRect, SwRect* pIntersect ) const { Size aSize( rPor.Width(), rPor.Height() ); if( rPor.IsHangingPortion() ) aSize.Width() = ((SwHangingPortion&)rPor).GetInnerWidth(); if( rPor.InSpaceGrp() && GetSpaceAdd() ) { SwTwips nAdd = rPor.CalcSpacing( GetSpaceAdd(), *this ); if( rPor.InFldGrp() && GetSpaceAdd() < 0 && nAdd ) nAdd += GetSpaceAdd() / SPACING_PRECISION_FACTOR; aSize.Width() += nAdd; } Point aPoint; if( IsRotated() ) { long nTmp = aSize.Width(); aSize.Width() = aSize.Height(); aSize.Height() = nTmp; if ( 1 == GetDirection() ) { aPoint.A() = X() - rPor.GetAscent(); aPoint.B() = Y() - aSize.Height(); } else { aPoint.A() = X() - rPor.Height() + rPor.GetAscent(); aPoint.B() = Y(); } } else { aPoint.A() = X(); aPoint.B() = Y() - rPor.GetAscent(); } // Adjust x coordinate if we are inside a bidi portion const sal_Bool bFrmDir = GetTxtFrm()->IsRightToLeft(); sal_Bool bCounterDir = ( ! bFrmDir && DIR_RIGHT2LEFT == GetDirection() ) || ( bFrmDir && DIR_LEFT2RIGHT == GetDirection() ); if ( bCounterDir ) aPoint.A() -= aSize.Width(); SwRect aRect( aPoint, aSize ); if ( GetTxtFrm()->IsRightToLeft() ) GetTxtFrm()->SwitchLTRtoRTL( aRect ); if ( GetTxtFrm()->IsVertical() ) GetTxtFrm()->SwitchHorizontalToVertical( aRect ); if ( pRect ) *pRect = aRect; if( aRect.HasArea() && pIntersect ) { ::SwAlignRect( aRect, (ViewShell*)GetVsh() ); if ( GetOut()->IsClipRegion() ) { SwRect aClip( GetOut()->GetClipRegion().GetBoundRect() ); aRect.Intersection( aClip ); } *pIntersect = aRect; } } /************************************************************************* * lcl_DrawSpecial * * Draws a special portion, e.g., line break portion, tab portion. * rPor - The portion * rRect - The rectangle surrounding the character * pCol - Specify a color for the character * bCenter - Draw the character centered, otherwise left aligned * bRotate - Rotate the character if character rotation is set *************************************************************************/ static void lcl_DrawSpecial( const SwTxtPaintInfo& rInf, const SwLinePortion& rPor, SwRect& rRect, const Color* pCol, sal_Unicode cChar, sal_uInt8 nOptions ) { sal_Bool bCenter = 0 != ( nOptions & DRAW_SPECIAL_OPTIONS_CENTER ); sal_Bool bRotate = 0 != ( nOptions & DRAW_SPECIAL_OPTIONS_ROTATE ); // rRect is given in absolute coordinates if ( rInf.GetTxtFrm()->IsRightToLeft() ) rInf.GetTxtFrm()->SwitchRTLtoLTR( rRect ); if ( rInf.GetTxtFrm()->IsVertical() ) rInf.GetTxtFrm()->SwitchVerticalToHorizontal( rRect ); const SwFont* pOldFnt = rInf.GetFont(); // Font is generated only once: static SwFont* pFnt = 0; if ( ! pFnt ) { pFnt = new SwFont( *pOldFnt ); pFnt->SetFamily( FAMILY_DONTKNOW, pFnt->GetActual() ); pFnt->SetName( numfunc::GetDefBulletFontname(), pFnt->GetActual() ); pFnt->SetStyleName( aEmptyStr, pFnt->GetActual() ); pFnt->SetCharSet( RTL_TEXTENCODING_SYMBOL, pFnt->GetActual() ); } // Some of the current values are set at the font: if ( ! bRotate ) pFnt->SetVertical( 0, rInf.GetTxtFrm()->IsVertical() ); else pFnt->SetVertical( pOldFnt->GetOrientation() ); if ( pCol ) pFnt->SetColor( *pCol ); else pFnt->SetColor( pOldFnt->GetColor() ); Size aFontSize( 0, SPECIAL_FONT_HEIGHT ); pFnt->SetSize( aFontSize, pFnt->GetActual() ); ((SwTxtPaintInfo&)rInf).SetFont( pFnt ); // The maximum width depends on the current orientation const sal_uInt16 nDir = pFnt->GetOrientation( rInf.GetTxtFrm()->IsVertical() ); SwTwips nMaxWidth = 0; switch ( nDir ) { case 0 : nMaxWidth = rRect.Width(); break; case 900 : case 2700 : nMaxWidth = rRect.Height(); break; default: ASSERT( sal_False, "Unknown direction set at font" ) break; } // check if char fits into rectangle const XubString aTmp( cChar ); aFontSize = rInf.GetTxtSize( aTmp ).SvLSize(); while ( aFontSize.Width() > nMaxWidth ) { SwTwips nFactor = ( 100 * aFontSize.Width() ) / nMaxWidth; const SwTwips nOldWidth = aFontSize.Width(); // new height for font const sal_uInt8 nAct = pFnt->GetActual(); aFontSize.Height() = ( 100 * pFnt->GetSize( nAct ).Height() ) / nFactor; aFontSize.Width() = ( 100 * pFnt->GetSize( nAct).Width() ) / nFactor; if ( !aFontSize.Width() && !aFontSize.Height() ) break; pFnt->SetSize( aFontSize, nAct ); aFontSize = rInf.GetTxtSize( aTmp ).SvLSize(); if ( aFontSize.Width() >= nOldWidth ) break; } const Point aOldPos( rInf.GetPos() ); // adjust values so that tab is vertically and horizontally centered SwTwips nX = rRect.Left(); SwTwips nY = rRect.Top(); switch ( nDir ) { case 0 : if ( bCenter ) nX += ( rRect.Width() - aFontSize.Width() ) / 2; nY += ( rRect.Height() - aFontSize.Height() ) / 2 + rInf.GetAscent(); break; case 900 : if ( bCenter ) nX += ( rRect.Width() - aFontSize.Height() ) / 2 + rInf.GetAscent(); nY += ( rRect.Height() + aFontSize.Width() ) / 2; break; case 2700 : if ( bCenter ) nX += ( rRect.Width() + aFontSize.Height() ) / 2 - rInf.GetAscent(); nY += ( rRect.Height() - aFontSize.Width() ) / 2; break; } Point aTmpPos( nX, nY ); ((SwTxtPaintInfo&)rInf).SetPos( aTmpPos ); sal_uInt16 nOldWidth = rPor.Width(); ((SwLinePortion&)rPor).Width( (sal_uInt16)aFontSize.Width() ); rInf.DrawText( aTmp, rPor ); ((SwLinePortion&)rPor).Width( nOldWidth ); ((SwTxtPaintInfo&)rInf).SetFont( (SwFont*)pOldFnt ); ((SwTxtPaintInfo&)rInf).SetPos( aOldPos ); } /************************************************************************* * SwTxtPaintInfo::DrawRect() *************************************************************************/ void SwTxtPaintInfo::DrawRect( const SwRect &rRect, sal_Bool bNoGraphic, sal_Bool bRetouche ) const { if ( OnWin() || !bRetouche ) { if( aTxtFly.IsOn() ) ((SwTxtPaintInfo*)this)->GetTxtFly()-> DrawFlyRect( pOut, rRect, *this, bNoGraphic ); else if ( bNoGraphic ) pOut->DrawRect( rRect.SVRect() ); else { ASSERT( ((SvxBrushItem*)-1) != pBrushItem, "DrawRect: Uninitialized BrushItem!" ); ::DrawGraphic( pBrushItem, pOut, aItemRect, rRect ); } } } /************************************************************************* * SwTxtPaintInfo::DrawTab() *************************************************************************/ void SwTxtPaintInfo::DrawTab( const SwLinePortion &rPor ) const { if( OnWin() ) { SwRect aRect; CalcRect( rPor, &aRect ); if ( ! aRect.HasArea() ) return; const sal_Unicode cChar = GetTxtFrm()->IsRightToLeft() ? CHAR_TAB_RTL : CHAR_TAB; const sal_uInt8 nOptions = DRAW_SPECIAL_OPTIONS_CENTER | DRAW_SPECIAL_OPTIONS_ROTATE; lcl_DrawSpecial( *this, rPor, aRect, 0, cChar, nOptions ); } } /************************************************************************* * SwTxtPaintInfo::DrawLineBreak() *************************************************************************/ void SwTxtPaintInfo::DrawLineBreak( const SwLinePortion &rPor ) const { if( OnWin() ) { KSHORT nOldWidth = rPor.Width(); ((SwLinePortion&)rPor).Width( LINE_BREAK_WIDTH ); SwRect aRect; CalcRect( rPor, &aRect ); if( aRect.HasArea() ) { const sal_Unicode cChar = GetTxtFrm()->IsRightToLeft() ? CHAR_LINEBREAK_RTL : CHAR_LINEBREAK; const sal_uInt8 nOptions = 0; lcl_DrawSpecial( *this, rPor, aRect, 0, cChar, nOptions ); } ((SwLinePortion&)rPor).Width( nOldWidth ); } } /************************************************************************* * SwTxtPaintInfo::DrawRedArrow() *************************************************************************/ void SwTxtPaintInfo::DrawRedArrow( const SwLinePortion &rPor ) const { Size aSize( SPECIAL_FONT_HEIGHT, SPECIAL_FONT_HEIGHT ); SwRect aRect( ((SwArrowPortion&)rPor).GetPos(), aSize ); sal_Unicode cChar; if( ((SwArrowPortion&)rPor).IsLeft() ) { aRect.Pos().Y() += 20 - GetAscent(); aRect.Pos().X() += 20; if( aSize.Height() > rPor.Height() ) aRect.Height( rPor.Height() ); cChar = CHAR_LEFT_ARROW; } else { if( aSize.Height() > rPor.Height() ) aRect.Height( rPor.Height() ); aRect.Pos().Y() -= aRect.Height() + 20; aRect.Pos().X() -= aRect.Width() + 20; cChar = CHAR_RIGHT_ARROW; } if ( GetTxtFrm()->IsVertical() ) GetTxtFrm()->SwitchHorizontalToVertical( aRect ); Color aCol( COL_LIGHTRED ); if( aRect.HasArea() ) { const sal_uInt8 nOptions = 0; lcl_DrawSpecial( *this, rPor, aRect, &aCol, cChar, nOptions ); } } /************************************************************************* * SwTxtPaintInfo::DrawPostIts() *************************************************************************/ void SwTxtPaintInfo::DrawPostIts( const SwLinePortion&, sal_Bool bScript ) const { if( OnWin() && pOpt->IsPostIts() ) { Size aSize; Point aTmp; const sal_uInt16 nPostItsWidth = pOpt->GetPostItsWidth( GetOut() ); const sal_uInt16 nFontHeight = pFnt->GetHeight( pVsh, *GetOut() ); const sal_uInt16 nFontAscent = pFnt->GetAscent( pVsh, *GetOut() ); switch ( pFnt->GetOrientation( GetTxtFrm()->IsVertical() ) ) { case 0 : aSize.Width() = nPostItsWidth; aSize.Height() = nFontHeight; aTmp.X() = aPos.X(); aTmp.Y() = aPos.Y() - nFontAscent; break; case 900 : aSize.Height() = nPostItsWidth; aSize.Width() = nFontHeight; aTmp.X() = aPos.X() - nFontAscent; aTmp.Y() = aPos.Y(); break; case 2700 : aSize.Height() = nPostItsWidth; aSize.Width() = nFontHeight; aTmp.X() = aPos.X() - nFontHeight + nFontAscent; aTmp.Y() = aPos.Y(); break; } SwRect aTmpRect( aTmp, aSize ); if ( GetTxtFrm()->IsRightToLeft() ) GetTxtFrm()->SwitchLTRtoRTL( aTmpRect ); if ( GetTxtFrm()->IsVertical() ) GetTxtFrm()->SwitchHorizontalToVertical( aTmpRect ); const Rectangle aRect( aTmpRect.SVRect() ); pOpt->PaintPostIts( (OutputDevice*)GetOut(), aRect, bScript ); } } void SwTxtPaintInfo::DrawCheckBox( const SwFieldFormPortion &rPor, bool checked) const { SwRect aIntersect; CalcRect( rPor, &aIntersect, 0 ); if ( aIntersect.HasArea() ) { if (OnWin() && SwViewOption::IsFieldShadings() && !GetOpt().IsPagePreview()) { OutputDevice* pOut_ = (OutputDevice*)GetOut(); pOut_->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); pOut_->SetFillColor( SwViewOption::GetFieldShadingsColor() ); pOut_->SetLineColor(); pOut_->DrawRect( aIntersect.SVRect() ); pOut_->Pop(); } const int delta=10; Rectangle r(aIntersect.Left()+delta, aIntersect.Top()+delta, aIntersect.Right()-delta, aIntersect.Bottom()-delta); pOut->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); pOut->SetLineColor( Color(0, 0, 0)); pOut->SetFillColor(); pOut->DrawRect( r ); if (checked) { pOut->DrawLine(r.TopLeft(), r.BottomRight()); pOut->DrawLine(r.TopRight(), r.BottomLeft()); } pOut->Pop(); } } /************************************************************************* * SwTxtPaintInfo::DrawBackGround() *************************************************************************/ void SwTxtPaintInfo::DrawBackground( const SwLinePortion &rPor ) const { ASSERT( OnWin(), "SwTxtPaintInfo::DrawBackground: printer polution ?" ); SwRect aIntersect; CalcRect( rPor, 0, &aIntersect ); if ( aIntersect.HasArea() ) { OutputDevice* pTmpOut = (OutputDevice*)GetOut(); pTmpOut->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); // For dark background we do not want to have a filled rectangle if ( GetVsh() && GetVsh()->GetWin() && lcl_IsDarkBackground( *this ) ) { pTmpOut->SetLineColor( SwViewOption::GetFontColor().GetColor() ); } else { pTmpOut->SetFillColor( SwViewOption::GetFieldShadingsColor() ); pTmpOut->SetLineColor(); } DrawRect( aIntersect, sal_True ); pTmpOut->Pop(); } } void SwTxtPaintInfo::_DrawBackBrush( const SwLinePortion &rPor ) const { { SwRect aIntersect; CalcRect( rPor, &aIntersect, 0 ); if(aIntersect.HasArea()) { SwTxtNode *pNd = pFrm->GetTxtNode(); const ::sw::mark::IMark* pFieldmark = NULL; if(pNd) { const SwDoc *doc=pNd->GetDoc(); if(doc) { SwIndex aIndex(pNd, GetIdx()); SwPosition aPosition(*pNd, aIndex); pFieldmark=doc->getIDocumentMarkAccess()->getFieldmarkFor(aPosition); } } bool bIsStartMark=(1==GetLen() && CH_TXT_ATR_FIELDSTART==GetTxt().GetChar(GetIdx())); if(pFieldmark) { OSL_TRACE("Found Fieldmark"); #if DEBUG rtl::OUString str = pFieldmark->ToString( ); fprintf( stderr, "%s\n", rtl::OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr( ) ); #endif } if(bIsStartMark) OSL_TRACE("Found StartMark"); if (OnWin() && (pFieldmark!=NULL || bIsStartMark) && SwViewOption::IsFieldShadings() && !GetOpt().IsPagePreview()) { OutputDevice* pOutDev = (OutputDevice*)GetOut(); pOutDev->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); pOutDev->SetFillColor( SwViewOption::GetFieldShadingsColor() ); pOutDev->SetLineColor( ); pOutDev->DrawRect( aIntersect.SVRect() ); pOutDev->Pop(); } } } if( !pFnt->GetBackColor() ) return; ASSERT( pFnt->GetBackColor(), "DrawBackBrush: Lost Color" ); SwRect aIntersect; CalcRect( rPor, 0, &aIntersect ); if ( aIntersect.HasArea() ) { OutputDevice* pTmpOut = (OutputDevice*)GetOut(); // --> FME 2004-06-24 #i16816# tagged pdf support SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, 0, *pTmpOut ); // <-- pTmpOut->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); pTmpOut->SetFillColor( *pFnt->GetBackColor() ); pTmpOut->SetLineColor(); DrawRect( aIntersect, sal_True, sal_False ); pTmpOut->Pop(); } } /************************************************************************* * SwTxtPaintInfo::DrawViewOpt() *************************************************************************/ void SwTxtPaintInfo::DrawViewOpt( const SwLinePortion &rPor, const MSHORT nWhich ) const { if( OnWin() && !IsMulti() ) { sal_Bool bDraw = sal_False; switch( nWhich ) { case POR_FTN: case POR_QUOVADIS: case POR_NUMBER: case POR_FLD: case POR_URL: case POR_HIDDEN: case POR_TOX: case POR_REF: case POR_META: case POR_CONTROLCHAR: if ( !GetOpt().IsPagePreview() && !GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() && (POR_NUMBER != nWhich || pFrm->GetTxtNode()->HasMarkedLabel())) // #i27615# bDraw = sal_True; break; case POR_TAB: if ( GetOpt().IsTab() ) bDraw = sal_True; break; case POR_SOFTHYPH: if ( GetOpt().IsSoftHyph() )bDraw = sal_True; break; case POR_BLANK: if ( GetOpt().IsHardBlank())bDraw = sal_True; break; default: { ASSERT( !this, "SwTxtPaintInfo::DrawViewOpt: don't know how to draw this" ); break; } } if ( bDraw ) DrawBackground( rPor ); } } /************************************************************************* * SwTxtPaintInfo::_NotifyURL() *************************************************************************/ void SwTxtPaintInfo::_NotifyURL( const SwLinePortion &rPor ) const { ASSERT( pNoteURL, "NotifyURL: pNoteURL gone with the wind!" ); SwRect aIntersect; CalcRect( rPor, 0, &aIntersect ); if( aIntersect.HasArea() ) { SwTxtNode *pNd = (SwTxtNode*)GetTxtFrm()->GetTxtNode(); SwTxtAttr *const pAttr = pNd->GetTxtAttrAt(GetIdx(), RES_TXTATR_INETFMT); if( pAttr ) { const SwFmtINetFmt& rFmt = pAttr->GetINetFmt(); pNoteURL->InsertURLNote( rFmt.GetValue(), rFmt.GetTargetFrame(), aIntersect ); } } } /************************************************************************* * lcl_InitHyphValues() *************************************************************************/ static void lcl_InitHyphValues( PropertyValues &rVals, sal_Int16 nMinLeading, sal_Int16 nMinTrailing ) { sal_Int32 nLen = rVals.getLength(); if (0 == nLen) // yet to be initialized? { rVals.realloc( 2 ); PropertyValue *pVal = rVals.getArray(); pVal[0].Name = C2U( UPN_HYPH_MIN_LEADING ); pVal[0].Handle = UPH_HYPH_MIN_LEADING; pVal[0].Value <<= nMinLeading; pVal[1].Name = C2U( UPN_HYPH_MIN_TRAILING ); pVal[1].Handle = UPH_HYPH_MIN_TRAILING; pVal[1].Value <<= nMinTrailing; } else if (2 == nLen) // already initialized once? { PropertyValue *pVal = rVals.getArray(); pVal[0].Value <<= nMinLeading; pVal[1].Value <<= nMinTrailing; } else { DBG_ERROR( "unxpected size of sequence" ); } } /************************************************************************* * SwTxtFormatInfo::GetHyphValues() *************************************************************************/ const PropertyValues & SwTxtFormatInfo::GetHyphValues() const { DBG_ASSERT( 2 == aHyphVals.getLength(), "hyphenation values not yet initialized" ); return aHyphVals; } /************************************************************************* * SwTxtFormatInfo::InitHyph() *************************************************************************/ sal_Bool SwTxtFormatInfo::InitHyph( const sal_Bool bAutoHyphen ) { const SwAttrSet& rAttrSet = GetTxtFrm()->GetTxtNode()->GetSwAttrSet(); SetHanging( rAttrSet.GetHangingPunctuation().GetValue() ); SetScriptSpace( rAttrSet.GetScriptSpace().GetValue() ); SetForbiddenChars( rAttrSet.GetForbiddenRule().GetValue() ); const SvxHyphenZoneItem &rAttr = rAttrSet.GetHyphenZone(); MaxHyph() = rAttr.GetMaxHyphens(); sal_Bool bAuto = bAutoHyphen || rAttr.IsHyphen(); if( bAuto || bInterHyph ) { nHyphStart = nHyphWrdStart = STRING_LEN; nHyphWrdLen = 0; const sal_Int16 nMinimalLeading = Max(rAttr.GetMinLead(), sal_uInt8(2)); const sal_Int16 nMinimalTrailing = rAttr.GetMinTrail(); lcl_InitHyphValues( aHyphVals, nMinimalLeading, nMinimalTrailing); } return bAuto; } /************************************************************************* * SwTxtFormatInfo::CtorInitTxtFormatInfo() *************************************************************************/ void SwTxtFormatInfo::CtorInitTxtFormatInfo( SwTxtFrm *pNewFrm, const sal_Bool bNewInterHyph, const sal_Bool bNewQuick, const sal_Bool bTst ) { CtorInitTxtPaintInfo( pNewFrm, SwRect() ); bQuick = bNewQuick; bInterHyph = bNewInterHyph; //! needs to be done in this order nMinLeading = 2; nMinTrailing = 2; nMinWordLength = 0; bAutoHyph = InitHyph(); bIgnoreFly = sal_False; bFakeLineStart = sal_False; bShift = sal_False; bDropInit = sal_False; bTestFormat = bTst; nLeft = 0; nRight = 0; nFirst = 0; nRealWidth = 0; nForcedLeftMargin = 0; pRest = 0; nLineHeight = 0; nLineNettoHeight = 0; SetLineStart(0); Init(); } /************************************************************************* * SwTxtFormatInfo::IsHyphenate() *************************************************************************/ // Trennen oder nicht trennen, das ist hier die Frage: // - in keinem Fall trennen, wenn der Hyphenator ERROR zurueckliefert, // oder wenn als Sprache NOLANGUAGE eingestellt ist. // - ansonsten immer trennen, wenn interaktive Trennung vorliegt // - wenn keine interakt. Trennung, dann nur trennen, wenn im ParaFmt // automatische Trennung eingestellt ist. sal_Bool SwTxtFormatInfo::IsHyphenate() const { if( !bInterHyph && !bAutoHyph ) return sal_False; LanguageType eTmp = GetFont()->GetLanguage(); if( LANGUAGE_DONTKNOW == eTmp || LANGUAGE_NONE == eTmp ) return sal_False; uno::Reference< XHyphenator > xHyph = ::GetHyphenator(); if (bInterHyph && xHyph.is()) SvxSpellWrapper::CheckHyphLang( xHyph, eTmp ); if( !xHyph.is() || !xHyph->hasLocale( pBreakIt->GetLocale(eTmp) ) ) return sal_False; return sal_True; } /************************************************************************* * SwTxtFormatInfo::GetDropFmt() *************************************************************************/ // Dropcaps vom SwTxtFormatter::CTOR gerufen. const SwFmtDrop *SwTxtFormatInfo::GetDropFmt() const { const SwFmtDrop *pDrop = &GetTxtFrm()->GetTxtNode()->GetSwAttrSet().GetDrop(); if( 1 >= pDrop->GetLines() || ( !pDrop->GetChars() && !pDrop->GetWholeWord() ) ) pDrop = 0; return pDrop; } /************************************************************************* * SwTxtFormatInfo::Init() *************************************************************************/ void SwTxtFormatInfo::Init() { // Nicht initialisieren: pRest, nLeft, nRight, nFirst, nRealWidth X(0); bArrowDone = bFull = bFtnDone = bErgoDone = bNumDone = bNoEndHyph = bNoMidHyph = bStop = bNewLine = bUnderFlow = sal_False; // generally we do not allow number portions in follows, except... if ( GetTxtFrm()->IsFollow() ) { const SwTxtFrm* pMaster = GetTxtFrm()->FindMaster(); const SwLinePortion* pTmpPara = pMaster->GetPara(); // there is a master for this follow and the master does not have // any contents (especially it does not have a number portion) bNumDone = ! pTmpPara || ! ((SwParaPortion*)pTmpPara)->GetFirstPortion()->IsFlyPortion(); } pRoot = 0; pLast = 0; pFly = 0; pLastFld = 0; pLastTab = 0; pUnderFlow = 0; cTabDecimal = 0; nWidth = nRealWidth; nForcedLeftMargin = 0; nSoftHyphPos = 0; nUnderScorePos = STRING_LEN; cHookChar = 0; SetIdx(0); SetLen( GetTxt().Len() ); SetPaintOfst(0); } /*-----------------16.10.00 11:39------------------- * There are a few differences between a copy constructor * and the following constructor for multi-line formatting. * The root is the first line inside the multi-portion, * the line start is the actual position in the text, * the line width is the rest width from the surrounding line * and the bMulti and bFirstMulti-flag has to be set correctly. * --------------------------------------------------*/ SwTxtFormatInfo::SwTxtFormatInfo( const SwTxtFormatInfo& rInf, SwLineLayout& rLay, SwTwips nActWidth ) : SwTxtPaintInfo( rInf ) { pRoot = &rLay; pLast = &rLay; pFly = NULL; pLastFld = NULL; pUnderFlow = NULL; pRest = NULL; pLastTab = NULL; nSoftHyphPos = 0; nUnderScorePos = STRING_LEN; nHyphStart = 0; nHyphWrdStart = 0; nHyphWrdLen = 0; nLineStart = rInf.GetIdx(); nLeft = rInf.nLeft; nRight = rInf.nRight; nFirst = rInf.nLeft; nRealWidth = KSHORT(nActWidth); nWidth = nRealWidth; nLineHeight = 0; nLineNettoHeight = 0; nForcedLeftMargin = 0; nMinLeading = 0; nMinTrailing = 0; nMinWordLength = 0; bFull = sal_False; bFtnDone = sal_True; bErgoDone = sal_True; bNumDone = sal_True; bArrowDone = sal_True; bStop = sal_False; bNewLine = sal_True; bShift = sal_False; bUnderFlow = sal_False; bInterHyph = sal_False; bAutoHyph = sal_False; bDropInit = sal_False; bQuick = rInf.bQuick; bNoEndHyph = sal_False; bNoMidHyph = sal_False; bIgnoreFly = sal_False; bFakeLineStart = sal_False; cTabDecimal = 0; cHookChar = 0; nMaxHyph = 0; bTestFormat = rInf.bTestFormat; SetMulti( sal_True ); SetFirstMulti( rInf.IsFirstMulti() ); } /************************************************************************* * SwTxtFormatInfo::_CheckFtnPortion() *************************************************************************/ sal_Bool SwTxtFormatInfo::_CheckFtnPortion( SwLineLayout* pCurr ) { KSHORT nHeight = pCurr->GetRealHeight(); SwLinePortion *pPor = pCurr->GetPortion(); sal_Bool bRet = sal_False; while( pPor ) { if( pPor->IsFtnPortion() && nHeight > ((SwFtnPortion*)pPor)->Orig() ) { bRet = sal_True; SetLineHeight( nHeight ); SetLineNettoHeight( pCurr->Height() ); break; } pPor = pPor->GetPortion(); } return bRet; } /************************************************************************* * SwTxtFormatInfo::ScanPortionEnd() *************************************************************************/ xub_StrLen SwTxtFormatInfo::ScanPortionEnd( const xub_StrLen nStart, const xub_StrLen nEnd ) { cHookChar = 0; xub_StrLen i = nStart; // // Used for decimal tab handling: // const xub_Unicode cTabDec = GetLastTab() ? (sal_Unicode)GetTabDecimal() : 0; const xub_Unicode cThousandSep = ',' == cTabDec ? '.' : ','; // --> FME 2006-01-23 #i45951# German (Switzerland) uses ' as thousand separator: const xub_Unicode cThousandSep2 = ',' == cTabDec ? '.' : '\''; // <-- bool bNumFound = false; const bool bTabCompat = GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT); // Removed for i7288. bSkip used to be passed from SwFldPortion::Format // as IsFollow(). Therefore more than one special character was not // handled correctly at the beginning of follow fields. // if ( bSkip && i < nEnd ) // ++i; for( ; i < nEnd; ++i ) { const xub_Unicode cPos = GetChar( i ); switch( cPos ) { case CH_TXTATR_BREAKWORD: case CH_TXTATR_INWORD: if( !HasHint( i )) break; // no break; case CHAR_SOFTHYPHEN: case CHAR_HARDHYPHEN: case CHAR_HARDBLANK: case CH_TAB: case CH_BREAK: case CHAR_ZWSP : case CHAR_ZWNBSP : // case CHAR_RLM : // case CHAR_LRM : cHookChar = cPos; return i; case CHAR_UNDERSCORE: if ( STRING_LEN == nUnderScorePos ) nUnderScorePos = i; break; default: if ( cTabDec ) { if( cTabDec == cPos ) { ASSERT( cPos, "Unexpected end of string" ); if( cPos ) // robust { cHookChar = cPos; return i; } } // // Compatibility: First non-digit character behind a // a digit character becomes the hook character // if ( bTabCompat ) { if ( ( 0x2F < cPos && cPos < 0x3A ) || ( bNumFound && ( cPos == cThousandSep || cPos == cThousandSep2 ) ) ) { bNumFound = true; } else { if ( bNumFound ) { cHookChar = cPos; SetTabDecimal( cPos ); return i; } } } } } } // --> FME 2006-01-13 #130210# Check if character *behind* the portion has // to become the hook: if ( i == nEnd && i < GetTxt().Len() && bNumFound ) { const xub_Unicode cPos = GetChar( i ); if ( cPos != cTabDec && cPos != cThousandSep && cPos !=cThousandSep2 && ( 0x2F >= cPos || cPos >= 0x3A ) ) { cHookChar = GetChar( i ); SetTabDecimal( cHookChar ); } } return i; } sal_Bool SwTxtFormatInfo::LastKernPortion() { if( GetLast() ) { if( GetLast()->IsKernPortion() ) return sal_True; if( GetLast()->Width() || ( GetLast()->GetLen() && !GetLast()->IsHolePortion() ) ) return sal_False; } SwLinePortion* pPor = GetRoot(); SwLinePortion *pKern = NULL; while( pPor ) { if( pPor->IsKernPortion() ) pKern = pPor; else if( pPor->Width() || ( pPor->GetLen() && !pPor->IsHolePortion() ) ) pKern = NULL; pPor = pPor->GetPortion(); } if( pKern ) { SetLast( pKern ); return sal_True; } return sal_False; } /************************************************************************* * class SwTxtSlot *************************************************************************/ SwTxtSlot::SwTxtSlot( const SwTxtSizeInfo *pNew, const SwLinePortion *pPor, bool bTxtLen, bool bExgLists, const sal_Char *pCh ) : pOldTxt( 0 ), pOldSmartTagList( 0 ), pOldGrammarCheckList( 0 ), pTempList( 0 ) { if( pCh ) { aTxt = XubString( pCh, RTL_TEXTENCODING_MS_1252 ); bOn = sal_True; } else bOn = pPor->GetExpTxt( *pNew, aTxt ); // Der Text wird ausgetauscht... if( bOn ) { pInf = (SwTxtSizeInfo*)pNew; nIdx = pInf->GetIdx(); nLen = pInf->GetLen(); pOldTxt = &(pInf->GetTxt()); pInf->SetTxt( aTxt ); pInf->SetIdx( 0 ); pInf->SetLen( bTxtLen ? pInf->GetTxt().Len() : pPor->GetLen() ); // ST2 if ( bExgLists ) { pOldSmartTagList = static_cast(pInf)->GetSmartTags(); if ( pOldSmartTagList ) { const sal_uInt16 nPos = pOldSmartTagList->GetWrongPos(nIdx); const xub_StrLen nListPos = pOldSmartTagList->Pos(nPos); if( nListPos == nIdx ) ((SwTxtPaintInfo*)pInf)->SetSmartTags( pOldSmartTagList->SubList( nPos ) ); else if( !pTempList && nPos < pOldSmartTagList->Count() && nListPos < nIdx && aTxt.Len() ) { pTempList = new SwWrongList( WRONGLIST_SMARTTAG ); pTempList->Insert( rtl::OUString(), 0, 0, aTxt.Len(), 0 ); ((SwTxtPaintInfo*)pInf)->SetSmartTags( pTempList ); } else ((SwTxtPaintInfo*)pInf)->SetSmartTags( 0); } pOldGrammarCheckList = static_cast(pInf)->GetGrammarCheckList(); if ( pOldGrammarCheckList ) { const sal_uInt16 nPos = pOldGrammarCheckList->GetWrongPos(nIdx); const xub_StrLen nListPos = pOldGrammarCheckList->Pos(nPos); if( nListPos == nIdx ) ((SwTxtPaintInfo*)pInf)->SetGrammarCheckList( pOldGrammarCheckList->SubList( nPos ) ); else if( !pTempList && nPos < pOldGrammarCheckList->Count() && nListPos < nIdx && aTxt.Len() ) { pTempList = new SwWrongList( WRONGLIST_GRAMMAR ); pTempList->Insert( rtl::OUString(), 0, 0, aTxt.Len(), 0 ); ((SwTxtPaintInfo*)pInf)->SetGrammarCheckList( pTempList ); } else ((SwTxtPaintInfo*)pInf)->SetGrammarCheckList( 0); } } } } /************************************************************************* * SwTxtSlot::~SwTxtSlot() *************************************************************************/ SwTxtSlot::~SwTxtSlot() { if( bOn ) { pInf->SetTxt( *pOldTxt ); pInf->SetIdx( nIdx ); pInf->SetLen( nLen ); // ST2 // Restore old smart tag list if ( pOldSmartTagList ) ((SwTxtPaintInfo*)pInf)->SetSmartTags( pOldSmartTagList ); if ( pOldGrammarCheckList ) ((SwTxtPaintInfo*)pInf)->SetGrammarCheckList( pOldGrammarCheckList ); delete pTempList; } } /************************************************************************* * SwFontSave::SwFontSave() *************************************************************************/ SwFontSave::SwFontSave( const SwTxtSizeInfo &rInf, SwFont *pNew, SwAttrIter* pItr ) : pFnt( pNew ? ((SwTxtSizeInfo&)rInf).GetFont() : 0 ) { if( pFnt ) { pInf = &((SwTxtSizeInfo&)rInf); // In these cases we temporarily switch to the new font: // 1. the fonts have a different magic number // 2. they have different script types // 3. their background colors differ (this is not covered by 1.) if( pFnt->DifferentMagic( pNew, pFnt->GetActual() ) || pNew->GetActual() != pFnt->GetActual() || ( ! pNew->GetBackColor() && pFnt->GetBackColor() ) || ( pNew->GetBackColor() && ! pFnt->GetBackColor() ) || ( pNew->GetBackColor() && pFnt->GetBackColor() && ( *pNew->GetBackColor() != *pFnt->GetBackColor() ) ) ) { pNew->SetTransparent( sal_True ); pNew->SetAlign( ALIGN_BASELINE ); pInf->SetFont( pNew ); } else pFnt = 0; pNew->Invalidate(); pNew->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() ); if( pItr && pItr->GetFnt() == pFnt ) { pIter = pItr; pIter->SetFnt( pNew ); } else pIter = NULL; } } /************************************************************************* * SwFontSave::~SwFontSave() *************************************************************************/ SwFontSave::~SwFontSave() { if( pFnt ) { // SwFont zurueckstellen pFnt->Invalidate(); pInf->SetFont( pFnt ); if( pIter ) { pIter->SetFnt( pFnt ); pIter->nPos = STRING_LEN; } } } /************************************************************************* * SwDefFontSave::SwDefFontSave() *************************************************************************/ SwDefFontSave::SwDefFontSave( const SwTxtSizeInfo &rInf ) : pFnt( ((SwTxtSizeInfo&)rInf).GetFont() ) { const sal_Bool bTmpAlter = pFnt->GetFixKerning() || ( RTL_TEXTENCODING_SYMBOL == pFnt->GetCharSet(pFnt->GetActual()) ) ; const sal_Bool bFamily = bTmpAlter && pFnt->GetName( pFnt->GetActual() ) != numfunc::GetDefBulletFontname(); const sal_Bool bRotation = (sal_Bool)pFnt->GetOrientation() && ! rInf.GetTxtFrm()->IsVertical(); if( bFamily || bRotation ) { pNewFnt = new SwFont( *pFnt ); if ( bFamily ) { pNewFnt->SetFamily( FAMILY_DONTKNOW, pFnt->GetActual() ); pNewFnt->SetName( numfunc::GetDefBulletFontname(), pFnt->GetActual() ); pNewFnt->SetStyleName( aEmptyStr, pFnt->GetActual() ); pNewFnt->SetCharSet( RTL_TEXTENCODING_SYMBOL, pFnt->GetActual() ); pNewFnt->SetFixKerning( 0 ); } if ( bRotation ) pNewFnt->SetVertical( 0, rInf.GetTxtFrm()->IsVertical() ); pInf = &((SwTxtSizeInfo&)rInf); pNewFnt->Invalidate(); pInf->SetFont( pNewFnt ); } else { pFnt = 0; pNewFnt = 0; } } /************************************************************************* * SwDefFontSave::~SwDefFontSave() *************************************************************************/ SwDefFontSave::~SwDefFontSave() { if( pFnt ) { delete pNewFnt; // SwFont zurueckstellen pFnt->Invalidate(); pInf->SetFont( pFnt ); } } /************************************************************************* * SwTxtFormatInfo::ChgHyph() *************************************************************************/ sal_Bool SwTxtFormatInfo::ChgHyph( const sal_Bool bNew ) { const sal_Bool bOld = bAutoHyph; if( bAutoHyph != bNew ) { bAutoHyph = bNew; InitHyph( bNew ); // 5744: Sprache am Hyphenator einstellen. if( pFnt ) pFnt->ChgPhysFnt( pVsh, *pOut ); } return bOld; }