Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / styles / CommonStylePreviewRenderer.cxx
blobd92aac21d89c2f302688d8eb007b1888fad180a2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
11 #include <memory>
12 #include <CommonStylePreviewRenderer.hxx>
14 #include <sfx2/objsh.hxx>
15 #include <svl/style.hxx>
16 #include <svl/itemset.hxx>
17 #include <svl/itempool.hxx>
18 #include <vcl/metric.hxx>
19 #include <vcl/outdev.hxx>
21 #include <com/sun/star/drawing/FillStyle.hpp>
22 #include <svx/xdef.hxx>
23 #include <svx/xfillit0.hxx>
24 #include <svx/xflclit.hxx>
25 #include <editeng/brushitem.hxx>
26 #include <editeng/fontitem.hxx>
27 #include <editeng/fhgtitem.hxx>
28 #include <editeng/charreliefitem.hxx>
29 #include <editeng/contouritem.hxx>
30 #include <editeng/colritem.hxx>
31 #include <editeng/crossedoutitem.hxx>
32 #include <editeng/editeng.hxx>
33 #include <editeng/emphasismarkitem.hxx>
34 #include <editeng/postitem.hxx>
35 #include <editeng/shdditem.hxx>
36 #include <editeng/udlnitem.hxx>
37 #include <editeng/wghtitem.hxx>
38 #include <editeng/svxfont.hxx>
39 #include <editeng/cmapitem.hxx>
41 #include <editeng/editids.hrc>
43 using namespace css;
45 namespace svx
48 CommonStylePreviewRenderer::CommonStylePreviewRenderer(
49 const SfxObjectShell& rShell, OutputDevice& rOutputDev,
50 SfxStyleSheetBase* pStyle, tools::Long nMaxHeight)
51 : StylePreviewRenderer(rShell, rOutputDev, pStyle, nMaxHeight)
52 , maFontColor(COL_AUTO)
53 , maHighlightColor(COL_AUTO)
54 , maBackgroundColor(COL_AUTO)
55 , mnHeight(0)
56 , mnBaseLine(0)
57 , maStyleName(mpStyle->GetName())
61 CommonStylePreviewRenderer::~CommonStylePreviewRenderer()
64 static bool GetWhich(const SfxItemSet& rSet, sal_uInt16 nSlot, sal_uInt16& rWhich)
66 rWhich = rSet.GetPool()->GetWhich(nSlot);
67 return rSet.GetItemState(rWhich) >= SfxItemState::DEFAULT;
70 static bool SetFont(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
72 sal_uInt16 nWhich;
73 if (GetWhich(rSet, nSlot, nWhich))
75 const auto& rFontItem = static_cast<const SvxFontItem&>(rSet.Get(nWhich));
76 rFont.SetFamily(rFontItem.GetFamily());
77 rFont.SetFamilyName(rFontItem.GetFamilyName());
78 rFont.SetPitch(rFontItem.GetPitch());
79 rFont.SetCharSet(rFontItem.GetCharSet());
80 rFont.SetStyleName(rFontItem.GetStyleName());
81 rFont.SetAlignment(ALIGN_BASELINE);
82 return true;
84 return false;
87 bool CommonStylePreviewRenderer::SetFontSize(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
89 sal_uInt16 nWhich;
90 if (GetWhich(rSet, nSlot, nWhich))
92 const auto& rFontHeightItem = static_cast<const SvxFontHeightItem&>(rSet.Get(nWhich));
93 Size aFontSize(0, rFontHeightItem.GetHeight());
94 aFontSize = mrOutputDev.LogicToPixel(aFontSize, MapMode(mrShell.GetMapUnit()));
95 rFont.SetFontSize(aFontSize);
96 mrOutputDev.SetFont(rFont);
97 FontMetric aMetric(mrOutputDev.GetFontMetric());
98 return true;
100 return false;
103 bool CommonStylePreviewRenderer::recalculate()
105 m_oFont.reset();
106 m_oCJKFont.reset();
107 m_oCTLFont.reset();
109 std::optional<SfxItemSet> pItemSet(mpStyle->GetItemSetForPreview());
111 if (!pItemSet) return false;
113 SvxFont aFont;
114 SvxFont aCJKFont;
115 SvxFont aCTLFont;
117 const SfxPoolItem* pItem;
119 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_WEIGHT)) != nullptr)
120 aFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight());
121 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CJK_WEIGHT)) != nullptr)
122 aCJKFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight());
123 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CTL_WEIGHT)) != nullptr)
124 aCTLFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight());
126 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_POSTURE)) != nullptr)
127 aFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture());
128 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CJK_POSTURE)) != nullptr)
129 aCJKFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture());
130 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CTL_POSTURE)) != nullptr)
131 aCTLFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture());
133 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CONTOUR)) != nullptr)
135 auto aVal = static_cast<const SvxContourItem*>(pItem)->GetValue();
136 aFont.SetOutline(aVal);
137 aCJKFont.SetOutline(aVal);
138 aCTLFont.SetOutline(aVal);
140 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_SHADOWED)) != nullptr)
142 auto aVal = static_cast<const SvxShadowedItem*>(pItem)->GetValue();
143 aFont.SetShadow(aVal);
144 aCJKFont.SetShadow(aVal);
145 aCTLFont.SetShadow(aVal);
147 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_RELIEF)) != nullptr)
149 auto aVal = static_cast<const SvxCharReliefItem*>(pItem)->GetValue();
150 aFont.SetRelief(aVal);
151 aCJKFont.SetRelief(aVal);
152 aCTLFont.SetRelief(aVal);
154 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_UNDERLINE)) != nullptr)
156 auto aVal = static_cast<const SvxUnderlineItem*>(pItem)->GetLineStyle();
157 aFont.SetUnderline(aVal);
158 aCJKFont.SetUnderline(aVal);
159 aCTLFont.SetUnderline(aVal);
161 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_OVERLINE)) != nullptr)
163 auto aVal = static_cast<const SvxOverlineItem*>(pItem)->GetValue();
164 aFont.SetOverline(aVal);
165 aCJKFont.SetOverline(aVal);
166 aCTLFont.SetOverline(aVal);
168 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_STRIKEOUT)) != nullptr)
170 auto aVal = static_cast<const SvxCrossedOutItem*>(pItem)->GetStrikeout();
171 aFont.SetStrikeout(aVal);
172 aCJKFont.SetStrikeout(aVal);
173 aCTLFont.SetStrikeout(aVal);
175 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CASEMAP)) != nullptr)
177 auto aVal = static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap();
178 aFont.SetCaseMap(aVal);
179 aCJKFont.SetCaseMap(aVal);
180 aCTLFont.SetCaseMap(aVal);
182 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_EMPHASISMARK)) != nullptr)
184 auto aVal = static_cast<const SvxEmphasisMarkItem*>(pItem)->GetEmphasisMark();
185 aFont.SetEmphasisMark(aVal);
186 aCJKFont.SetEmphasisMark(aVal);
187 aCTLFont.SetEmphasisMark(aVal);
189 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_COLOR)) != nullptr)
191 maFontColor = static_cast<const SvxColorItem*>(pItem)->GetValue();
193 if ((pItem = pItemSet->GetItem(SID_ATTR_BRUSH_CHAR)) != nullptr)
195 maHighlightColor = static_cast<const SvxBrushItem*>(pItem)->GetColor();
198 if (mpStyle->GetFamily() == SfxStyleFamily::Para)
200 if ((pItem = pItemSet->GetItem(XATTR_FILLSTYLE)) != nullptr)
202 css::drawing::FillStyle aFillStyle = static_cast<const XFillStyleItem*>(pItem)->GetValue();
203 if (aFillStyle == drawing::FillStyle_SOLID)
205 if ((pItem = pItemSet->GetItem(XATTR_FILLCOLOR)) != nullptr)
207 maBackgroundColor = static_cast<const XFillColorItem*>(pItem)->GetColorValue();
213 if (SetFont(*pItemSet, SID_ATTR_CHAR_FONT, aFont) &&
214 SetFontSize(*pItemSet, SID_ATTR_CHAR_FONTHEIGHT, aFont))
215 m_oFont = aFont;
217 if (SetFont(*pItemSet, SID_ATTR_CHAR_CJK_FONT, aCJKFont) &&
218 SetFontSize(*pItemSet, SID_ATTR_CHAR_CJK_FONTHEIGHT, aCJKFont))
219 m_oCJKFont = aCJKFont;
221 if (SetFont(*pItemSet, SID_ATTR_CHAR_CTL_FONT, aCTLFont) &&
222 SetFontSize(*pItemSet, SID_ATTR_CHAR_CTL_FONTHEIGHT, aCTLFont))
223 m_oCTLFont = aCTLFont;
225 CheckScript();
226 CalcRenderSize();
227 return true;
230 void CommonStylePreviewRenderer::CalcRenderSize()
232 const OUString& rText = maStyleName;
234 mnBaseLine = 0;
235 mnHeight = 0;
236 SvtScriptType aScript;
237 sal_uInt16 nIdx = 0;
238 sal_Int32 nStart = 0;
239 sal_Int32 nEnd;
240 size_t nCnt = maScriptChanges.size();
242 if (nCnt)
244 nEnd = maScriptChanges[nIdx].changePos;
245 aScript = maScriptChanges[nIdx].scriptType;
247 else
249 nEnd = rText.getLength();
250 aScript = SvtScriptType::LATIN;
255 auto oFont = (aScript == SvtScriptType::ASIAN) ?
256 m_oCJKFont :
257 ((aScript == SvtScriptType::COMPLEX) ?
258 m_oCTLFont :
259 m_oFont);
261 mrOutputDev.Push(vcl::PushFlags::FONT);
263 tools::Long nWidth;
264 if (oFont)
266 mrOutputDev.SetFont(*oFont);
267 nWidth = oFont->GetTextSize(mrOutputDev, rText, nStart, nEnd - nStart).Width();
269 else
270 nWidth = mrOutputDev.GetTextWidth(rText, nStart, nEnd - nStart);
272 tools::Rectangle aRect;
273 mrOutputDev.GetTextBoundRect(aRect, rText, nStart, nStart, nEnd - nStart);
275 mrOutputDev.Pop();
277 mnBaseLine = std::max(mnBaseLine, -aRect.Top());
278 mnHeight = std::max(mnHeight, aRect.GetHeight());
279 if (nIdx >= maScriptChanges.size())
280 break;
282 maScriptChanges[nIdx++].textWidth = nWidth;
284 if (nEnd < rText.getLength() && nIdx < nCnt)
286 nStart = nEnd;
287 nEnd = maScriptChanges[nIdx].changePos;
288 aScript = maScriptChanges[nIdx].scriptType;
290 else
291 break;
293 while(true);
295 double fRatio = 1;
296 if (mnHeight > mnMaxHeight && mnHeight != 0)
297 fRatio = double(mnMaxHeight) / mnHeight;
299 mnHeight *= fRatio;
300 mnBaseLine *= fRatio;
301 if (fRatio != 1)
303 Size aFontSize;
304 if (m_oFont)
306 aFontSize = m_oFont->GetFontSize();
307 m_oFont->SetFontSize(Size(aFontSize.Width() * fRatio, aFontSize.Height() * fRatio));
309 if (m_oCJKFont)
311 aFontSize = m_oCJKFont->GetFontSize();
312 m_oCJKFont->SetFontSize(Size(aFontSize.Width() * fRatio, aFontSize.Height() * fRatio));
314 if (m_oCTLFont)
316 aFontSize = m_oCTLFont->GetFontSize();
317 m_oCTLFont->SetFontSize(Size(aFontSize.Width() * fRatio, aFontSize.Height() * fRatio));
320 for (auto& aChange : maScriptChanges)
321 aChange.textWidth *= fRatio;
325 bool CommonStylePreviewRenderer::render(const tools::Rectangle& aRectangle, RenderAlign eRenderAlign)
327 const OUString& rText = maStyleName;
329 // setup the device & draw
330 mrOutputDev.Push(vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR | vcl::PushFlags::FILLCOLOR | vcl::PushFlags::TEXTFILLCOLOR);
332 if (maBackgroundColor != COL_AUTO)
334 mrOutputDev.SetFillColor(maBackgroundColor);
335 mrOutputDev.DrawRect(aRectangle);
338 Point aFontDrawPosition = aRectangle.TopLeft();
339 aFontDrawPosition.AdjustY(mnBaseLine);
340 if (eRenderAlign == RenderAlign::CENTER)
342 if (aRectangle.GetHeight() > mnHeight)
343 aFontDrawPosition.AdjustY((aRectangle.GetHeight() - mnHeight) / 2 );
346 SvtScriptType aScript;
347 sal_uInt16 nIdx = 0;
348 sal_Int32 nStart = 0;
349 sal_Int32 nEnd;
350 size_t nCnt = maScriptChanges.size();
351 if (nCnt)
353 nEnd = maScriptChanges[nIdx].changePos;
354 aScript = maScriptChanges[nIdx].scriptType;
356 else
358 nEnd = rText.getLength();
359 aScript = SvtScriptType::LATIN;
364 auto oFont = (aScript == SvtScriptType::ASIAN)
365 ? m_oCJKFont
366 : ((aScript == SvtScriptType::COMPLEX)
367 ? m_oCTLFont
368 : m_oFont);
370 mrOutputDev.Push(vcl::PushFlags::FONT);
372 if (oFont)
373 mrOutputDev.SetFont(*oFont);
375 if (maFontColor != COL_AUTO)
376 mrOutputDev.SetTextColor(maFontColor);
378 if (maHighlightColor != COL_AUTO)
379 mrOutputDev.SetTextFillColor(maHighlightColor);
381 if (oFont)
382 oFont->QuickDrawText(&mrOutputDev, aFontDrawPosition, rText, nStart, nEnd - nStart, {});
383 else
384 mrOutputDev.DrawText(aFontDrawPosition, rText, nStart, nEnd - nStart);
386 mrOutputDev.Pop();
388 aFontDrawPosition.AdjustX(maScriptChanges[nIdx++].textWidth);
389 if (nEnd < rText.getLength() && nIdx < nCnt)
391 nStart = nEnd;
392 nEnd = maScriptChanges[nIdx].changePos;
393 aScript = maScriptChanges[nIdx].scriptType;
395 else
396 break;
398 while(true);
400 mrOutputDev.Pop();
402 return true;
405 void CommonStylePreviewRenderer::CheckScript()
407 assert(!maStyleName.isEmpty()); // must have a preview text here!
408 if (maStyleName == maScriptText)
409 return; // already initialized
411 maScriptText = maStyleName;
412 maScriptChanges.clear();
414 auto aEditEngine = EditEngine(nullptr);
415 aEditEngine.SetText(maScriptText);
417 auto aScript = aEditEngine.GetScriptType({ 0, 0, 0, 0 });
418 for (sal_Int32 i = 1; i <= maScriptText.getLength(); i++)
420 auto aNextScript = aEditEngine.GetScriptType({ 0, i, 0, i });
421 if (aNextScript != aScript)
422 maScriptChanges.emplace_back(aScript, i - 1);
423 if (i == maScriptText.getLength())
424 maScriptChanges.emplace_back(aScript, i);
425 aScript = aNextScript;
429 } // end svx namespace
431 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */