tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / svx / source / styles / CommonStylePreviewRenderer.cxx
blobb517b44378113fddca87c0343996d8a44c58b016
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 <CommonStylePreviewRenderer.hxx>
13 #include <sfx2/objsh.hxx>
14 #include <svl/style.hxx>
15 #include <svl/itemset.hxx>
16 #include <svl/itempool.hxx>
17 #include <vcl/metric.hxx>
18 #include <vcl/outdev.hxx>
20 #include <com/sun/star/drawing/FillStyle.hpp>
21 #include <svx/xdef.hxx>
22 #include <svx/xfillit0.hxx>
23 #include <svx/xflclit.hxx>
24 #include <editeng/brushitem.hxx>
25 #include <editeng/fontitem.hxx>
26 #include <editeng/fhgtitem.hxx>
27 #include <editeng/charreliefitem.hxx>
28 #include <editeng/contouritem.hxx>
29 #include <editeng/colritem.hxx>
30 #include <editeng/crossedoutitem.hxx>
31 #include <editeng/editeng.hxx>
32 #include <editeng/emphasismarkitem.hxx>
33 #include <editeng/postitem.hxx>
34 #include <editeng/shdditem.hxx>
35 #include <editeng/udlnitem.hxx>
36 #include <editeng/wghtitem.hxx>
37 #include <editeng/svxfont.hxx>
38 #include <editeng/cmapitem.hxx>
40 #include <editeng/editids.hrc>
42 using namespace css;
44 namespace svx
47 CommonStylePreviewRenderer::CommonStylePreviewRenderer(
48 const SfxObjectShell& rShell, OutputDevice& rOutputDev,
49 SfxStyleSheetBase* pStyle, tools::Long nMaxHeight)
50 : StylePreviewRenderer(rShell, rOutputDev, pStyle, nMaxHeight)
51 , maFontColor(COL_AUTO)
52 , maHighlightColor(COL_AUTO)
53 , maBackgroundColor(COL_AUTO)
54 , mnHeight(0)
55 , mnBaseLine(0)
56 , maStyleName(mpStyle->GetName())
60 CommonStylePreviewRenderer::~CommonStylePreviewRenderer()
63 static bool GetWhich(const SfxItemSet& rSet, sal_uInt16 nSlot, sal_uInt16& rWhich)
65 rWhich = rSet.GetPool()->GetWhichIDFromSlotID(nSlot);
66 return rSet.GetItemState(rWhich) >= SfxItemState::DEFAULT;
69 static bool SetFont(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
71 sal_uInt16 nWhich;
72 if (GetWhich(rSet, nSlot, nWhich))
74 const auto& rFontItem = static_cast<const SvxFontItem&>(rSet.Get(nWhich));
75 rFont.SetFamily(rFontItem.GetFamily());
76 rFont.SetFamilyName(rFontItem.GetFamilyName());
77 rFont.SetPitch(rFontItem.GetPitch());
78 rFont.SetCharSet(rFontItem.GetCharSet());
79 rFont.SetStyleName(rFontItem.GetStyleName());
80 rFont.SetAlignment(ALIGN_BASELINE);
81 return true;
83 return false;
86 bool CommonStylePreviewRenderer::SetFontSize(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
88 sal_uInt16 nWhich;
89 if (GetWhich(rSet, nSlot, nWhich))
91 const auto& rFontHeightItem = static_cast<const SvxFontHeightItem&>(rSet.Get(nWhich));
92 Size aFontSize(0, rFontHeightItem.GetHeight());
93 aFontSize = mrOutputDev.LogicToPixel(aFontSize, MapMode(mrShell.GetMapUnit()));
94 rFont.SetFontSize(aFontSize);
95 mrOutputDev.SetFont(rFont);
96 FontMetric aMetric(mrOutputDev.GetFontMetric());
97 return true;
99 return false;
102 bool CommonStylePreviewRenderer::recalculate()
104 m_oFont.reset();
105 m_oCJKFont.reset();
106 m_oCTLFont.reset();
108 std::optional<SfxItemSet> pItemSet(mpStyle->GetItemSetForPreview());
110 if (!pItemSet) return false;
112 SvxFont aFont;
113 SvxFont aCJKFont;
114 SvxFont aCTLFont;
116 const SfxPoolItem* pItem;
118 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_WEIGHT)) != nullptr)
119 aFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight());
120 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CJK_WEIGHT)) != nullptr)
121 aCJKFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight());
122 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CTL_WEIGHT)) != nullptr)
123 aCTLFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight());
125 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_POSTURE)) != nullptr)
126 aFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture());
127 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CJK_POSTURE)) != nullptr)
128 aCJKFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture());
129 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CTL_POSTURE)) != nullptr)
130 aCTLFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture());
132 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CONTOUR)) != nullptr)
134 auto aVal = static_cast<const SvxContourItem*>(pItem)->GetValue();
135 aFont.SetOutline(aVal);
136 aCJKFont.SetOutline(aVal);
137 aCTLFont.SetOutline(aVal);
139 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_SHADOWED)) != nullptr)
141 auto aVal = static_cast<const SvxShadowedItem*>(pItem)->GetValue();
142 aFont.SetShadow(aVal);
143 aCJKFont.SetShadow(aVal);
144 aCTLFont.SetShadow(aVal);
146 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_RELIEF)) != nullptr)
148 auto aVal = static_cast<const SvxCharReliefItem*>(pItem)->GetValue();
149 aFont.SetRelief(aVal);
150 aCJKFont.SetRelief(aVal);
151 aCTLFont.SetRelief(aVal);
153 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_UNDERLINE)) != nullptr)
155 auto aVal = static_cast<const SvxUnderlineItem*>(pItem)->GetLineStyle();
156 aFont.SetUnderline(aVal);
157 aCJKFont.SetUnderline(aVal);
158 aCTLFont.SetUnderline(aVal);
160 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_OVERLINE)) != nullptr)
162 auto aVal = static_cast<const SvxOverlineItem*>(pItem)->GetValue();
163 aFont.SetOverline(aVal);
164 aCJKFont.SetOverline(aVal);
165 aCTLFont.SetOverline(aVal);
167 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_STRIKEOUT)) != nullptr)
169 auto aVal = static_cast<const SvxCrossedOutItem*>(pItem)->GetStrikeout();
170 aFont.SetStrikeout(aVal);
171 aCJKFont.SetStrikeout(aVal);
172 aCTLFont.SetStrikeout(aVal);
174 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CASEMAP)) != nullptr)
176 auto aVal = static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap();
177 aFont.SetCaseMap(aVal);
178 aCJKFont.SetCaseMap(aVal);
179 aCTLFont.SetCaseMap(aVal);
181 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_EMPHASISMARK)) != nullptr)
183 auto aVal = static_cast<const SvxEmphasisMarkItem*>(pItem)->GetEmphasisMark();
184 aFont.SetEmphasisMark(aVal);
185 aCJKFont.SetEmphasisMark(aVal);
186 aCTLFont.SetEmphasisMark(aVal);
188 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_COLOR)) != nullptr)
190 maFontColor = static_cast<const SvxColorItem*>(pItem)->GetValue();
192 if ((pItem = pItemSet->GetItem(SID_ATTR_BRUSH_CHAR)) != nullptr)
194 maHighlightColor = static_cast<const SvxBrushItem*>(pItem)->GetColor();
197 if (mpStyle->GetFamily() == SfxStyleFamily::Para)
199 if ((pItem = pItemSet->GetItem(XATTR_FILLSTYLE)) != nullptr)
201 css::drawing::FillStyle aFillStyle = static_cast<const XFillStyleItem*>(pItem)->GetValue();
202 if (aFillStyle == drawing::FillStyle_SOLID)
204 if ((pItem = pItemSet->GetItem(XATTR_FILLCOLOR)) != nullptr)
206 maBackgroundColor = static_cast<const XFillColorItem*>(pItem)->GetColorValue();
212 if (SetFont(*pItemSet, SID_ATTR_CHAR_FONT, aFont) &&
213 SetFontSize(*pItemSet, SID_ATTR_CHAR_FONTHEIGHT, aFont))
214 m_oFont = aFont;
216 if (SetFont(*pItemSet, SID_ATTR_CHAR_CJK_FONT, aCJKFont) &&
217 SetFontSize(*pItemSet, SID_ATTR_CHAR_CJK_FONTHEIGHT, aCJKFont))
218 m_oCJKFont = aCJKFont;
220 if (SetFont(*pItemSet, SID_ATTR_CHAR_CTL_FONT, aCTLFont) &&
221 SetFontSize(*pItemSet, SID_ATTR_CHAR_CTL_FONTHEIGHT, aCTLFont))
222 m_oCTLFont = aCTLFont;
224 CheckScript();
225 CalcRenderSize();
226 return true;
229 void CommonStylePreviewRenderer::CalcRenderSize()
231 const OUString& rText = maStyleName;
233 mnBaseLine = 0;
234 mnHeight = 0;
235 SvtScriptType aScript;
236 sal_uInt16 nIdx = 0;
237 sal_Int32 nStart = 0;
238 sal_Int32 nEnd;
239 size_t nCnt = maScriptChanges.size();
241 if (nCnt)
243 nEnd = maScriptChanges[nIdx].changePos;
244 aScript = maScriptChanges[nIdx].scriptType;
246 else
248 nEnd = rText.getLength();
249 aScript = SvtScriptType::LATIN;
254 auto oFont = (aScript == SvtScriptType::ASIAN) ?
255 m_oCJKFont :
256 ((aScript == SvtScriptType::COMPLEX) ?
257 m_oCTLFont :
258 m_oFont);
260 mrOutputDev.Push(vcl::PushFlags::FONT);
262 tools::Long nWidth;
263 if (oFont)
265 mrOutputDev.SetFont(*oFont);
266 nWidth = oFont->GetTextSize(mrOutputDev, rText, nStart, nEnd - nStart).Width();
268 else
269 nWidth = mrOutputDev.GetTextWidth(rText, nStart, nEnd - nStart);
271 tools::Rectangle aRect;
272 mrOutputDev.GetTextBoundRect(aRect, rText, nStart, nStart, nEnd - nStart);
274 mrOutputDev.Pop();
276 mnBaseLine = std::max(mnBaseLine, -aRect.Top());
277 mnHeight = std::max(mnHeight, aRect.GetHeight());
278 if (nIdx >= maScriptChanges.size())
279 break;
281 maScriptChanges[nIdx++].textWidth = nWidth;
283 if (nEnd < rText.getLength() && nIdx < nCnt)
285 nStart = nEnd;
286 nEnd = maScriptChanges[nIdx].changePos;
287 aScript = maScriptChanges[nIdx].scriptType;
289 else
290 break;
292 while(true);
294 double fRatio = 1;
295 if (mnHeight > mnMaxHeight && mnHeight != 0)
296 fRatio = double(mnMaxHeight) / mnHeight;
298 mnHeight *= fRatio;
299 mnBaseLine *= fRatio;
300 if (fRatio != 1)
302 Size aFontSize;
303 if (m_oFont)
305 aFontSize = m_oFont->GetFontSize();
306 m_oFont->SetFontSize(Size(aFontSize.Width() * fRatio, aFontSize.Height() * fRatio));
308 if (m_oCJKFont)
310 aFontSize = m_oCJKFont->GetFontSize();
311 m_oCJKFont->SetFontSize(Size(aFontSize.Width() * fRatio, aFontSize.Height() * fRatio));
313 if (m_oCTLFont)
315 aFontSize = m_oCTLFont->GetFontSize();
316 m_oCTLFont->SetFontSize(Size(aFontSize.Width() * fRatio, aFontSize.Height() * fRatio));
319 for (auto& aChange : maScriptChanges)
320 aChange.textWidth *= fRatio;
324 bool CommonStylePreviewRenderer::render(const tools::Rectangle& aRectangle, RenderAlign eRenderAlign)
326 const OUString& rText = maStyleName;
328 // setup the device & draw
329 mrOutputDev.Push(vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR | vcl::PushFlags::FILLCOLOR | vcl::PushFlags::TEXTFILLCOLOR);
331 if (maBackgroundColor != COL_AUTO)
333 mrOutputDev.SetFillColor(maBackgroundColor);
334 mrOutputDev.DrawRect(aRectangle);
337 Point aFontDrawPosition = aRectangle.TopLeft();
338 aFontDrawPosition.AdjustY(mnBaseLine);
339 if (eRenderAlign == RenderAlign::CENTER)
341 if (aRectangle.GetHeight() > mnHeight)
342 aFontDrawPosition.AdjustY((aRectangle.GetHeight() - mnHeight) / 2 );
345 SvtScriptType aScript;
346 sal_uInt16 nIdx = 0;
347 sal_Int32 nStart = 0;
348 sal_Int32 nEnd;
349 size_t nCnt = maScriptChanges.size();
350 if (nCnt)
352 nEnd = maScriptChanges[nIdx].changePos;
353 aScript = maScriptChanges[nIdx].scriptType;
355 else
357 nEnd = rText.getLength();
358 aScript = SvtScriptType::LATIN;
363 auto oFont = (aScript == SvtScriptType::ASIAN)
364 ? m_oCJKFont
365 : ((aScript == SvtScriptType::COMPLEX)
366 ? m_oCTLFont
367 : m_oFont);
369 mrOutputDev.Push(vcl::PushFlags::FONT);
371 if (oFont)
372 mrOutputDev.SetFont(*oFont);
374 if (maFontColor != COL_AUTO)
375 mrOutputDev.SetTextColor(maFontColor);
377 if (maHighlightColor != COL_AUTO)
378 mrOutputDev.SetTextFillColor(maHighlightColor);
380 if (oFont)
381 oFont->QuickDrawText(&mrOutputDev, aFontDrawPosition, rText, nStart, nEnd - nStart, {});
382 else
383 mrOutputDev.DrawText(aFontDrawPosition, rText, nStart, nEnd - nStart);
385 mrOutputDev.Pop();
387 aFontDrawPosition.AdjustX(maScriptChanges[nIdx++].textWidth);
388 if (nEnd < rText.getLength() && nIdx < nCnt)
390 nStart = nEnd;
391 nEnd = maScriptChanges[nIdx].changePos;
392 aScript = maScriptChanges[nIdx].scriptType;
394 else
395 break;
397 while(true);
399 mrOutputDev.Pop();
401 return true;
404 void CommonStylePreviewRenderer::CheckScript()
406 assert(!maStyleName.isEmpty()); // must have a preview text here!
407 if (maStyleName == maScriptText)
408 return; // already initialized
410 maScriptText = maStyleName;
411 maScriptChanges.clear();
413 auto aEditEngine = EditEngine(nullptr);
414 aEditEngine.SetText(maScriptText);
416 auto aScript = aEditEngine.GetScriptType({ 0, 0, 0, 0 });
417 for (sal_Int32 i = 1; i <= maScriptText.getLength(); i++)
419 auto aNextScript = aEditEngine.GetScriptType({ 0, i, 0, i });
420 if (aNextScript != aScript)
421 maScriptChanges.emplace_back(aScript, i - 1);
422 if (i == maScriptText.getLength())
423 maScriptChanges.emplace_back(aScript, i);
424 aScript = aNextScript;
428 } // end svx namespace
430 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */