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/.
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>
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
)
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
)
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
);
87 bool CommonStylePreviewRenderer::SetFontSize(const SfxItemSet
& rSet
, sal_uInt16 nSlot
, SvxFont
& rFont
)
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());
103 bool CommonStylePreviewRenderer::recalculate()
109 std::optional
<SfxItemSet
> pItemSet(mpStyle
->GetItemSetForPreview());
111 if (!pItemSet
) return false;
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
))
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
;
230 void CommonStylePreviewRenderer::CalcRenderSize()
232 const OUString
& rText
= maStyleName
;
236 SvtScriptType aScript
;
238 sal_Int32 nStart
= 0;
240 size_t nCnt
= maScriptChanges
.size();
244 nEnd
= maScriptChanges
[nIdx
].changePos
;
245 aScript
= maScriptChanges
[nIdx
].scriptType
;
249 nEnd
= rText
.getLength();
250 aScript
= SvtScriptType::LATIN
;
255 auto oFont
= (aScript
== SvtScriptType::ASIAN
) ?
257 ((aScript
== SvtScriptType::COMPLEX
) ?
261 mrOutputDev
.Push(vcl::PushFlags::FONT
);
266 mrOutputDev
.SetFont(*oFont
);
267 nWidth
= oFont
->GetTextSize(mrOutputDev
, rText
, nStart
, nEnd
- nStart
).Width();
270 nWidth
= mrOutputDev
.GetTextWidth(rText
, nStart
, nEnd
- nStart
);
272 tools::Rectangle aRect
;
273 mrOutputDev
.GetTextBoundRect(aRect
, rText
, nStart
, nStart
, nEnd
- nStart
);
277 mnBaseLine
= std::max(mnBaseLine
, -aRect
.Top());
278 mnHeight
= std::max(mnHeight
, aRect
.GetHeight());
279 if (nIdx
>= maScriptChanges
.size())
282 maScriptChanges
[nIdx
++].textWidth
= nWidth
;
284 if (nEnd
< rText
.getLength() && nIdx
< nCnt
)
287 nEnd
= maScriptChanges
[nIdx
].changePos
;
288 aScript
= maScriptChanges
[nIdx
].scriptType
;
296 if (mnHeight
> mnMaxHeight
&& mnHeight
!= 0)
297 fRatio
= double(mnMaxHeight
) / mnHeight
;
300 mnBaseLine
*= fRatio
;
306 aFontSize
= m_oFont
->GetFontSize();
307 m_oFont
->SetFontSize(Size(aFontSize
.Width() * fRatio
, aFontSize
.Height() * fRatio
));
311 aFontSize
= m_oCJKFont
->GetFontSize();
312 m_oCJKFont
->SetFontSize(Size(aFontSize
.Width() * fRatio
, aFontSize
.Height() * fRatio
));
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
;
348 sal_Int32 nStart
= 0;
350 size_t nCnt
= maScriptChanges
.size();
353 nEnd
= maScriptChanges
[nIdx
].changePos
;
354 aScript
= maScriptChanges
[nIdx
].scriptType
;
358 nEnd
= rText
.getLength();
359 aScript
= SvtScriptType::LATIN
;
364 auto oFont
= (aScript
== SvtScriptType::ASIAN
)
366 : ((aScript
== SvtScriptType::COMPLEX
)
370 mrOutputDev
.Push(vcl::PushFlags::FONT
);
373 mrOutputDev
.SetFont(*oFont
);
375 if (maFontColor
!= COL_AUTO
)
376 mrOutputDev
.SetTextColor(maFontColor
);
378 if (maHighlightColor
!= COL_AUTO
)
379 mrOutputDev
.SetTextFillColor(maHighlightColor
);
382 oFont
->QuickDrawText(&mrOutputDev
, aFontDrawPosition
, rText
, nStart
, nEnd
- nStart
, {});
384 mrOutputDev
.DrawText(aFontDrawPosition
, rText
, nStart
, nEnd
- nStart
);
388 aFontDrawPosition
.AdjustX(maScriptChanges
[nIdx
++].textWidth
);
389 if (nEnd
< rText
.getLength() && nIdx
< nCnt
)
392 nEnd
= maScriptChanges
[nIdx
].changePos
;
393 aScript
= maScriptChanges
[nIdx
].scriptType
;
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: */