diff options
Diffstat (limited to 'sw/source/core/txtnode/swfont.cxx')
-rw-r--r-- | sw/source/core/txtnode/swfont.cxx | 1469 |
1 files changed, 1469 insertions, 0 deletions
diff --git a/sw/source/core/txtnode/swfont.cxx b/sw/source/core/txtnode/swfont.cxx new file mode 100644 index 000000000..0ed7baf87 --- /dev/null +++ b/sw/source/core/txtnode/swfont.cxx @@ -0,0 +1,1469 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <hintids.hxx> + +#include <com/sun/star/i18n/ScriptType.hpp> +#include <vcl/outdev.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/cmapitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/escapementitem.hxx> +#include <editeng/autokernitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/contouritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/emphasismarkitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charrotateitem.hxx> +#include <editeng/twolinesitem.hxx> +#include <editeng/charhiddenitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/shaditem.hxx> +#include <IDocumentSettingAccess.hxx> +#include <charatr.hxx> +#include <viewsh.hxx> +#include <swfont.hxx> +#include <fntcache.hxx> +#include <txtfrm.hxx> +#include <scriptinfo.hxx> + +#ifdef DBG_UTIL +// global Variable +SvStatistics g_SvStat; +#endif + +using namespace ::com::sun::star; + +// set background brush, depending on character formatting +void SwFont::SetBackColor( std::optional<Color> xNewColor ) +{ + mxBackColor = xNewColor; + m_bFontChg = true; + m_aSub[SwFontScript::Latin].m_nFontCacheId = m_aSub[SwFontScript::CJK].m_nFontCacheId = m_aSub[SwFontScript::CTL].m_nFontCacheId = nullptr; +} + +void SwFont::SetTopBorder( const editeng::SvxBorderLine* pTopBorder ) +{ + if( pTopBorder ) + m_aTopBorder = *pTopBorder; + else + { + m_aTopBorder.reset(); + m_nTopBorderDist = 0; + } + m_bFontChg = true; + m_aSub[SwFontScript::Latin].m_nFontCacheId = m_aSub[SwFontScript::CJK].m_nFontCacheId = m_aSub[SwFontScript::CTL].m_nFontCacheId = nullptr; +} + +void SwFont::SetBottomBorder( const editeng::SvxBorderLine* pBottomBorder ) +{ + if( pBottomBorder ) + m_aBottomBorder = *pBottomBorder; + else + { + m_aBottomBorder.reset(); + m_nBottomBorderDist = 0; + } + m_bFontChg = true; + m_aSub[SwFontScript::Latin].m_nFontCacheId = m_aSub[SwFontScript::CJK].m_nFontCacheId = m_aSub[SwFontScript::CTL].m_nFontCacheId = nullptr; +} + +void SwFont::SetRightBorder( const editeng::SvxBorderLine* pRightBorder ) +{ + if( pRightBorder ) + m_aRightBorder = *pRightBorder; + else + { + m_aRightBorder.reset(); + m_nRightBorderDist = 0; + } + m_bFontChg = true; + m_aSub[SwFontScript::Latin].m_nFontCacheId = m_aSub[SwFontScript::CJK].m_nFontCacheId = m_aSub[SwFontScript::CTL].m_nFontCacheId = nullptr; +} + +void SwFont::SetLeftBorder( const editeng::SvxBorderLine* pLeftBorder ) +{ + if( pLeftBorder ) + m_aLeftBorder = *pLeftBorder; + else + { + m_aLeftBorder.reset(); + m_nLeftBorderDist = 0; + } + m_bFontChg = true; + m_aSub[SwFontScript::Latin].m_nFontCacheId = m_aSub[SwFontScript::CJK].m_nFontCacheId = m_aSub[SwFontScript::CTL].m_nFontCacheId = nullptr; +} + +const std::optional<editeng::SvxBorderLine>& +SwFont::GetAbsTopBorder(const bool bVertLayout, const bool bVertLayoutLRBT) const +{ + switch (GetOrientation(bVertLayout, bVertLayoutLRBT).get()) + { + case 0 : + return m_aTopBorder; + case 900 : + return m_aRightBorder; + case 1800 : + return m_aBottomBorder; + case 2700 : + return m_aLeftBorder; + default : + assert(false); + return m_aTopBorder; + } +} + +const std::optional<editeng::SvxBorderLine>& +SwFont::GetAbsBottomBorder(const bool bVertLayout, const bool bVertLayoutLRBT) const +{ + switch (GetOrientation(bVertLayout, bVertLayoutLRBT).get()) + { + case 0 : + return m_aBottomBorder; + case 900 : + return m_aLeftBorder; + case 1800 : + return m_aTopBorder; + case 2700 : + return m_aRightBorder; + default : + assert(false); + return m_aBottomBorder; + } +} + +const std::optional<editeng::SvxBorderLine>& +SwFont::GetAbsLeftBorder(const bool bVertLayout, const bool bVertLayoutLRBT) const +{ + switch (GetOrientation(bVertLayout, bVertLayoutLRBT).get()) + { + case 0 : + return m_aLeftBorder; + case 900 : + return m_aTopBorder; + case 1800 : + return m_aRightBorder; + case 2700 : + return m_aBottomBorder; + default : + assert(false); + return m_aLeftBorder; + } +} + +const std::optional<editeng::SvxBorderLine>& +SwFont::GetAbsRightBorder(const bool bVertLayout, const bool bVertLayoutLRBT) const +{ + switch (GetOrientation(bVertLayout, bVertLayoutLRBT).get()) + { + case 0 : + return m_aRightBorder; + case 900 : + return m_aBottomBorder; + case 1800 : + return m_aLeftBorder; + case 2700 : + return m_aTopBorder; + default : + assert(false); + return m_aRightBorder; + } +} + +SvxShadowLocation SwFont::GetAbsShadowLocation(const bool bVertLayout, + const bool bVertLayoutLRBT) const +{ + SvxShadowLocation aLocation = SvxShadowLocation::NONE; + switch (GetOrientation(bVertLayout, bVertLayoutLRBT).get()) + { + case 0: + aLocation = m_aShadowLocation; + break; + + case 900: + switch ( m_aShadowLocation ) + { + case SvxShadowLocation::TopLeft: + aLocation = SvxShadowLocation::BottomLeft; + break; + case SvxShadowLocation::TopRight: + aLocation = SvxShadowLocation::TopLeft; + break; + case SvxShadowLocation::BottomLeft: + aLocation = SvxShadowLocation::BottomRight; + break; + case SvxShadowLocation::BottomRight: + aLocation = SvxShadowLocation::TopRight; + break; + case SvxShadowLocation::NONE: + case SvxShadowLocation::End: + aLocation = m_aShadowLocation; + break; + } + break; + + case 1800: + switch ( m_aShadowLocation ) + { + case SvxShadowLocation::TopLeft: + aLocation = SvxShadowLocation::BottomRight; + break; + case SvxShadowLocation::TopRight: + aLocation = SvxShadowLocation::BottomLeft; + break; + case SvxShadowLocation::BottomLeft: + aLocation = SvxShadowLocation::TopRight; + break; + case SvxShadowLocation::BottomRight: + aLocation = SvxShadowLocation::TopLeft; + break; + case SvxShadowLocation::NONE: + case SvxShadowLocation::End: + aLocation = m_aShadowLocation; + break; + } + break; + + case 2700: + switch ( m_aShadowLocation ) + { + case SvxShadowLocation::TopLeft: + aLocation = SvxShadowLocation::TopRight; + break; + case SvxShadowLocation::TopRight: + aLocation = SvxShadowLocation::BottomRight; + break; + case SvxShadowLocation::BottomLeft: + aLocation = SvxShadowLocation::TopLeft; + break; + case SvxShadowLocation::BottomRight: + aLocation = SvxShadowLocation::BottomLeft; + break; + case SvxShadowLocation::NONE: + case SvxShadowLocation::End: + aLocation = m_aShadowLocation; + break; + } + break; + + default: + assert(false); + break; + } + return aLocation; +} + +sal_uInt16 SwFont::CalcShadowSpace(const SvxShadowItemSide nShadow, const bool bVertLayout, + const bool bVertLayoutLRBT, const bool bSkipLeft, + const bool bSkipRight) const +{ + sal_uInt16 nSpace = 0; + const Degree10 nOrient = GetOrientation(bVertLayout, bVertLayoutLRBT); + const SvxShadowLocation aLoc = GetAbsShadowLocation(bVertLayout, bVertLayoutLRBT); + switch( nShadow ) + { + case SvxShadowItemSide::TOP: + if(( aLoc == SvxShadowLocation::TopLeft || + aLoc == SvxShadowLocation::TopRight ) && + ( nOrient == 0_deg10 || nOrient == 1800_deg10 || + ( nOrient == 900_deg10 && !bSkipRight ) || + ( nOrient == 2700_deg10 && !bSkipLeft ))) + { + nSpace = m_nShadowWidth; + } + break; + + case SvxShadowItemSide::BOTTOM: + if(( aLoc == SvxShadowLocation::BottomLeft || + aLoc == SvxShadowLocation::BottomRight ) && + ( nOrient == 0_deg10 || nOrient == 1800_deg10 || + ( nOrient == 900_deg10 && !bSkipLeft ) || + ( nOrient == 2700_deg10 && !bSkipRight ))) + { + nSpace = m_nShadowWidth; + } + break; + + case SvxShadowItemSide::LEFT: + if(( aLoc == SvxShadowLocation::TopLeft || + aLoc == SvxShadowLocation::BottomLeft ) && + ( nOrient == 900_deg10 || nOrient == 2700_deg10 || + ( nOrient == 0_deg10 && !bSkipLeft ) || + ( nOrient == 1800_deg10 && !bSkipRight ))) + { + nSpace = m_nShadowWidth; + } + break; + + case SvxShadowItemSide::RIGHT: + if(( aLoc == SvxShadowLocation::TopRight || + aLoc == SvxShadowLocation::BottomRight ) && + ( nOrient == 900_deg10 || nOrient == 2700_deg10 || + ( nOrient == 0_deg10 && !bSkipRight ) || + ( nOrient == 1800_deg10 && !bSkipLeft ))) + { + nSpace = m_nShadowWidth; + } + break; + default: + assert(false); + break; + } + + return nSpace; +} + +// maps directions for vertical layout +static Degree10 MapDirection(Degree10 nDir, const bool bVertFormat, const bool bVertFormatLRBT) +{ + if ( bVertFormat ) + { + switch ( nDir.get() ) + { + case 0 : + if (bVertFormatLRBT) + nDir = 900_deg10; + else + nDir = 2700_deg10; + break; + case 900 : + nDir = 0_deg10; + break; + case 2700 : + nDir = 1800_deg10; + break; +#if OSL_DEBUG_LEVEL > 0 + default : + OSL_FAIL( "Unsupported direction" ); + break; +#endif + } + } + return nDir; +} + +// maps the absolute direction set at the font to its logical counterpart +// in the rotated environment +Degree10 UnMapDirection(Degree10 nDir, const bool bVertFormat, const bool bVertFormatLRBT) +{ + if (bVertFormatLRBT) + { + switch (nDir.get()) + { + case 900: + nDir = 0_deg10; + break; + default: + SAL_WARN("sw.core", "unsupported direction for VertLRBT"); + break; + } + return nDir; + } + + if ( bVertFormat ) + { + switch ( nDir.get() ) + { + case 0 : + nDir = 900_deg10; + break; + case 1800 : + nDir = 2700_deg10; + break; + case 2700 : + nDir = 0_deg10; + break; +#if OSL_DEBUG_LEVEL > 0 + default : + OSL_FAIL( "Unsupported direction" ); + break; +#endif + } + } + return nDir; +} + +Degree10 SwFont::GetOrientation(const bool bVertFormat, const bool bVertFormatLRBT) const +{ + return UnMapDirection(m_aSub[m_nActual].GetOrientation(), bVertFormat, bVertFormatLRBT); +} + +void SwFont::SetVertical(Degree10 nDir, const bool bVertFormat, const bool bVertLayoutLRBT) +{ + // map direction if frame has vertical layout + nDir = MapDirection(nDir, bVertFormat, bVertLayoutLRBT); + + if( nDir != m_aSub[SwFontScript::Latin].GetOrientation() ) + { + m_bFontChg = true; + bool bVertical = bVertFormat && !bVertLayoutLRBT; + m_aSub[SwFontScript::Latin].SetVertical(nDir, bVertical); + m_aSub[SwFontScript::CJK].SetVertical(nDir, bVertical); + m_aSub[SwFontScript::CTL].SetVertical(nDir, bVertical); + } +} + +/* + Escapement: + frEsc: Fraction, ratio of Escapements + Esc = resulting Escapement + A1 = original Ascent (nOrgAscent) + A2 = shrunk Ascent (nEscAscent) + Ax = resulting Ascent (GetAscent()) + H1 = original Height (nOrgHeight) + H2 = shrunk Height (nEscHeight) + Hx = resulting Height (GetHeight()) + Bx = resulting Baseline for Text (CalcPos()) + (Attention: Y - A1!) + + Escapement: + Esc = H1 * frEsc; + + Superscript: + Ax = A2 + Esc; + Hx = H2 + Esc; + Bx = A1 - Esc; + + Subscript: + Ax = A1; + Hx = A1 + Esc + (H2 - A2); + Bx = A1 + Esc; +*/ + +// nEsc is the percentage +sal_uInt16 SwSubFont::CalcEscAscent( const sal_uInt16 nOldAscent ) const +{ + if( DFLT_ESC_AUTO_SUPER != GetEscapement() && + DFLT_ESC_AUTO_SUB != GetEscapement() ) + { + const tools::Long nAscent = nOldAscent + + ( static_cast<tools::Long>(m_nOrgHeight) * GetEscapement() ) / 100; + if ( nAscent>0 ) + return std::max<sal_uInt16>( nAscent, m_nOrgAscent ); + } + return m_nOrgAscent; +} + +void SwFont::SetDiffFnt( const SfxItemSet *pAttrSet, + const IDocumentSettingAccess *pIDocumentSettingAccess ) +{ + mxBackColor.reset(); + + if( pAttrSet ) + { + + if( const SvxFontItem* pFont = pAttrSet->GetItemIfSet( RES_CHRATR_FONT ) ) + { + m_aSub[SwFontScript::Latin].SetFamily( pFont->GetFamily() ); + m_aSub[SwFontScript::Latin].Font::SetFamilyName( pFont->GetFamilyName() ); + m_aSub[SwFontScript::Latin].Font::SetStyleName( pFont->GetStyleName() ); + m_aSub[SwFontScript::Latin].Font::SetPitch( pFont->GetPitch() ); + m_aSub[SwFontScript::Latin].Font::SetCharSet( pFont->GetCharSet() ); + } + if( const SvxFontHeightItem *pHeight = pAttrSet->GetItemIfSet( RES_CHRATR_FONTSIZE ) ) + { + m_aSub[SwFontScript::Latin].SvxFont::SetPropr( 100 ); + m_aSub[SwFontScript::Latin].m_aSize = m_aSub[SwFontScript::Latin].Font::GetFontSize(); + Size aTmpSize = m_aSub[SwFontScript::Latin].m_aSize; + aTmpSize.setHeight( pHeight->GetHeight() ); + m_aSub[SwFontScript::Latin].SetSize( aTmpSize ); + } + if( const SvxPostureItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_POSTURE ) ) + m_aSub[SwFontScript::Latin].Font::SetItalic( pItem->GetPosture() ); + if( const SvxWeightItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_WEIGHT ) ) + m_aSub[SwFontScript::Latin].Font::SetWeight( pItem->GetWeight() ); + if( const SvxLanguageItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_LANGUAGE ) ) + m_aSub[SwFontScript::Latin].SetLanguage( pItem->GetLanguage() ); + + if( const SvxFontItem* pFont = pAttrSet->GetItemIfSet( RES_CHRATR_CJK_FONT ) ) + { + m_aSub[SwFontScript::CJK].SetFamily( pFont->GetFamily() ); + m_aSub[SwFontScript::CJK].Font::SetFamilyName( pFont->GetFamilyName() ); + m_aSub[SwFontScript::CJK].Font::SetStyleName( pFont->GetStyleName() ); + m_aSub[SwFontScript::CJK].Font::SetPitch( pFont->GetPitch() ); + m_aSub[SwFontScript::CJK].Font::SetCharSet( pFont->GetCharSet() ); + } + if( const SvxFontHeightItem* pHeight = pAttrSet->GetItemIfSet( RES_CHRATR_CJK_FONTSIZE) ) + { + m_aSub[SwFontScript::CJK].SvxFont::SetPropr( 100 ); + m_aSub[SwFontScript::CJK].m_aSize = m_aSub[SwFontScript::CJK].Font::GetFontSize(); + Size aTmpSize = m_aSub[SwFontScript::CJK].m_aSize; + aTmpSize.setHeight( pHeight->GetHeight() ); + m_aSub[SwFontScript::CJK].SetSize( aTmpSize ); + } + if( const SvxPostureItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_CJK_POSTURE ) ) + m_aSub[SwFontScript::CJK].Font::SetItalic( pItem->GetPosture() ); + if( const SvxWeightItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_CJK_WEIGHT ) ) + m_aSub[SwFontScript::CJK].Font::SetWeight( pItem->GetWeight() ); + if( const SvxLanguageItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_CJK_LANGUAGE ) ) + { + LanguageType eNewLang = pItem->GetLanguage(); + m_aSub[SwFontScript::CJK].SetLanguage( eNewLang ); + m_aSub[SwFontScript::Latin].SetCJKContextLanguage( eNewLang ); + m_aSub[SwFontScript::CJK].SetCJKContextLanguage( eNewLang ); + m_aSub[SwFontScript::CTL].SetCJKContextLanguage( eNewLang ); + } + + if( const SvxFontItem* pFont = pAttrSet->GetItemIfSet( RES_CHRATR_CTL_FONT ) ) + { + m_aSub[SwFontScript::CTL].SetFamily( pFont->GetFamily() ); + m_aSub[SwFontScript::CTL].Font::SetFamilyName( pFont->GetFamilyName() ); + m_aSub[SwFontScript::CTL].Font::SetStyleName( pFont->GetStyleName() ); + m_aSub[SwFontScript::CTL].Font::SetPitch( pFont->GetPitch() ); + m_aSub[SwFontScript::CTL].Font::SetCharSet( pFont->GetCharSet() ); + } + if( const SvxFontHeightItem* pHeight = pAttrSet->GetItemIfSet( RES_CHRATR_CTL_FONTSIZE ) ) + { + m_aSub[SwFontScript::CTL].SvxFont::SetPropr( 100 ); + m_aSub[SwFontScript::CTL].m_aSize = m_aSub[SwFontScript::CTL].Font::GetFontSize(); + Size aTmpSize = m_aSub[SwFontScript::CTL].m_aSize; + aTmpSize.setHeight( pHeight->GetHeight() ); + m_aSub[SwFontScript::CTL].SetSize( aTmpSize ); + } + if( const SvxPostureItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_CTL_POSTURE ) ) + m_aSub[SwFontScript::CTL].Font::SetItalic(pItem->GetPosture() ); + if( const SvxWeightItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_CTL_WEIGHT ) ) + m_aSub[SwFontScript::CTL].Font::SetWeight( pItem->GetWeight() ); + if( const SvxLanguageItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_CTL_LANGUAGE ) ) + m_aSub[SwFontScript::CTL].SetLanguage( pItem->GetLanguage() ); + + if( const SvxUnderlineItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_UNDERLINE ) ) + { + SetUnderline( pItem->GetLineStyle() ); + SetUnderColor( pItem->GetColor() ); + } + if( const SvxOverlineItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_OVERLINE ) ) + { + SetOverline( pItem->GetLineStyle() ); + SetOverColor( pItem->GetColor() ); + } + if( const SvxCrossedOutItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_CROSSEDOUT ) ) + SetStrikeout( pItem->GetStrikeout() ); + if( const SvxColorItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_COLOR ) ) + SetColor( pItem->GetValue() ); + if( const SvxEmphasisMarkItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_EMPHASIS_MARK )) + SetEmphasisMark( pItem->GetEmphasisMark() ); + + SetTransparent( true ); + SetAlign( ALIGN_BASELINE ); + if( const SvxContourItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_CONTOUR ) ) + SetOutline( pItem->GetValue() ); + if( const SvxShadowedItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_SHADOWED ) ) + SetShadow( pItem->GetValue() ); + if( const SvxCharReliefItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_RELIEF ) ) + SetRelief( pItem->GetValue() ); + if( const SvxShadowedItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_SHADOWED )) + SetPropWidth( pItem->GetValue() ? 50 : 100 ); + if( const SvxAutoKernItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_AUTOKERN ) ) + { + if( pItem->GetValue() ) + { + SetAutoKern( ( !pIDocumentSettingAccess || + !pIDocumentSettingAccess->get(DocumentSettingId::KERN_ASIAN_PUNCTUATION) ) ? + FontKerning::FontSpecific : + FontKerning::Asian ); + } + else + SetAutoKern( FontKerning::NONE ); + } + if( const SvxWordLineModeItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_WORDLINEMODE ) ) + SetWordLineMode( pItem->GetValue() ); + + if( const SvxEscapementItem* pEsc = pAttrSet->GetItemIfSet( RES_CHRATR_ESCAPEMENT ) ) + { + SetEscapement( pEsc->GetEsc() ); + if( m_aSub[SwFontScript::Latin].IsEsc() ) + SetProportion( pEsc->GetProportionalHeight() ); + } + if( const SvxCaseMapItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_CASEMAP ) ) + SetCaseMap( pItem->GetCaseMap() ); + if( const SvxKerningItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_KERNING ) ) + SetFixKerning( pItem->GetValue() ); + if( const SvxCharRotateItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_ROTATE ) ) + SetVertical( pItem->GetValue() ); + if( const SvxBrushItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_BACKGROUND ) ) + mxBackColor = pItem->GetColor(); + if( const SvxBrushItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_HIGHLIGHT ) ) + SetHighlightColor(pItem->GetColor()); + if( const SvxBoxItem* pBoxItem = pAttrSet->GetItemIfSet( RES_CHRATR_BOX ) ) + { + SetTopBorder(pBoxItem->GetTop()); + SetBottomBorder(pBoxItem->GetBottom()); + SetRightBorder(pBoxItem->GetRight()); + SetLeftBorder(pBoxItem->GetLeft()); + SetTopBorderDist(pBoxItem->GetDistance(SvxBoxItemLine::TOP)); + SetBottomBorderDist(pBoxItem->GetDistance(SvxBoxItemLine::BOTTOM)); + SetRightBorderDist(pBoxItem->GetDistance(SvxBoxItemLine::RIGHT)); + SetLeftBorderDist(pBoxItem->GetDistance(SvxBoxItemLine::LEFT)); + } + if( const SvxShadowItem* pShadowItem = pAttrSet->GetItemIfSet( RES_CHRATR_SHADOW ) ) + { + SetShadowColor(pShadowItem->GetColor()); + SetShadowWidth(pShadowItem->GetWidth()); + SetShadowLocation(pShadowItem->GetLocation()); + } + const SvxTwoLinesItem* pTwoLinesItem = pAttrSet->GetItemIfSet( RES_CHRATR_TWO_LINES ); + if( pTwoLinesItem && pTwoLinesItem->GetValue() ) + SetVertical( 0_deg10 ); + } + else + { + Invalidate(); + } + m_bPaintBlank = false; + OSL_ENSURE( m_aSub[SwFontScript::Latin].IsTransparent(), "SwFont: Transparent revolution" ); +} + +SwFont::SwFont( const SwFont &rFont ) + : m_aSub(rFont.m_aSub) +{ + m_nActual = rFont.m_nActual; + mxBackColor = rFont.mxBackColor; + m_aHighlightColor = rFont.m_aHighlightColor; + m_aTopBorder = rFont.m_aTopBorder; + m_aBottomBorder = rFont.m_aBottomBorder; + m_aRightBorder = rFont.m_aRightBorder; + m_aLeftBorder = rFont.m_aLeftBorder; + m_nTopBorderDist = rFont.m_nTopBorderDist; + m_nBottomBorderDist = rFont.m_nBottomBorderDist; + m_nRightBorderDist = rFont.m_nRightBorderDist; + m_nLeftBorderDist = rFont.m_nLeftBorderDist; + m_aShadowColor = rFont.m_aShadowColor; + m_nShadowWidth = rFont.m_nShadowWidth; + m_aShadowLocation = rFont.m_aShadowLocation; + m_aUnderColor = rFont.GetUnderColor(); + m_aOverColor = rFont.GetOverColor(); + m_nToxCount = 0; + m_nRefCount = 0; + m_nMetaCount = 0; + m_nContentControlCount = 0; + m_nInputFieldCount = 0; + m_bFontChg = rFont.m_bFontChg; + m_bOrgChg = rFont.m_bOrgChg; + m_bPaintBlank = rFont.m_bPaintBlank; + m_bGreyWave = rFont.m_bGreyWave; +} + +SwFont::SwFont( const SwAttrSet* pAttrSet, + const IDocumentSettingAccess* pIDocumentSettingAccess ) + : m_aSub() +{ + m_nActual = SwFontScript::Latin; + m_nToxCount = 0; + m_nRefCount = 0; + m_nMetaCount = 0; + m_nContentControlCount = 0; + m_nInputFieldCount = 0; + m_bPaintBlank = false; + m_bGreyWave = false; + m_bOrgChg = true; + { + const SvxFontItem& rFont = pAttrSet->GetFont(); + m_aSub[SwFontScript::Latin].SetFamily( rFont.GetFamily() ); + m_aSub[SwFontScript::Latin].SetFamilyName( rFont.GetFamilyName() ); + m_aSub[SwFontScript::Latin].SetStyleName( rFont.GetStyleName() ); + m_aSub[SwFontScript::Latin].SetPitch( rFont.GetPitch() ); + m_aSub[SwFontScript::Latin].SetCharSet( rFont.GetCharSet() ); + m_aSub[SwFontScript::Latin].SvxFont::SetPropr( 100 ); // 100% of FontSize + Size aTmpSize = m_aSub[SwFontScript::Latin].m_aSize; + aTmpSize.setHeight( pAttrSet->GetSize().GetHeight() ); + m_aSub[SwFontScript::Latin].SetSize( aTmpSize ); + m_aSub[SwFontScript::Latin].SetItalic( pAttrSet->GetPosture().GetPosture() ); + m_aSub[SwFontScript::Latin].SetWeight( pAttrSet->GetWeight().GetWeight() ); + m_aSub[SwFontScript::Latin].SetLanguage( pAttrSet->GetLanguage().GetLanguage() ); + } + + { + const SvxFontItem& rFont = pAttrSet->GetCJKFont(); + m_aSub[SwFontScript::CJK].SetFamily( rFont.GetFamily() ); + m_aSub[SwFontScript::CJK].SetFamilyName( rFont.GetFamilyName() ); + m_aSub[SwFontScript::CJK].SetStyleName( rFont.GetStyleName() ); + m_aSub[SwFontScript::CJK].SetPitch( rFont.GetPitch() ); + m_aSub[SwFontScript::CJK].SetCharSet( rFont.GetCharSet() ); + m_aSub[SwFontScript::CJK].SvxFont::SetPropr( 100 ); // 100% of FontSize + Size aTmpSize = m_aSub[SwFontScript::CJK].m_aSize; + aTmpSize.setHeight( pAttrSet->GetCJKSize().GetHeight() ); + m_aSub[SwFontScript::CJK].SetSize( aTmpSize ); + m_aSub[SwFontScript::CJK].SetItalic( pAttrSet->GetCJKPosture().GetPosture() ); + m_aSub[SwFontScript::CJK].SetWeight( pAttrSet->GetCJKWeight().GetWeight() ); + LanguageType eNewLang = pAttrSet->GetCJKLanguage().GetLanguage(); + m_aSub[SwFontScript::CJK].SetLanguage( eNewLang ); + m_aSub[SwFontScript::Latin].SetCJKContextLanguage( eNewLang ); + m_aSub[SwFontScript::CJK].SetCJKContextLanguage( eNewLang ); + m_aSub[SwFontScript::CTL].SetCJKContextLanguage( eNewLang ); + } + + { + const SvxFontItem& rFont = pAttrSet->GetCTLFont(); + m_aSub[SwFontScript::CTL].SetFamily( rFont.GetFamily() ); + m_aSub[SwFontScript::CTL].SetFamilyName( rFont.GetFamilyName() ); + m_aSub[SwFontScript::CTL].SetStyleName( rFont.GetStyleName() ); + m_aSub[SwFontScript::CTL].SetPitch( rFont.GetPitch() ); + m_aSub[SwFontScript::CTL].SetCharSet( rFont.GetCharSet() ); + m_aSub[SwFontScript::CTL].SvxFont::SetPropr( 100 ); // 100% of FontSize + Size aTmpSize = m_aSub[SwFontScript::CTL].m_aSize; + aTmpSize.setHeight( pAttrSet->GetCTLSize().GetHeight() ); + m_aSub[SwFontScript::CTL].SetSize( aTmpSize ); + m_aSub[SwFontScript::CTL].SetItalic( pAttrSet->GetCTLPosture().GetPosture() ); + m_aSub[SwFontScript::CTL].SetWeight( pAttrSet->GetCTLWeight().GetWeight() ); + m_aSub[SwFontScript::CTL].SetLanguage( pAttrSet->GetCTLLanguage().GetLanguage() ); + } + if ( pAttrSet->GetCharHidden().GetValue() ) + SetUnderline( LINESTYLE_DOTTED ); + else + SetUnderline( pAttrSet->GetUnderline().GetLineStyle() ); + SetUnderColor( pAttrSet->GetUnderline().GetColor() ); + SetOverline( pAttrSet->GetOverline().GetLineStyle() ); + SetOverColor( pAttrSet->GetOverline().GetColor() ); + SetEmphasisMark( pAttrSet->GetEmphasisMark().GetEmphasisMark() ); + SetStrikeout( pAttrSet->GetCrossedOut().GetStrikeout() ); + SetColor( pAttrSet->GetColor().GetValue() ); + SetTransparent( true ); + SetAlign( ALIGN_BASELINE ); + SetOutline( pAttrSet->GetContour().GetValue() ); + SetShadow( pAttrSet->GetShadowed().GetValue() ); + SetPropWidth( pAttrSet->GetCharScaleW().GetValue() ); + SetRelief( pAttrSet->GetCharRelief().GetValue() ); + if( pAttrSet->GetAutoKern().GetValue() ) + { + SetAutoKern( ( !pIDocumentSettingAccess || + !pIDocumentSettingAccess->get(DocumentSettingId::KERN_ASIAN_PUNCTUATION) ) ? + FontKerning::FontSpecific : + FontKerning::Asian ); + } + else + SetAutoKern( FontKerning::NONE ); + SetWordLineMode( pAttrSet->GetWordLineMode().GetValue() ); + const SvxEscapementItem &rEsc = pAttrSet->GetEscapement(); + SetEscapement( rEsc.GetEsc() ); + if( m_aSub[SwFontScript::Latin].IsEsc() ) + SetProportion( rEsc.GetProportionalHeight() ); + SetCaseMap( pAttrSet->GetCaseMap().GetCaseMap() ); + SetFixKerning( pAttrSet->GetKerning().GetValue() ); + if( const SvxBrushItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_BACKGROUND ) ) + mxBackColor = pItem->GetColor(); + if( const SvxBrushItem* pItem = pAttrSet->GetItemIfSet( RES_CHRATR_HIGHLIGHT ) ) + SetHighlightColor(pItem->GetColor()); + else + SetHighlightColor(COL_TRANSPARENT); + if( const SvxBoxItem* pBoxItem = pAttrSet->GetItemIfSet( RES_CHRATR_BOX ) ) + { + SetTopBorder(pBoxItem->GetTop()); + SetBottomBorder(pBoxItem->GetBottom()); + SetRightBorder(pBoxItem->GetRight()); + SetLeftBorder(pBoxItem->GetLeft()); + SetTopBorderDist(pBoxItem->GetDistance(SvxBoxItemLine::TOP)); + SetBottomBorderDist(pBoxItem->GetDistance(SvxBoxItemLine::BOTTOM)); + SetRightBorderDist(pBoxItem->GetDistance(SvxBoxItemLine::RIGHT)); + SetLeftBorderDist(pBoxItem->GetDistance(SvxBoxItemLine::LEFT)); + } + else + { + SetTopBorder(nullptr); + SetBottomBorder(nullptr); + SetRightBorder(nullptr); + SetLeftBorder(nullptr); + SetTopBorderDist(0); + SetBottomBorderDist(0); + SetRightBorderDist(0); + SetLeftBorderDist(0); + } + + if( const SvxShadowItem* pShadowItem = pAttrSet->GetItemIfSet( RES_CHRATR_SHADOW ) ) + { + SetShadowColor(pShadowItem->GetColor()); + SetShadowWidth(pShadowItem->GetWidth()); + SetShadowLocation(pShadowItem->GetLocation()); + } + else + { + SetShadowColor(COL_TRANSPARENT); + SetShadowWidth(0); + SetShadowLocation(SvxShadowLocation::NONE); + } + + const SvxTwoLinesItem& rTwoLinesItem = pAttrSet->Get2Lines(); + if ( ! rTwoLinesItem.GetValue() ) + SetVertical( pAttrSet->GetCharRotate().GetValue() ); + else + SetVertical( 0_deg10 ); + if( pIDocumentSettingAccess && pIDocumentSettingAccess->get( DocumentSettingId::SMALL_CAPS_PERCENTAGE_66 )) + { + m_aSub[ SwFontScript::Latin ].m_bSmallCapsPercentage66 = true; + m_aSub[ SwFontScript::CJK ].m_bSmallCapsPercentage66 = true; + m_aSub[ SwFontScript::CTL ].m_bSmallCapsPercentage66 = true; + } +} + +SwFont::~SwFont() +{ +} + +SwFont& SwFont::operator=( const SwFont &rFont ) +{ + if (this != &rFont) + { + m_aSub[SwFontScript::Latin] = rFont.m_aSub[SwFontScript::Latin]; + m_aSub[SwFontScript::CJK] = rFont.m_aSub[SwFontScript::CJK]; + m_aSub[SwFontScript::CTL] = rFont.m_aSub[SwFontScript::CTL]; + m_nActual = rFont.m_nActual; + mxBackColor = rFont.mxBackColor; + m_aHighlightColor = rFont.m_aHighlightColor; + m_aTopBorder = rFont.m_aTopBorder; + m_aBottomBorder = rFont.m_aBottomBorder; + m_aRightBorder = rFont.m_aRightBorder; + m_aLeftBorder = rFont.m_aLeftBorder; + m_nTopBorderDist = rFont.m_nTopBorderDist; + m_nBottomBorderDist = rFont.m_nBottomBorderDist; + m_nRightBorderDist = rFont.m_nRightBorderDist; + m_nLeftBorderDist = rFont.m_nLeftBorderDist; + m_aShadowColor = rFont.m_aShadowColor; + m_nShadowWidth = rFont.m_nShadowWidth; + m_aShadowLocation = rFont.m_aShadowLocation; + m_aUnderColor = rFont.GetUnderColor(); + m_aOverColor = rFont.GetOverColor(); + m_nToxCount = 0; + m_nRefCount = 0; + m_nMetaCount = 0; + m_nContentControlCount = 0; + m_nInputFieldCount = 0; + m_bFontChg = rFont.m_bFontChg; + m_bOrgChg = rFont.m_bOrgChg; + m_bPaintBlank = rFont.m_bPaintBlank; + m_bGreyWave = rFont.m_bGreyWave; + } + return *this; +} + +void SwFont::AllocFontCacheId( SwViewShell const *pSh, SwFontScript nWhich ) +{ + SwFntAccess aFntAccess( m_aSub[nWhich].m_nFontCacheId, m_aSub[nWhich].m_nFontIndex, + &m_aSub[nWhich], pSh, true ); +} + +bool SwSubFont::IsSymbol( SwViewShell const *pSh ) +{ + SwFntAccess aFntAccess( m_nFontCacheId, m_nFontIndex, this, pSh, false ); + return aFntAccess.Get()->IsSymbol(); +} + +bool SwSubFont::ChgFnt( SwViewShell const *pSh, OutputDevice& rOut ) +{ + if ( pLastFont ) + pLastFont->Unlock(); + SwFntAccess aFntAccess( m_nFontCacheId, m_nFontIndex, this, pSh, true ); + SV_STAT( nChangeFont ); + + pLastFont = aFntAccess.Get(); + + pLastFont->SetDevFont( pSh, rOut ); + + pLastFont->Lock(); + return LINESTYLE_NONE != GetUnderline() || + LINESTYLE_NONE != GetOverline() || + STRIKEOUT_NONE != GetStrikeout(); +} + +void SwFont::ChgPhysFnt( SwViewShell const *pSh, OutputDevice& rOut ) +{ + if( m_bOrgChg && m_aSub[m_nActual].IsEsc() ) + { + const sal_uInt8 nOldProp = m_aSub[m_nActual].GetPropr(); + SetProportion( 100 ); + ChgFnt( pSh, rOut ); + SwFntAccess aFntAccess( m_aSub[m_nActual].m_nFontCacheId, m_aSub[m_nActual].m_nFontIndex, + &m_aSub[m_nActual], pSh ); + m_aSub[m_nActual].m_nOrgHeight = aFntAccess.Get()->GetFontHeight( pSh, rOut ); + m_aSub[m_nActual].m_nOrgAscent = aFntAccess.Get()->GetFontAscent( pSh, rOut ); + SetProportion( nOldProp ); + m_bOrgChg = false; + } + + if( m_bFontChg ) + { + ChgFnt( pSh, rOut ); + m_bFontChg = m_bOrgChg; + } + if( rOut.GetTextLineColor() != m_aUnderColor ) + rOut.SetTextLineColor( m_aUnderColor ); + if( rOut.GetOverlineColor() != m_aOverColor ) + rOut.SetOverlineColor( m_aOverColor ); +} + +// Height = MaxAscent + MaxDescent +// MaxAscent = Max (T1_ascent, T2_ascent + (Esc * T1_height) ); +// MaxDescent = Max (T1_height-T1_ascent, +// T2_height-T2_ascent - (Esc * T1_height) +sal_uInt16 SwSubFont::CalcEscHeight( const sal_uInt16 nOldHeight, + const sal_uInt16 nOldAscent ) const +{ + if( DFLT_ESC_AUTO_SUPER != GetEscapement() && + DFLT_ESC_AUTO_SUB != GetEscapement() ) + { + tools::Long nDescent = nOldHeight - nOldAscent - + ( static_cast<tools::Long>(m_nOrgHeight) * GetEscapement() ) / 100; + const sal_uInt16 nDesc = nDescent>0 + ? std::max<sal_uInt16>( nDescent, m_nOrgHeight - m_nOrgAscent) + : m_nOrgHeight - m_nOrgAscent; + return ( nDesc + CalcEscAscent( nOldAscent ) ); + } + return m_nOrgHeight; +} + +short SwSubFont::CheckKerning_( ) +{ + short nKernx = - short( Font::GetFontSize().Height() / 6 ); + + if ( nKernx < GetFixKerning() ) + return GetFixKerning(); + return nKernx; +} + +sal_uInt16 SwSubFont::GetAscent( SwViewShell const *pSh, const OutputDevice& rOut ) +{ + SwFntAccess aFntAccess( m_nFontCacheId, m_nFontIndex, this, pSh ); + const sal_uInt16 nAscent = aFntAccess.Get()->GetFontAscent( pSh, rOut ); + return GetEscapement() ? CalcEscAscent( nAscent ) : nAscent; +} + +sal_uInt16 SwSubFont::GetHeight( SwViewShell const *pSh, const OutputDevice& rOut ) +{ + SV_STAT( nGetTextSize ); + SwFntAccess aFntAccess( m_nFontCacheId, m_nFontIndex, this, pSh ); + const sal_uInt16 nHeight = aFntAccess.Get()->GetFontHeight( pSh, rOut ); + if ( GetEscapement() ) + { + const sal_uInt16 nAscent = aFntAccess.Get()->GetFontAscent( pSh, rOut ); + return CalcEscHeight( nHeight, nAscent ); // + nLeading; + } + return nHeight; // + nLeading; +} + +sal_uInt16 SwSubFont::GetHangingBaseline( SwViewShell const *pSh, const OutputDevice& rOut ) +{ + SwFntAccess aFntAccess( m_nFontCacheId, m_nFontIndex, this, pSh ); + return aFntAccess.Get()->GetFontHangingBaseline( pSh, rOut ); +} + +Size SwSubFont::GetTextSize_( SwDrawTextInfo& rInf ) +{ + // Robust: the font is supposed to be set already, but better safe than + // sorry... + if ( !pLastFont || pLastFont->GetOwner() != m_nFontCacheId || + !IsSameInstance( rInf.GetpOut()->GetFont() ) ) + ChgFnt( rInf.GetShell(), rInf.GetOut() ); + + SwDigitModeModifier aDigitModeModifier( rInf.GetOut(), rInf.GetFont()->GetLanguage() ); + + Size aTextSize; + TextFrameIndex const nLn = rInf.GetLen() == TextFrameIndex(COMPLETE_STRING) + ? TextFrameIndex(rInf.GetText().getLength()) + : rInf.GetLen(); + rInf.SetLen( nLn ); + if( IsCapital() && nLn ) + aTextSize = GetCapitalSize( rInf ); + else + { + SV_STAT( nGetTextSize ); + tools::Long nOldKern = rInf.GetKern(); + const OUString oldText = rInf.GetText(); + rInf.SetKern( CheckKerning() ); + if ( !IsCaseMap() ) + aTextSize = pLastFont->GetTextSize( rInf ); + else + { + const OUString aTmp = CalcCaseMap( rInf.GetText() ); + const OUString oldStr = rInf.GetText(); + bool bCaseMapLengthDiffers(aTmp.getLength() != oldStr.getLength()); + + if(bCaseMapLengthDiffers && rInf.GetLen()) + { + // If the length of the original string and the CaseMapped one + // are different, it is necessary to handle the given text part as + // a single snippet since its size may differ, too. + TextFrameIndex const nOldIdx(rInf.GetIdx()); + TextFrameIndex const nOldLen(rInf.GetLen()); + const OUString aSnippet(oldStr.copy(sal_Int32(nOldIdx), sal_Int32(nOldLen))); + const OUString aNewText(CalcCaseMap(aSnippet)); + + rInf.SetText( aNewText ); + rInf.SetIdx( TextFrameIndex(0) ); + rInf.SetLen( TextFrameIndex(aNewText.getLength()) ); + + aTextSize = pLastFont->GetTextSize( rInf ); + + rInf.SetIdx( nOldIdx ); + rInf.SetLen( nOldLen ); + } + else + { + rInf.SetText( aTmp ); + aTextSize = pLastFont->GetTextSize( rInf ); + } + + rInf.SetText(oldStr); + } + rInf.SetKern( nOldKern ); + rInf.SetText(oldText); + // A word that's longer than one line, with escapement at the line + // break, must report its effective height. + if( GetEscapement() ) + { + const sal_uInt16 nAscent = pLastFont->GetFontAscent( rInf.GetShell(), + rInf.GetOut() ); + aTextSize.setHeight( + static_cast<tools::Long>(CalcEscHeight( o3tl::narrowing<sal_uInt16>(aTextSize.Height()), nAscent)) ); + } + } + + if (TextFrameIndex(1) == rInf.GetLen() + && CH_TXT_ATR_FIELDSTART == rInf.GetText()[sal_Int32(rInf.GetIdx())]) + { + assert(!"this is presumably dead code"); + TextFrameIndex const nOldIdx(rInf.GetIdx()); + TextFrameIndex const nOldLen(rInf.GetLen()); + const OUString aNewText(CH_TXT_ATR_SUBST_FIELDSTART); + rInf.SetText( aNewText ); + rInf.SetIdx( TextFrameIndex(0) ); + rInf.SetLen( TextFrameIndex(aNewText.getLength()) ); + aTextSize = pLastFont->GetTextSize( rInf ); + rInf.SetIdx( nOldIdx ); + rInf.SetLen( nOldLen ); + } + else if (TextFrameIndex(1) == rInf.GetLen() + && CH_TXT_ATR_FIELDEND == rInf.GetText()[sal_Int32(rInf.GetIdx())]) + { + assert(!"this is presumably dead code"); + TextFrameIndex const nOldIdx(rInf.GetIdx()); + TextFrameIndex const nOldLen(rInf.GetLen()); + const OUString aNewText(CH_TXT_ATR_SUBST_FIELDEND); + rInf.SetText( aNewText ); + rInf.SetIdx( TextFrameIndex(0) ); + rInf.SetLen( TextFrameIndex(aNewText.getLength()) ); + aTextSize = pLastFont->GetTextSize( rInf ); + rInf.SetIdx( nOldIdx ); + rInf.SetLen( nOldLen ); + } + + return aTextSize; +} + +void SwSubFont::DrawText_( SwDrawTextInfo &rInf, const bool bGrey ) +{ + rInf.SetGreyWave( bGrey ); + TextFrameIndex const nLn(rInf.GetText().getLength()); + if( !rInf.GetLen() || !nLn ) + return; + if (TextFrameIndex(COMPLETE_STRING) == rInf.GetLen()) + rInf.SetLen( nLn ); + + FontLineStyle nOldUnder = LINESTYLE_NONE; + SwUnderlineFont* pUnderFnt = nullptr; + + if( rInf.GetUnderFnt() ) + { + nOldUnder = GetUnderline(); + SetUnderline( LINESTYLE_NONE ); + pUnderFnt = rInf.GetUnderFnt(); + } + + if( !pLastFont || pLastFont->GetOwner() != m_nFontCacheId ) + ChgFnt( rInf.GetShell(), rInf.GetOut() ); + + SwDigitModeModifier aDigitModeModifier( rInf.GetOut(), rInf.GetFont()->GetLanguage() ); + + const Point aOldPos(rInf.GetPos()); + Point aPos( rInf.GetPos() ); + + if( GetEscapement() ) + CalcEsc( rInf, aPos ); + + rInf.SetPos( aPos ); + rInf.SetKern( CheckKerning() + rInf.GetCharacterSpacing() / SPACING_PRECISION_FACTOR ); + + if( IsCapital() ) + DrawCapital( rInf ); + else + { + SV_STAT( nDrawText ); + if ( !IsCaseMap() ) + pLastFont->DrawText( rInf ); + else + { + const OUString oldStr = rInf.GetText(); + const OUString aString( CalcCaseMap(oldStr) ); + bool bCaseMapLengthDiffers(aString.getLength() != oldStr.getLength()); + + if(bCaseMapLengthDiffers && rInf.GetLen()) + { + // If the length of the original string and the CaseMapped one + // are different, it is necessary to handle the given text part as + // a single snippet since its size may differ, too. + TextFrameIndex const nOldIdx(rInf.GetIdx()); + TextFrameIndex const nOldLen(rInf.GetLen()); + const OUString aSnippet(oldStr.copy(sal_Int32(nOldIdx), sal_Int32(nOldLen))); + const OUString aNewText = CalcCaseMap(aSnippet); + + rInf.SetText( aNewText ); + rInf.SetIdx( TextFrameIndex(0) ); + rInf.SetLen( TextFrameIndex(aNewText.getLength()) ); + + pLastFont->DrawText( rInf ); + + rInf.SetIdx( nOldIdx ); + rInf.SetLen( nOldLen ); + } + else + { + rInf.SetText( aString ); + pLastFont->DrawText( rInf ); + } + + rInf.SetText(oldStr); + } + } + + if( pUnderFnt && nOldUnder != LINESTYLE_NONE ) + { + Size aFontSize = GetTextSize_( rInf ); + const OUString oldStr = rInf.GetText(); + + TextFrameIndex const nOldIdx = rInf.GetIdx(); + TextFrameIndex const nOldLen = rInf.GetLen(); + tools::Long nSpace = 0; + if( rInf.GetSpace() ) + { + TextFrameIndex nTmpEnd = nOldIdx + nOldLen; + if (nTmpEnd > TextFrameIndex(oldStr.getLength())) + nTmpEnd = TextFrameIndex(oldStr.getLength()); + + const SwScriptInfo* pSI = rInf.GetScriptInfo(); + + const bool bAsianFont = + ( rInf.GetFont() && SwFontScript::CJK == rInf.GetFont()->GetActual() ); + for (TextFrameIndex nTmp = nOldIdx; nTmp < nTmpEnd; ++nTmp) + { + if (CH_BLANK == oldStr[sal_Int32(nTmp)] || bAsianFont || + (nTmp + TextFrameIndex(1) < TextFrameIndex(oldStr.getLength()) + && pSI + && i18n::ScriptType::ASIAN == pSI->ScriptType(nTmp + TextFrameIndex(1)))) + { + ++nSpace; + } + } + + // if next portion if a hole portion we do not consider any + // extra space added because the last character was ASIAN + if ( nSpace && rInf.IsSpaceStop() && bAsianFont ) + --nSpace; + + nSpace *= rInf.GetSpace() / SPACING_PRECISION_FACTOR; + } + + rInf.SetWidth( sal_uInt16(aFontSize.Width() + nSpace) ); + rInf.SetTextIdxLen( " ", TextFrameIndex(0), TextFrameIndex(2) ); + SetUnderline( nOldUnder ); + rInf.SetUnderFnt( nullptr ); + + // set position for underline font + rInf.SetPos( pUnderFnt->GetPos() ); + + pUnderFnt->GetFont().DrawStretchText_( rInf ); + + rInf.SetUnderFnt( pUnderFnt ); + rInf.SetTextIdxLen(oldStr, nOldIdx, nOldLen); + } + + rInf.SetPos(aOldPos); +} + +void SwSubFont::DrawStretchText_( SwDrawTextInfo &rInf ) +{ + if( !rInf.GetLen() || !rInf.GetText().getLength() ) + return; + + FontLineStyle nOldUnder = LINESTYLE_NONE; + SwUnderlineFont* pUnderFnt = nullptr; + + if( rInf.GetUnderFnt() ) + { + nOldUnder = GetUnderline(); + SetUnderline( LINESTYLE_NONE ); + pUnderFnt = rInf.GetUnderFnt(); + } + + if ( !pLastFont || pLastFont->GetOwner() != m_nFontCacheId ) + ChgFnt( rInf.GetShell(), rInf.GetOut() ); + + SwDigitModeModifier aDigitModeModifier( rInf.GetOut(), rInf.GetFont()->GetLanguage() ); + + rInf.ApplyAutoColor(); + + const Point aOldPos(rInf.GetPos()); + Point aPos( rInf.GetPos() ); + + if( GetEscapement() ) + CalcEsc( rInf, aPos ); + + rInf.SetKern( CheckKerning() + rInf.GetCharacterSpacing() / SPACING_PRECISION_FACTOR ); + rInf.SetPos( aPos ); + + if( IsCapital() ) + DrawStretchCapital( rInf ); + else + { + SV_STAT( nDrawStretchText ); + + if ( rInf.GetFrame() ) + { + if ( rInf.GetFrame()->IsRightToLeft() ) + rInf.GetFrame()->SwitchLTRtoRTL( aPos ); + + if ( rInf.GetFrame()->IsVertical() ) + rInf.GetFrame()->SwitchHorizontalToVertical( aPos ); + + rInf.SetPos( aPos ); + } + + if ( !IsCaseMap() ) + rInf.GetOut().DrawStretchText( aPos, rInf.GetWidth(), + rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); + else + rInf.GetOut().DrawStretchText( aPos, rInf.GetWidth(), + CalcCaseMap(rInf.GetText()), + sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); + } + + if( pUnderFnt && nOldUnder != LINESTYLE_NONE ) + { + const OUString oldStr = rInf.GetText(); + TextFrameIndex const nOldIdx = rInf.GetIdx(); + TextFrameIndex const nOldLen = rInf.GetLen(); + rInf.SetTextIdxLen( " ", TextFrameIndex(0), TextFrameIndex(2) ); + SetUnderline( nOldUnder ); + rInf.SetUnderFnt( nullptr ); + + // set position for underline font + rInf.SetPos( pUnderFnt->GetPos() ); + + pUnderFnt->GetFont().DrawStretchText_( rInf ); + + rInf.SetUnderFnt( pUnderFnt ); + rInf.SetTextIdxLen(oldStr, nOldIdx, nOldLen); + } + + rInf.SetPos(aOldPos); +} + +TextFrameIndex SwSubFont::GetModelPositionForViewPoint_( SwDrawTextInfo& rInf ) +{ + if ( !pLastFont || pLastFont->GetOwner() != m_nFontCacheId ) + ChgFnt( rInf.GetShell(), rInf.GetOut() ); + + SwDigitModeModifier aDigitModeModifier( rInf.GetOut(), rInf.GetFont()->GetLanguage() ); + + TextFrameIndex const nLn = rInf.GetLen() == TextFrameIndex(COMPLETE_STRING) + ? TextFrameIndex(rInf.GetText().getLength()) + : rInf.GetLen(); + rInf.SetLen( nLn ); + TextFrameIndex nCursor(0); + if( IsCapital() && nLn ) + nCursor = GetCapitalCursorOfst( rInf ); + else + { + const OUString oldText = rInf.GetText(); + tools::Long nOldKern = rInf.GetKern(); + rInf.SetKern( CheckKerning() ); + SV_STAT( nGetTextSize ); + if ( !IsCaseMap() ) + nCursor = pLastFont->GetModelPositionForViewPoint( rInf ); + else + { + rInf.SetText( CalcCaseMap( rInf.GetText() ) ); + nCursor = pLastFont->GetModelPositionForViewPoint( rInf ); + } + rInf.SetKern( nOldKern ); + rInf.SetText(oldText); + } + return nCursor; +} + +void SwSubFont::CalcEsc( SwDrawTextInfo const & rInf, Point& rPos ) +{ + tools::Long nOfst; + + bool bVert = false; + bool bVertLRBT = false; + if (rInf.GetFrame()) + { + bVert = rInf.GetFrame()->IsVertical(); + bVertLRBT = rInf.GetFrame()->IsVertLRBT(); + } + const Degree10 nDir = UnMapDirection(GetOrientation(), bVert, bVertLRBT); + + switch ( GetEscapement() ) + { + case DFLT_ESC_AUTO_SUB : + nOfst = m_nOrgHeight - m_nOrgAscent - + pLastFont->GetFontHeight( rInf.GetShell(), rInf.GetOut() ) + + pLastFont->GetFontAscent( rInf.GetShell(), rInf.GetOut() ); + + switch ( nDir.get() ) + { + case 0 : + rPos.AdjustY(nOfst ); + break; + case 900 : + rPos.AdjustX(nOfst ); + break; + case 2700 : + rPos.AdjustX( -nOfst ); + break; + } + + break; + case DFLT_ESC_AUTO_SUPER : + nOfst = pLastFont->GetFontAscent( rInf.GetShell(), rInf.GetOut() ) - + m_nOrgAscent; + + switch ( nDir.get() ) + { + case 0 : + rPos.AdjustY(nOfst ); + break; + case 900 : + rPos.AdjustX(nOfst ); + break; + case 2700 : + rPos.AdjustX( -nOfst ); + break; + } + + break; + default : + nOfst = (static_cast<tools::Long>(m_nOrgHeight) * GetEscapement()) / 100; + + switch ( nDir.get() ) + { + case 0 : + rPos.AdjustY( -nOfst ); + break; + case 900 : + rPos.AdjustX( -nOfst ); + break; + case 2700 : + rPos.AdjustX(nOfst ); + break; + } + } +} + +// used during painting of small capitals +void SwDrawTextInfo::Shift( Degree10 nDir ) +{ +#ifdef DBG_UTIL + OSL_ENSURE( m_bPos, "DrawTextInfo: Undefined Position" ); + OSL_ENSURE( m_bSize, "DrawTextInfo: Undefined Width" ); +#endif + + const bool bBidiPor = ( GetFrame() && GetFrame()->IsRightToLeft() ) != + ( vcl::text::ComplexTextLayoutFlags::Default != ( vcl::text::ComplexTextLayoutFlags::BiDiRtl & GetpOut()->GetLayoutMode() ) ); + + bool bVert = false; + bool bVertLRBT = false; + if (GetFrame()) + { + bVert = GetFrame()->IsVertical(); + bVertLRBT = GetFrame()->IsVertLRBT(); + } + nDir = bBidiPor ? 1800_deg10 : UnMapDirection(nDir, bVert, bVertLRBT); + + switch ( nDir.get() ) + { + case 0 : + m_aPos.AdjustX(GetSize().Width() ); + break; + case 900 : + OSL_ENSURE( m_aPos.Y() >= GetSize().Width(), "Going underground" ); + m_aPos.AdjustY( -(GetSize().Width()) ); + break; + case 1800 : + m_aPos.AdjustX( -(GetSize().Width()) ); + break; + case 2700 : + m_aPos.AdjustY(GetSize().Width() ); + break; + } +} + +/** + * @note Used for the "continuous underline" feature. + **/ +SwUnderlineFont::SwUnderlineFont(SwFont& rFnt, TextFrameIndex const nEnd, const Point& rPoint) + : m_aPos( rPoint ), m_nEnd( nEnd ), m_pFont( &rFnt ) +{ +}; + +SwUnderlineFont::~SwUnderlineFont() +{ +} + +/// Helper for filters to find true lineheight of a font +tools::Long AttrSetToLineHeight( const IDocumentSettingAccess& rIDocumentSettingAccess, + const SwAttrSet &rSet, + const vcl::RenderContext &rOut, sal_Int16 nScript) +{ + SwFont aFont(&rSet, &rIDocumentSettingAccess); + SwFontScript nActual; + switch (nScript) + { + default: + case i18n::ScriptType::LATIN: + nActual = SwFontScript::Latin; + break; + case i18n::ScriptType::ASIAN: + nActual = SwFontScript::CJK; + break; + case i18n::ScriptType::COMPLEX: + nActual = SwFontScript::CTL; + break; + } + aFont.SetActual(nActual); + + vcl::RenderContext &rMutableOut = const_cast<vcl::RenderContext &>(rOut); + const vcl::Font aOldFont(rMutableOut.GetFont()); + + rMutableOut.SetFont(aFont.GetActualFont()); + tools::Long nHeight = rMutableOut.GetTextHeight(); + + rMutableOut.SetFont(aOldFont); + return nHeight; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |