Teach symstore more duplicated DLLs
[LibreOffice.git] / drawinglayer / source / primitive2d / textlayoutdevice.cxx
blob299fea5d90a30d7095a5a2aa4d3c899da07db7a2
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 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <algorithm>
24 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
25 #include <comphelper/processfactory.hxx>
26 #include <comphelper/unique_disposing_ptr.hxx>
27 #include <tools/gen.hxx>
28 #include <vcl/canvastools.hxx>
29 #include <vcl/timer.hxx>
30 #include <vcl/virdev.hxx>
31 #include <vcl/font.hxx>
32 #include <vcl/metric.hxx>
33 #include <i18nlangtag/languagetag.hxx>
34 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
35 #include <vcl/svapp.hxx>
36 #include <o3tl/deleter.hxx>
39 // VDev RevDevice provider
41 namespace
43 class ImpTimedRefDev;
45 //the scoped_timed_RefDev owns an ImpTimeRefDev and releases it on dtor
46 //or disposing of the default XComponentContext which causes the underlying
47 //OutputDevice to get released
49 //The ImpTimerRefDev itself, if the timeout ever gets hit, will call
50 //reset on the scoped_timed_RefDev to release the ImpTimerRefDev early
51 //if its unused for a few minutes
52 class scoped_timed_RefDev : public comphelper::unique_disposing_ptr<ImpTimedRefDev>
54 public:
55 scoped_timed_RefDev() : comphelper::unique_disposing_ptr<ImpTimedRefDev>((css::uno::Reference<css::lang::XComponent>(::comphelper::getProcessComponentContext(), css::uno::UNO_QUERY_THROW)))
60 class the_scoped_timed_RefDev : public rtl::Static<scoped_timed_RefDev, the_scoped_timed_RefDev> {};
62 class ImpTimedRefDev : public Timer
64 scoped_timed_RefDev& mrOwnerOfMe;
65 VclPtr<VirtualDevice> mpVirDev;
66 sal_uInt32 mnUseCount;
68 public:
69 explicit ImpTimedRefDev(scoped_timed_RefDev& rOwnerofMe);
70 virtual ~ImpTimedRefDev() override;
71 virtual void Invoke() override;
73 VirtualDevice& acquireVirtualDevice();
74 void releaseVirtualDevice();
77 ImpTimedRefDev::ImpTimedRefDev(scoped_timed_RefDev& rOwnerOfMe)
78 : Timer( "drawinglayer ImpTimedRefDev destroy mpVirDev" ),
79 mrOwnerOfMe(rOwnerOfMe),
80 mpVirDev(nullptr),
81 mnUseCount(0)
83 SetTimeout(3L * 60L * 1000L); // three minutes
84 Start();
87 ImpTimedRefDev::~ImpTimedRefDev()
89 OSL_ENSURE(0 == mnUseCount, "destruction of a still used ImpTimedRefDev (!)");
90 const SolarMutexGuard aSolarGuard;
91 mpVirDev.disposeAndClear();
94 void ImpTimedRefDev::Invoke()
96 // for obvious reasons, do not call anything after this
97 mrOwnerOfMe.reset();
100 VirtualDevice& ImpTimedRefDev::acquireVirtualDevice()
102 if(!mpVirDev)
104 mpVirDev = VclPtr<VirtualDevice>::Create();
105 mpVirDev->SetReferenceDevice( VirtualDevice::RefDevMode::MSO1 );
108 if(!mnUseCount)
110 Stop();
113 mnUseCount++;
115 return *mpVirDev;
118 void ImpTimedRefDev::releaseVirtualDevice()
120 OSL_ENSURE(mnUseCount, "mismatch call number to releaseVirtualDevice() (!)");
121 mnUseCount--;
123 if(!mnUseCount)
125 Start();
128 } // end of anonymous namespace
131 // access to one global ImpTimedRefDev incarnation in namespace drawinglayer::primitive
133 namespace drawinglayer
135 namespace primitive2d
137 // static methods here
138 static VirtualDevice& acquireGlobalVirtualDevice()
140 scoped_timed_RefDev& rStdRefDevice = the_scoped_timed_RefDev::get();
142 if(!rStdRefDevice)
143 rStdRefDevice.reset(new ImpTimedRefDev(rStdRefDevice));
145 return rStdRefDevice->acquireVirtualDevice();
148 static void releaseGlobalVirtualDevice()
150 scoped_timed_RefDev& rStdRefDevice = the_scoped_timed_RefDev::get();
152 OSL_ENSURE(rStdRefDevice, "releaseGlobalVirtualDevice() without prior acquireGlobalVirtualDevice() call(!)");
153 rStdRefDevice->releaseVirtualDevice();
156 TextLayouterDevice::TextLayouterDevice()
157 : maSolarGuard(),
158 mrDevice(acquireGlobalVirtualDevice())
162 TextLayouterDevice::~TextLayouterDevice() COVERITY_NOEXCEPT_FALSE
164 releaseGlobalVirtualDevice();
167 void TextLayouterDevice::setFont(const vcl::Font& rFont)
169 mrDevice.SetFont( rFont );
172 void TextLayouterDevice::setFontAttribute(
173 const attribute::FontAttribute& rFontAttribute,
174 double fFontScaleX,
175 double fFontScaleY,
176 const css::lang::Locale& rLocale)
178 setFont(getVclFontFromFontAttribute(
179 rFontAttribute,
180 fFontScaleX,
181 fFontScaleY,
182 0.0,
183 rLocale));
186 double TextLayouterDevice::getOverlineOffset() const
188 const ::FontMetric& rMetric = mrDevice.GetFontMetric();
189 double fRet = (rMetric.GetInternalLeading() / 2.0) - rMetric.GetAscent();
190 return fRet;
193 double TextLayouterDevice::getUnderlineOffset() const
195 const ::FontMetric& rMetric = mrDevice.GetFontMetric();
196 double fRet = rMetric.GetDescent() / 2.0;
197 return fRet;
200 double TextLayouterDevice::getStrikeoutOffset() const
202 const ::FontMetric& rMetric = mrDevice.GetFontMetric();
203 double fRet = (rMetric.GetAscent() - rMetric.GetInternalLeading()) / 3.0;
204 return fRet;
207 double TextLayouterDevice::getOverlineHeight() const
209 const ::FontMetric& rMetric = mrDevice.GetFontMetric();
210 double fRet = rMetric.GetInternalLeading() / 2.5;
211 return fRet;
214 double TextLayouterDevice::getUnderlineHeight() const
216 const ::FontMetric& rMetric = mrDevice.GetFontMetric();
217 double fRet = rMetric.GetDescent() / 4.0;
218 return fRet;
221 double TextLayouterDevice::getTextHeight() const
223 return mrDevice.GetTextHeight();
226 double TextLayouterDevice::getTextWidth(
227 const OUString& rText,
228 sal_uInt32 nIndex,
229 sal_uInt32 nLength) const
231 return mrDevice.GetTextWidth(rText, nIndex, nLength);
234 void TextLayouterDevice::getTextOutlines(
235 basegfx::B2DPolyPolygonVector& rB2DPolyPolyVector,
236 const OUString& rText,
237 sal_uInt32 nIndex,
238 sal_uInt32 nLength,
239 const std::vector< double >& rDXArray) const
241 const sal_uInt32 nDXArrayCount(rDXArray.size());
242 sal_uInt32 nTextLength(nLength);
243 const sal_uInt32 nStringLength(rText.getLength());
245 if(nTextLength + nIndex > nStringLength)
247 nTextLength = nStringLength - nIndex;
250 if(nDXArrayCount)
252 OSL_ENSURE(nDXArrayCount == nTextLength, "DXArray size does not correspond to text portion size (!)");
253 std::vector< long > aIntegerDXArray(nDXArrayCount);
255 for(sal_uInt32 a(0); a < nDXArrayCount; a++)
257 aIntegerDXArray[a] = basegfx::fround(rDXArray[a]);
260 mrDevice.GetTextOutlines(
261 rB2DPolyPolyVector,
262 rText,
263 nIndex,
264 nIndex,
265 nLength,
267 aIntegerDXArray.data());
269 else
271 mrDevice.GetTextOutlines(
272 rB2DPolyPolyVector,
273 rText,
274 nIndex,
275 nIndex,
276 nLength);
280 basegfx::B2DRange TextLayouterDevice::getTextBoundRect(
281 const OUString& rText,
282 sal_uInt32 nIndex,
283 sal_uInt32 nLength) const
285 sal_uInt32 nTextLength(nLength);
286 const sal_uInt32 nStringLength(rText.getLength());
288 if(nTextLength + nIndex > nStringLength)
290 nTextLength = nStringLength - nIndex;
293 if(nTextLength)
295 ::tools::Rectangle aRect;
297 mrDevice.GetTextBoundRect(
298 aRect,
299 rText,
300 nIndex,
301 nIndex,
302 nLength);
304 // #i104432#, #i102556# take empty results into account
305 if(!aRect.IsEmpty())
307 return vcl::unotools::b2DRectangleFromRectangle(aRect);
311 return basegfx::B2DRange();
314 double TextLayouterDevice::getFontAscent() const
316 const ::FontMetric& rMetric = mrDevice.GetFontMetric();
317 return rMetric.GetAscent();
320 double TextLayouterDevice::getFontDescent() const
322 const ::FontMetric& rMetric = mrDevice.GetFontMetric();
323 return rMetric.GetDescent();
326 void TextLayouterDevice::addTextRectActions(
327 const ::tools::Rectangle& rRectangle,
328 const OUString& rText,
329 DrawTextFlags nStyle,
330 GDIMetaFile& rGDIMetaFile) const
332 mrDevice.AddTextRectActions(
333 rRectangle, rText, nStyle, rGDIMetaFile);
336 std::vector< double > TextLayouterDevice::getTextArray(
337 const OUString& rText,
338 sal_uInt32 nIndex,
339 sal_uInt32 nLength) const
341 std::vector< double > aRetval;
342 sal_uInt32 nTextLength(nLength);
343 const sal_uInt32 nStringLength(rText.getLength());
345 if(nTextLength + nIndex > nStringLength)
347 nTextLength = nStringLength - nIndex;
350 if(nTextLength)
352 aRetval.reserve(nTextLength);
353 std::vector<long> aArray(nTextLength);
354 mrDevice.GetTextArray(rText, aArray.data(), nIndex, nLength);
355 aRetval.assign(aArray.begin(), aArray.end());
358 return aRetval;
361 } // end of namespace primitive2d
362 } // end of namespace drawinglayer
365 // helper methods for vcl font handling
367 namespace drawinglayer
369 namespace primitive2d
371 vcl::Font getVclFontFromFontAttribute(
372 const attribute::FontAttribute& rFontAttribute,
373 double fFontScaleX,
374 double fFontScaleY,
375 double fFontRotation,
376 const css::lang::Locale& rLocale)
378 // detect FontScaling
379 const sal_uInt32 nHeight(basegfx::fround(fabs(fFontScaleY)));
380 const sal_uInt32 nWidth(basegfx::fround(fabs(fFontScaleX)));
381 const bool bFontIsScaled(nHeight != nWidth);
383 #ifdef _WIN32
384 // for WIN32 systems, start with creating an unscaled font. If FontScaling
385 // is wanted, that width needs to be adapted using FontMetric again to get a
386 // width of the unscaled font
387 vcl::Font aRetval(
388 rFontAttribute.getFamilyName(),
389 rFontAttribute.getStyleName(),
390 Size(0, nHeight));
391 #else
392 // for non-WIN32 systems things are easier since these accept a Font creation
393 // with initially nWidth != nHeight for FontScaling. Despite that, use zero for
394 // FontWidth when no scaling is used to explicitly have that zero when e.g. the
395 // Font would be recorded in a MetaFile (The MetaFile FontAction WILL record a
396 // set FontWidth; import that in a WIN32 system, and trouble is there)
397 vcl::Font aRetval(
398 rFontAttribute.getFamilyName(),
399 rFontAttribute.getStyleName(),
400 Size(bFontIsScaled ? std::max<sal_uInt32>(nWidth, 1) : 0, nHeight));
401 #endif
402 // define various other FontAttribute
403 aRetval.SetAlignment(ALIGN_BASELINE);
404 aRetval.SetCharSet(rFontAttribute.getSymbol() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE);
405 aRetval.SetVertical(rFontAttribute.getVertical());
406 aRetval.SetWeight(static_cast<FontWeight>(rFontAttribute.getWeight()));
407 aRetval.SetItalic(rFontAttribute.getItalic() ? ITALIC_NORMAL : ITALIC_NONE);
408 aRetval.SetOutline(rFontAttribute.getOutline());
409 aRetval.SetPitch(rFontAttribute.getMonospaced() ? PITCH_FIXED : PITCH_VARIABLE);
410 aRetval.SetLanguage(LanguageTag::convertToLanguageType( rLocale, false));
412 // handle FontRotation (if defined)
413 if(!basegfx::fTools::equalZero(fFontRotation))
415 sal_Int16 aRotate10th(static_cast<sal_Int16>(fFontRotation * (-1800.0/F_PI)));
416 aRetval.SetOrientation(aRotate10th % 3600);
419 return aRetval;
422 attribute::FontAttribute getFontAttributeFromVclFont(
423 basegfx::B2DVector& o_rSize,
424 const vcl::Font& rFont,
425 bool bRTL,
426 bool bBiDiStrong)
428 const attribute::FontAttribute aRetval(
429 rFont.GetFamilyName(),
430 rFont.GetStyleName(),
431 static_cast<sal_uInt16>(rFont.GetWeight()),
432 RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet(),
433 rFont.IsVertical(),
434 ITALIC_NONE != rFont.GetItalic(),
435 PITCH_FIXED == rFont.GetPitch(),
436 rFont.IsOutline(),
437 bRTL,
438 bBiDiStrong);
439 // TODO: eKerning
441 // set FontHeight and init to no FontScaling
442 o_rSize.setY(std::max<long>(rFont.GetFontSize().getHeight(), 0));
443 o_rSize.setX(o_rSize.getY());
445 #ifdef _WIN32
446 // for WIN32 systems, the FontScaling at the Font is detected by
447 // checking that FontWidth != 0. When FontScaling is used, WIN32
448 // needs to do extra stuff to detect the correct width (since it's
449 // zero and not equal the font height) and its relationship to
450 // the height
451 if(rFont.GetFontSize().getWidth() > 0)
453 vcl::Font aUnscaledFont(rFont);
454 aUnscaledFont.SetAverageFontWidth(0);
455 const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont));
457 if(aUnscaledFontMetric.GetAverageFontWidth() > 0)
459 const double fScaleFactor(static_cast<double>(rFont.GetFontSize().getWidth()) / static_cast<double>(aUnscaledFontMetric.GetAverageFontWidth()));
460 o_rSize.setX(fScaleFactor * o_rSize.getY());
463 #else
464 // For non-WIN32 systems the detection is the same, but the value
465 // is easier achieved since width == height is interpreted as no
466 // scaling. Ergo, Width == 0 means width == height, and width != 0
467 // means the scaling is in the direct relation of width to height
468 if(rFont.GetFontSize().getWidth() > 0)
470 o_rSize.setX(static_cast<double>(rFont.GetFontSize().getWidth()));
472 #endif
473 return aRetval;
475 } // end of namespace primitive2d
476 } // end of namespace drawinglayer
478 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */