diff options
Diffstat (limited to 'svx/source/styles/CommonStylePreviewRenderer.cxx')
-rw-r--r-- | svx/source/styles/CommonStylePreviewRenderer.cxx | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/svx/source/styles/CommonStylePreviewRenderer.cxx b/svx/source/styles/CommonStylePreviewRenderer.cxx new file mode 100644 index 0000000000..d92aac21d8 --- /dev/null +++ b/svx/source/styles/CommonStylePreviewRenderer.cxx @@ -0,0 +1,431 @@ +/* -*- 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/. + * + */ + +#include <memory> +#include <CommonStylePreviewRenderer.hxx> + +#include <sfx2/objsh.hxx> +#include <svl/style.hxx> +#include <svl/itemset.hxx> +#include <svl/itempool.hxx> +#include <vcl/metric.hxx> +#include <vcl/outdev.hxx> + +#include <com/sun/star/drawing/FillStyle.hpp> +#include <svx/xdef.hxx> +#include <svx/xfillit0.hxx> +#include <svx/xflclit.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/contouritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/editeng.hxx> +#include <editeng/emphasismarkitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/svxfont.hxx> +#include <editeng/cmapitem.hxx> + +#include <editeng/editids.hrc> + +using namespace css; + +namespace svx +{ + +CommonStylePreviewRenderer::CommonStylePreviewRenderer( + const SfxObjectShell& rShell, OutputDevice& rOutputDev, + SfxStyleSheetBase* pStyle, tools::Long nMaxHeight) + : StylePreviewRenderer(rShell, rOutputDev, pStyle, nMaxHeight) + , maFontColor(COL_AUTO) + , maHighlightColor(COL_AUTO) + , maBackgroundColor(COL_AUTO) + , mnHeight(0) + , mnBaseLine(0) + , maStyleName(mpStyle->GetName()) +{ +} + +CommonStylePreviewRenderer::~CommonStylePreviewRenderer() +{} + +static bool GetWhich(const SfxItemSet& rSet, sal_uInt16 nSlot, sal_uInt16& rWhich) +{ + rWhich = rSet.GetPool()->GetWhich(nSlot); + return rSet.GetItemState(rWhich) >= SfxItemState::DEFAULT; +} + +static bool SetFont(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont) +{ + sal_uInt16 nWhich; + if (GetWhich(rSet, nSlot, nWhich)) + { + const auto& rFontItem = static_cast<const SvxFontItem&>(rSet.Get(nWhich)); + rFont.SetFamily(rFontItem.GetFamily()); + rFont.SetFamilyName(rFontItem.GetFamilyName()); + rFont.SetPitch(rFontItem.GetPitch()); + rFont.SetCharSet(rFontItem.GetCharSet()); + rFont.SetStyleName(rFontItem.GetStyleName()); + rFont.SetAlignment(ALIGN_BASELINE); + return true; + } + return false; +} + +bool CommonStylePreviewRenderer::SetFontSize(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont) +{ + sal_uInt16 nWhich; + if (GetWhich(rSet, nSlot, nWhich)) + { + const auto& rFontHeightItem = static_cast<const SvxFontHeightItem&>(rSet.Get(nWhich)); + Size aFontSize(0, rFontHeightItem.GetHeight()); + aFontSize = mrOutputDev.LogicToPixel(aFontSize, MapMode(mrShell.GetMapUnit())); + rFont.SetFontSize(aFontSize); + mrOutputDev.SetFont(rFont); + FontMetric aMetric(mrOutputDev.GetFontMetric()); + return true; + } + return false; +} + +bool CommonStylePreviewRenderer::recalculate() +{ + m_oFont.reset(); + m_oCJKFont.reset(); + m_oCTLFont.reset(); + + std::optional<SfxItemSet> pItemSet(mpStyle->GetItemSetForPreview()); + + if (!pItemSet) return false; + + SvxFont aFont; + SvxFont aCJKFont; + SvxFont aCTLFont; + + const SfxPoolItem* pItem; + + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_WEIGHT)) != nullptr) + aFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight()); + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CJK_WEIGHT)) != nullptr) + aCJKFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight()); + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CTL_WEIGHT)) != nullptr) + aCTLFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight()); + + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_POSTURE)) != nullptr) + aFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture()); + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CJK_POSTURE)) != nullptr) + aCJKFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture()); + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CTL_POSTURE)) != nullptr) + aCTLFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture()); + + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CONTOUR)) != nullptr) + { + auto aVal = static_cast<const SvxContourItem*>(pItem)->GetValue(); + aFont.SetOutline(aVal); + aCJKFont.SetOutline(aVal); + aCTLFont.SetOutline(aVal); + } + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_SHADOWED)) != nullptr) + { + auto aVal = static_cast<const SvxShadowedItem*>(pItem)->GetValue(); + aFont.SetShadow(aVal); + aCJKFont.SetShadow(aVal); + aCTLFont.SetShadow(aVal); + } + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_RELIEF)) != nullptr) + { + auto aVal = static_cast<const SvxCharReliefItem*>(pItem)->GetValue(); + aFont.SetRelief(aVal); + aCJKFont.SetRelief(aVal); + aCTLFont.SetRelief(aVal); + } + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_UNDERLINE)) != nullptr) + { + auto aVal = static_cast<const SvxUnderlineItem*>(pItem)->GetLineStyle(); + aFont.SetUnderline(aVal); + aCJKFont.SetUnderline(aVal); + aCTLFont.SetUnderline(aVal); + } + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_OVERLINE)) != nullptr) + { + auto aVal = static_cast<const SvxOverlineItem*>(pItem)->GetValue(); + aFont.SetOverline(aVal); + aCJKFont.SetOverline(aVal); + aCTLFont.SetOverline(aVal); + } + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_STRIKEOUT)) != nullptr) + { + auto aVal = static_cast<const SvxCrossedOutItem*>(pItem)->GetStrikeout(); + aFont.SetStrikeout(aVal); + aCJKFont.SetStrikeout(aVal); + aCTLFont.SetStrikeout(aVal); + } + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CASEMAP)) != nullptr) + { + auto aVal = static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap(); + aFont.SetCaseMap(aVal); + aCJKFont.SetCaseMap(aVal); + aCTLFont.SetCaseMap(aVal); + } + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_EMPHASISMARK)) != nullptr) + { + auto aVal = static_cast<const SvxEmphasisMarkItem*>(pItem)->GetEmphasisMark(); + aFont.SetEmphasisMark(aVal); + aCJKFont.SetEmphasisMark(aVal); + aCTLFont.SetEmphasisMark(aVal); + } + if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_COLOR)) != nullptr) + { + maFontColor = static_cast<const SvxColorItem*>(pItem)->GetValue(); + } + if ((pItem = pItemSet->GetItem(SID_ATTR_BRUSH_CHAR)) != nullptr) + { + maHighlightColor = static_cast<const SvxBrushItem*>(pItem)->GetColor(); + } + + if (mpStyle->GetFamily() == SfxStyleFamily::Para) + { + if ((pItem = pItemSet->GetItem(XATTR_FILLSTYLE)) != nullptr) + { + css::drawing::FillStyle aFillStyle = static_cast<const XFillStyleItem*>(pItem)->GetValue(); + if (aFillStyle == drawing::FillStyle_SOLID) + { + if ((pItem = pItemSet->GetItem(XATTR_FILLCOLOR)) != nullptr) + { + maBackgroundColor = static_cast<const XFillColorItem*>(pItem)->GetColorValue(); + } + } + } + } + + if (SetFont(*pItemSet, SID_ATTR_CHAR_FONT, aFont) && + SetFontSize(*pItemSet, SID_ATTR_CHAR_FONTHEIGHT, aFont)) + m_oFont = aFont; + + if (SetFont(*pItemSet, SID_ATTR_CHAR_CJK_FONT, aCJKFont) && + SetFontSize(*pItemSet, SID_ATTR_CHAR_CJK_FONTHEIGHT, aCJKFont)) + m_oCJKFont = aCJKFont; + + if (SetFont(*pItemSet, SID_ATTR_CHAR_CTL_FONT, aCTLFont) && + SetFontSize(*pItemSet, SID_ATTR_CHAR_CTL_FONTHEIGHT, aCTLFont)) + m_oCTLFont = aCTLFont; + + CheckScript(); + CalcRenderSize(); + return true; +} + +void CommonStylePreviewRenderer::CalcRenderSize() +{ + const OUString& rText = maStyleName; + + mnBaseLine = 0; + mnHeight = 0; + SvtScriptType aScript; + sal_uInt16 nIdx = 0; + sal_Int32 nStart = 0; + sal_Int32 nEnd; + size_t nCnt = maScriptChanges.size(); + + if (nCnt) + { + nEnd = maScriptChanges[nIdx].changePos; + aScript = maScriptChanges[nIdx].scriptType; + } + else + { + nEnd = rText.getLength(); + aScript = SvtScriptType::LATIN; + } + + do + { + auto oFont = (aScript == SvtScriptType::ASIAN) ? + m_oCJKFont : + ((aScript == SvtScriptType::COMPLEX) ? + m_oCTLFont : + m_oFont); + + mrOutputDev.Push(vcl::PushFlags::FONT); + + tools::Long nWidth; + if (oFont) + { + mrOutputDev.SetFont(*oFont); + nWidth = oFont->GetTextSize(mrOutputDev, rText, nStart, nEnd - nStart).Width(); + } + else + nWidth = mrOutputDev.GetTextWidth(rText, nStart, nEnd - nStart); + + tools::Rectangle aRect; + mrOutputDev.GetTextBoundRect(aRect, rText, nStart, nStart, nEnd - nStart); + + mrOutputDev.Pop(); + + mnBaseLine = std::max(mnBaseLine, -aRect.Top()); + mnHeight = std::max(mnHeight, aRect.GetHeight()); + if (nIdx >= maScriptChanges.size()) + break; + + maScriptChanges[nIdx++].textWidth = nWidth; + + if (nEnd < rText.getLength() && nIdx < nCnt) + { + nStart = nEnd; + nEnd = maScriptChanges[nIdx].changePos; + aScript = maScriptChanges[nIdx].scriptType; + } + else + break; + } + while(true); + + double fRatio = 1; + if (mnHeight > mnMaxHeight && mnHeight != 0) + fRatio = double(mnMaxHeight) / mnHeight; + + mnHeight *= fRatio; + mnBaseLine *= fRatio; + if (fRatio != 1) + { + Size aFontSize; + if (m_oFont) + { + aFontSize = m_oFont->GetFontSize(); + m_oFont->SetFontSize(Size(aFontSize.Width() * fRatio, aFontSize.Height() * fRatio)); + } + if (m_oCJKFont) + { + aFontSize = m_oCJKFont->GetFontSize(); + m_oCJKFont->SetFontSize(Size(aFontSize.Width() * fRatio, aFontSize.Height() * fRatio)); + } + if (m_oCTLFont) + { + aFontSize = m_oCTLFont->GetFontSize(); + m_oCTLFont->SetFontSize(Size(aFontSize.Width() * fRatio, aFontSize.Height() * fRatio)); + } + + for (auto& aChange : maScriptChanges) + aChange.textWidth *= fRatio; + } +} + +bool CommonStylePreviewRenderer::render(const tools::Rectangle& aRectangle, RenderAlign eRenderAlign) +{ + const OUString& rText = maStyleName; + + // setup the device & draw + mrOutputDev.Push(vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR | vcl::PushFlags::FILLCOLOR | vcl::PushFlags::TEXTFILLCOLOR); + + if (maBackgroundColor != COL_AUTO) + { + mrOutputDev.SetFillColor(maBackgroundColor); + mrOutputDev.DrawRect(aRectangle); + } + + Point aFontDrawPosition = aRectangle.TopLeft(); + aFontDrawPosition.AdjustY(mnBaseLine); + if (eRenderAlign == RenderAlign::CENTER) + { + if (aRectangle.GetHeight() > mnHeight) + aFontDrawPosition.AdjustY((aRectangle.GetHeight() - mnHeight) / 2 ); + } + + SvtScriptType aScript; + sal_uInt16 nIdx = 0; + sal_Int32 nStart = 0; + sal_Int32 nEnd; + size_t nCnt = maScriptChanges.size(); + if (nCnt) + { + nEnd = maScriptChanges[nIdx].changePos; + aScript = maScriptChanges[nIdx].scriptType; + } + else + { + nEnd = rText.getLength(); + aScript = SvtScriptType::LATIN; + } + + do + { + auto oFont = (aScript == SvtScriptType::ASIAN) + ? m_oCJKFont + : ((aScript == SvtScriptType::COMPLEX) + ? m_oCTLFont + : m_oFont); + + mrOutputDev.Push(vcl::PushFlags::FONT); + + if (oFont) + mrOutputDev.SetFont(*oFont); + + if (maFontColor != COL_AUTO) + mrOutputDev.SetTextColor(maFontColor); + + if (maHighlightColor != COL_AUTO) + mrOutputDev.SetTextFillColor(maHighlightColor); + + if (oFont) + oFont->QuickDrawText(&mrOutputDev, aFontDrawPosition, rText, nStart, nEnd - nStart, {}); + else + mrOutputDev.DrawText(aFontDrawPosition, rText, nStart, nEnd - nStart); + + mrOutputDev.Pop(); + + aFontDrawPosition.AdjustX(maScriptChanges[nIdx++].textWidth); + if (nEnd < rText.getLength() && nIdx < nCnt) + { + nStart = nEnd; + nEnd = maScriptChanges[nIdx].changePos; + aScript = maScriptChanges[nIdx].scriptType; + } + else + break; + } + while(true); + + mrOutputDev.Pop(); + + return true; +} + +void CommonStylePreviewRenderer::CheckScript() +{ + assert(!maStyleName.isEmpty()); // must have a preview text here! + if (maStyleName == maScriptText) + return; // already initialized + + maScriptText = maStyleName; + maScriptChanges.clear(); + + auto aEditEngine = EditEngine(nullptr); + aEditEngine.SetText(maScriptText); + + auto aScript = aEditEngine.GetScriptType({ 0, 0, 0, 0 }); + for (sal_Int32 i = 1; i <= maScriptText.getLength(); i++) + { + auto aNextScript = aEditEngine.GetScriptType({ 0, i, 0, i }); + if (aNextScript != aScript) + maScriptChanges.emplace_back(aScript, i - 1); + if (i == maScriptText.getLength()) + maScriptChanges.emplace_back(aScript, i); + aScript = aNextScript; + } +} + +} // end svx namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |