1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
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>
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
)
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
)
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
);
86 bool CommonStylePreviewRenderer::SetFontSize(const SfxItemSet
& rSet
, sal_uInt16 nSlot
, SvxFont
& rFont
)
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());
102 bool CommonStylePreviewRenderer::recalculate()
108 std::optional
<SfxItemSet
> pItemSet(mpStyle
->GetItemSetForPreview());
110 if (!pItemSet
) return false;
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
))
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
;
229 void CommonStylePreviewRenderer::CalcRenderSize()
231 const OUString
& rText
= maStyleName
;
235 SvtScriptType aScript
;
237 sal_Int32 nStart
= 0;
239 size_t nCnt
= maScriptChanges
.size();
243 nEnd
= maScriptChanges
[nIdx
].changePos
;
244 aScript
= maScriptChanges
[nIdx
].scriptType
;
248 nEnd
= rText
.getLength();
249 aScript
= SvtScriptType::LATIN
;
254 auto oFont
= (aScript
== SvtScriptType::ASIAN
) ?
256 ((aScript
== SvtScriptType::COMPLEX
) ?
260 mrOutputDev
.Push(vcl::PushFlags::FONT
);
265 mrOutputDev
.SetFont(*oFont
);
266 nWidth
= oFont
->GetTextSize(mrOutputDev
, rText
, nStart
, nEnd
- nStart
).Width();
269 nWidth
= mrOutputDev
.GetTextWidth(rText
, nStart
, nEnd
- nStart
);
271 tools::Rectangle aRect
;
272 mrOutputDev
.GetTextBoundRect(aRect
, rText
, nStart
, nStart
, nEnd
- nStart
);
276 mnBaseLine
= std::max(mnBaseLine
, -aRect
.Top());
277 mnHeight
= std::max(mnHeight
, aRect
.GetHeight());
278 if (nIdx
>= maScriptChanges
.size())
281 maScriptChanges
[nIdx
++].textWidth
= nWidth
;
283 if (nEnd
< rText
.getLength() && nIdx
< nCnt
)
286 nEnd
= maScriptChanges
[nIdx
].changePos
;
287 aScript
= maScriptChanges
[nIdx
].scriptType
;
295 if (mnHeight
> mnMaxHeight
&& mnHeight
!= 0)
296 fRatio
= double(mnMaxHeight
) / mnHeight
;
299 mnBaseLine
*= fRatio
;
305 aFontSize
= m_oFont
->GetFontSize();
306 m_oFont
->SetFontSize(Size(aFontSize
.Width() * fRatio
, aFontSize
.Height() * fRatio
));
310 aFontSize
= m_oCJKFont
->GetFontSize();
311 m_oCJKFont
->SetFontSize(Size(aFontSize
.Width() * fRatio
, aFontSize
.Height() * fRatio
));
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
;
347 sal_Int32 nStart
= 0;
349 size_t nCnt
= maScriptChanges
.size();
352 nEnd
= maScriptChanges
[nIdx
].changePos
;
353 aScript
= maScriptChanges
[nIdx
].scriptType
;
357 nEnd
= rText
.getLength();
358 aScript
= SvtScriptType::LATIN
;
363 auto oFont
= (aScript
== SvtScriptType::ASIAN
)
365 : ((aScript
== SvtScriptType::COMPLEX
)
369 mrOutputDev
.Push(vcl::PushFlags::FONT
);
372 mrOutputDev
.SetFont(*oFont
);
374 if (maFontColor
!= COL_AUTO
)
375 mrOutputDev
.SetTextColor(maFontColor
);
377 if (maHighlightColor
!= COL_AUTO
)
378 mrOutputDev
.SetTextFillColor(maHighlightColor
);
381 oFont
->QuickDrawText(&mrOutputDev
, aFontDrawPosition
, rText
, nStart
, nEnd
- nStart
, {});
383 mrOutputDev
.DrawText(aFontDrawPosition
, rText
, nStart
, nEnd
- nStart
);
387 aFontDrawPosition
.AdjustX(maScriptChanges
[nIdx
++].textWidth
);
388 if (nEnd
< rText
.getLength() && nIdx
< nCnt
)
391 nEnd
= maScriptChanges
[nIdx
].changePos
;
392 aScript
= maScriptChanges
[nIdx
].scriptType
;
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: */