LibreOffice Module svx (master) 1
CommonStylePreviewRenderer.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 */
10
11#include <memory>
13
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>
20
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>
30#include <editeng/colritem.hxx>
32#include <editeng/editeng.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>
40
41#include <editeng/editids.hrc>
42
43using namespace css;
44
45namespace svx
46{
47
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)
55 , mnHeight(0)
56 , mnBaseLine(0)
57 , maStyleName(mpStyle->GetName())
58{
59}
60
62{}
63
64static bool GetWhich(const SfxItemSet& rSet, sal_uInt16 nSlot, sal_uInt16& rWhich)
65{
66 rWhich = rSet.GetPool()->GetWhich(nSlot);
67 return rSet.GetItemState(rWhich) >= SfxItemState::DEFAULT;
68}
69
70static bool SetFont(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
71{
72 sal_uInt16 nWhich;
73 if (GetWhich(rSet, nSlot, nWhich))
74 {
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;
83 }
84 return false;
85}
86
87bool CommonStylePreviewRenderer::SetFontSize(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
88{
89 sal_uInt16 nWhich;
90 if (GetWhich(rSet, nSlot, nWhich))
91 {
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);
98 return true;
99 }
100 return false;
101}
102
104{
105 m_oFont.reset();
106 m_oCJKFont.reset();
107 m_oCTLFont.reset();
108
109 std::optional<SfxItemSet> pItemSet(mpStyle->GetItemSetForPreview());
110
111 if (!pItemSet) return false;
112
113 SvxFont aFont;
114 SvxFont aCJKFont;
115 SvxFont aCTLFont;
116
117 const SfxPoolItem* pItem;
118
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());
125
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());
132
133 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CONTOUR)) != nullptr)
134 {
135 auto aVal = static_cast<const SvxContourItem*>(pItem)->GetValue();
136 aFont.SetOutline(aVal);
137 aCJKFont.SetOutline(aVal);
138 aCTLFont.SetOutline(aVal);
139 }
140 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_SHADOWED)) != nullptr)
141 {
142 auto aVal = static_cast<const SvxShadowedItem*>(pItem)->GetValue();
143 aFont.SetShadow(aVal);
144 aCJKFont.SetShadow(aVal);
145 aCTLFont.SetShadow(aVal);
146 }
147 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_RELIEF)) != nullptr)
148 {
149 auto aVal = static_cast<const SvxCharReliefItem*>(pItem)->GetValue();
150 aFont.SetRelief(aVal);
151 aCJKFont.SetRelief(aVal);
152 aCTLFont.SetRelief(aVal);
153 }
154 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_UNDERLINE)) != nullptr)
155 {
156 auto aVal = static_cast<const SvxUnderlineItem*>(pItem)->GetLineStyle();
157 aFont.SetUnderline(aVal);
158 aCJKFont.SetUnderline(aVal);
159 aCTLFont.SetUnderline(aVal);
160 }
161 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_OVERLINE)) != nullptr)
162 {
163 auto aVal = static_cast<const SvxOverlineItem*>(pItem)->GetValue();
164 aFont.SetOverline(aVal);
165 aCJKFont.SetOverline(aVal);
166 aCTLFont.SetOverline(aVal);
167 }
168 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_STRIKEOUT)) != nullptr)
169 {
170 auto aVal = static_cast<const SvxCrossedOutItem*>(pItem)->GetStrikeout();
171 aFont.SetStrikeout(aVal);
172 aCJKFont.SetStrikeout(aVal);
173 aCTLFont.SetStrikeout(aVal);
174 }
175 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_CASEMAP)) != nullptr)
176 {
177 auto aVal = static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap();
178 aFont.SetCaseMap(aVal);
179 aCJKFont.SetCaseMap(aVal);
180 aCTLFont.SetCaseMap(aVal);
181 }
182 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_EMPHASISMARK)) != nullptr)
183 {
184 auto aVal = static_cast<const SvxEmphasisMarkItem*>(pItem)->GetEmphasisMark();
185 aFont.SetEmphasisMark(aVal);
186 aCJKFont.SetEmphasisMark(aVal);
187 aCTLFont.SetEmphasisMark(aVal);
188 }
189 if ((pItem = pItemSet->GetItem(SID_ATTR_CHAR_COLOR)) != nullptr)
190 {
191 maFontColor = static_cast<const SvxColorItem*>(pItem)->GetValue();
192 }
193 if ((pItem = pItemSet->GetItem(SID_ATTR_BRUSH_CHAR)) != nullptr)
194 {
195 maHighlightColor = static_cast<const SvxBrushItem*>(pItem)->GetColor();
196 }
197
198 if (mpStyle->GetFamily() == SfxStyleFamily::Para)
199 {
200 if ((pItem = pItemSet->GetItem(XATTR_FILLSTYLE)) != nullptr)
201 {
202 css::drawing::FillStyle aFillStyle = static_cast<const XFillStyleItem*>(pItem)->GetValue();
203 if (aFillStyle == drawing::FillStyle_SOLID)
204 {
205 if ((pItem = pItemSet->GetItem(XATTR_FILLCOLOR)) != nullptr)
206 {
207 maBackgroundColor = static_cast<const XFillColorItem*>(pItem)->GetColorValue();
208 }
209 }
210 }
211 }
212
213 if (SetFont(*pItemSet, SID_ATTR_CHAR_FONT, aFont) &&
214 SetFontSize(*pItemSet, SID_ATTR_CHAR_FONTHEIGHT, aFont))
215 m_oFont = aFont;
216
217 if (SetFont(*pItemSet, SID_ATTR_CHAR_CJK_FONT, aCJKFont) &&
218 SetFontSize(*pItemSet, SID_ATTR_CHAR_CJK_FONTHEIGHT, aCJKFont))
219 m_oCJKFont = aCJKFont;
220
221 if (SetFont(*pItemSet, SID_ATTR_CHAR_CTL_FONT, aCTLFont) &&
222 SetFontSize(*pItemSet, SID_ATTR_CHAR_CTL_FONTHEIGHT, aCTLFont))
223 m_oCTLFont = aCTLFont;
224
225 CheckScript();
227 return true;
228}
229
231{
232 const OUString& rText = maStyleName;
233
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();
241
242 if (nCnt)
243 {
244 nEnd = maScriptChanges[nIdx].changePos;
245 aScript = maScriptChanges[nIdx].scriptType;
246 }
247 else
248 {
249 nEnd = rText.getLength();
250 aScript = SvtScriptType::LATIN;
251 }
252
253 do
254 {
255 auto oFont = (aScript == SvtScriptType::ASIAN) ?
256 m_oCJKFont :
257 ((aScript == SvtScriptType::COMPLEX) ?
258 m_oCTLFont :
259 m_oFont);
260
262
263 tools::Long nWidth;
264 if (oFont)
265 {
266 mrOutputDev.SetFont(*oFont);
267 nWidth = oFont->GetTextSize(mrOutputDev, rText, nStart, nEnd - nStart).Width();
268 }
269 else
270 nWidth = mrOutputDev.GetTextWidth(rText, nStart, nEnd - nStart);
271
272 tools::Rectangle aRect;
273 mrOutputDev.GetTextBoundRect(aRect, rText, nStart, nStart, nEnd - nStart);
274
276
277 mnBaseLine = std::max(mnBaseLine, -aRect.Top());
278 mnHeight = std::max(mnHeight, aRect.GetHeight());
279 if (nIdx >= maScriptChanges.size())
280 break;
281
282 maScriptChanges[nIdx++].textWidth = nWidth;
283
284 if (nEnd < rText.getLength() && nIdx < nCnt)
285 {
286 nStart = nEnd;
287 nEnd = maScriptChanges[nIdx].changePos;
288 aScript = maScriptChanges[nIdx].scriptType;
289 }
290 else
291 break;
292 }
293 while(true);
294
295 double fRatio = 1;
296 if (mnHeight > mnMaxHeight && mnHeight != 0)
297 fRatio = double(mnMaxHeight) / mnHeight;
298
299 mnHeight *= fRatio;
300 mnBaseLine *= fRatio;
301 if (fRatio != 1)
302 {
303 Size aFontSize;
304 if (m_oFont)
305 {
306 aFontSize = m_oFont->GetFontSize();
307 m_oFont->SetFontSize(Size(aFontSize.Width() * fRatio, aFontSize.Height() * fRatio));
308 }
309 if (m_oCJKFont)
310 {
311 aFontSize = m_oCJKFont->GetFontSize();
312 m_oCJKFont->SetFontSize(Size(aFontSize.Width() * fRatio, aFontSize.Height() * fRatio));
313 }
314 if (m_oCTLFont)
315 {
316 aFontSize = m_oCTLFont->GetFontSize();
317 m_oCTLFont->SetFontSize(Size(aFontSize.Width() * fRatio, aFontSize.Height() * fRatio));
318 }
319
320 for (auto& aChange : maScriptChanges)
321 aChange.textWidth *= fRatio;
322 }
323}
324
326{
327 const OUString& rText = maStyleName;
328
329 // setup the device & draw
331
333 {
335 mrOutputDev.DrawRect(aRectangle);
336 }
337
338 if (maFontColor != COL_AUTO)
340
343
344 Point aFontDrawPosition = aRectangle.TopLeft();
345 aFontDrawPosition.AdjustY(mnBaseLine);
346 if (eRenderAlign == RenderAlign::CENTER)
347 {
348 if (aRectangle.GetHeight() > mnHeight)
349 aFontDrawPosition.AdjustY((aRectangle.GetHeight() - mnHeight) / 2 );
350 }
351
352 SvtScriptType aScript;
353 sal_uInt16 nIdx = 0;
354 sal_Int32 nStart = 0;
355 sal_Int32 nEnd;
356 size_t nCnt = maScriptChanges.size();
357 if (nCnt)
358 {
359 nEnd = maScriptChanges[nIdx].changePos;
360 aScript = maScriptChanges[nIdx].scriptType;
361 }
362 else
363 {
364 nEnd = rText.getLength();
365 aScript = SvtScriptType::LATIN;
366 }
367
368 do
369 {
370 auto oFont = (aScript == SvtScriptType::ASIAN)
371 ? m_oCJKFont
372 : ((aScript == SvtScriptType::COMPLEX)
373 ? m_oCTLFont
374 : m_oFont);
375
377
378 if (oFont)
379 {
380 mrOutputDev.SetFont(*oFont);
381 oFont->QuickDrawText(&mrOutputDev, aFontDrawPosition, rText, nStart, nEnd - nStart, {});
382 }
383 else
384 mrOutputDev.DrawText(aFontDrawPosition, rText, nStart, nEnd - nStart);
385
387
388 aFontDrawPosition.AdjustX(maScriptChanges[nIdx++].textWidth);
389 if (nEnd < rText.getLength() && nIdx < nCnt)
390 {
391 nStart = nEnd;
392 nEnd = maScriptChanges[nIdx].changePos;
393 aScript = maScriptChanges[nIdx].scriptType;
394 }
395 else
396 break;
397 }
398 while(true);
399
401
402 return true;
403}
404
406{
407 assert(!maStyleName.isEmpty()); // must have a preview text here!
409 return; // already initialized
410
412 maScriptChanges.clear();
413
414 auto aEditEngine = EditEngine(nullptr);
415 aEditEngine.SetText(maScriptText);
416
417 auto aScript = aEditEngine.GetScriptType({ 0, 0, 0, 0 });
418 for (sal_Int32 i = 1; i <= maScriptText.getLength(); i++)
419 {
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;
426 }
427}
428
429} // end svx namespace
430
431/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Color maBackgroundColor
void SetFont(const vcl::Font &rNewFont)
void DrawRect(const tools::Rectangle &rRect)
bool GetTextBoundRect(tools::Rectangle &rRect, const OUString &rStr, sal_Int32 nBase=0, sal_Int32 nIndex=0, sal_Int32 nLen=-1, sal_uLong nLayoutWidth=0, KernArraySpan aDXArray=KernArraySpan(), o3tl::span< const sal_Bool > pKashidaArray={}, const SalLayoutGlyphs *pGlyphs=nullptr) const
tools::Long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::text::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
void SetTextColor(const Color &rColor)
void SetFillColor()
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
FontMetric GetFontMetric() const
void SetTextFillColor()
void Push(vcl::PushFlags nFlags=vcl::PushFlags::ALL)
void DrawText(const Point &rStartPt, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, std::vector< tools::Rectangle > *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pLayoutCache=nullptr)
tools::Long AdjustY(tools::Long nVertMove)
tools::Long AdjustX(tools::Long nHorzMove)
sal_uInt16 GetWhich(sal_uInt16 nSlot, bool bDeep=true) const
SfxItemPool * GetPool() const
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
MapUnit GetMapUnit() const
SfxStyleFamily GetFamily() const
virtual std::optional< SfxItemSet > GetItemSetForPreview()
constexpr tools::Long Height() const
constexpr tools::Long Width() const
void SetCaseMap(const SvxCaseMap eNew)
SfxStyleSheetBase * mpStyle
OutputDevice & mrOutputDev
const SfxObjectShell & mrShell
CommonStylePreviewRenderer(const SfxObjectShell &rShell, OutputDevice &rOutputDev, SfxStyleSheetBase *pStyle, tools::Long nMaxHeight)
virtual bool render(const tools::Rectangle &aRectangle, RenderAlign eRenderAlign=RenderAlign::CENTER) override
bool SetFontSize(const SfxItemSet &rSet, sal_uInt16 nSlot, SvxFont &rFont)
constexpr tools::Long Top() const
constexpr Point TopLeft() const
constexpr tools::Long GetHeight() const
constexpr ::Color COL_AUTO(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
virtual OUString GetName() const override
ALIGN_BASELINE
SvtScriptType
int i
sal_Int16 GetCaseMap(sal_Int32 nToken)
static bool GetWhich(const SfxItemSet &rSet, sal_uInt16 nSlot, sal_uInt16 &rWhich)
static bool SetFont(const SfxItemSet &rSet, sal_uInt16 nSlot, SvxFont &rFont)
long Long
const char GetValue[]
double mnHeight
static SfxItemSet & rSet
constexpr TypedWhichId< XFillColorItem > XATTR_FILLCOLOR(XATTR_FILL_FIRST+1)
constexpr TypedWhichId< XFillStyleItem > XATTR_FILLSTYLE(XATTR_FILL_FIRST)