LibreOffice Module vcl (master)  1
utils.hxx
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  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #ifndef INCLUDED_VCL_INC_SKIA_UTILS_H
21 #define INCLUDED_VCL_INC_SKIA_UTILS_H
22 
23 #include <vcl/skia/SkiaHelper.hxx>
24 
25 #include <tools/gen.hxx>
26 #include <driverblocklist.hxx>
27 #include <vcl/bitmap.hxx>
28 #include <vcl/salgtype.hxx>
29 
30 #include <test/GraphicsRenderTests.hxx>
31 
32 #include <premac.h>
33 #include <SkRegion.h>
34 #include <SkSurface.h>
35 #include <tools/sk_app/WindowContext.h>
36 #include <postmac.h>
37 
38 #include <string_view>
39 
40 namespace SkiaHelper
41 {
42 // Get the one shared GrDirectContext instance.
43 GrDirectContext* getSharedGrDirectContext();
44 
45 void disableRenderMethod(RenderMethod method);
46 
47 // Create SkSurface, GPU-backed if possible.
48 VCL_DLLPUBLIC sk_sp<SkSurface> createSkSurface(int width, int height,
49  SkColorType type = kN32_SkColorType,
50  SkAlphaType alpha = kPremul_SkAlphaType);
51 
52 inline sk_sp<SkSurface> createSkSurface(const Size& size, SkColorType type = kN32_SkColorType,
53  SkAlphaType alpha = kPremul_SkAlphaType)
54 {
55  return createSkSurface(size.Width(), size.Height(), type, alpha);
56 }
57 
58 inline sk_sp<SkSurface> createSkSurface(int width, int height, SkAlphaType alpha)
59 {
60  return createSkSurface(width, height, kN32_SkColorType, alpha);
61 }
62 
63 inline sk_sp<SkSurface> createSkSurface(const Size& size, SkAlphaType alpha)
64 {
65  return createSkSurface(size.Width(), size.Height(), kN32_SkColorType, alpha);
66 }
67 
68 // Create SkImage, GPU-backed if possible.
69 VCL_DLLPUBLIC sk_sp<SkImage> createSkImage(const SkBitmap& bitmap);
70 
71 // Call surface->makeImageSnapshot() and abort on failure.
72 VCL_DLLPUBLIC sk_sp<SkImage> makeCheckedImageSnapshot(sk_sp<SkSurface> surface);
73 VCL_DLLPUBLIC sk_sp<SkImage> makeCheckedImageSnapshot(sk_sp<SkSurface> surface,
74  const SkIRect& bounds);
75 
76 inline Size imageSize(const sk_sp<SkImage>& image) { return Size(image->width(), image->height()); }
77 
78 inline SkColor toSkColor(Color color)
79 {
80  return SkColorSetARGB(color.GetAlpha(), color.GetRed(), color.GetGreen(), color.GetBlue());
81 }
82 
83 inline SkColor toSkColorWithTransparency(Color aColor, double fTransparency)
84 {
85  return SkColorSetA(toSkColor(aColor), 255 * (1.0 - fTransparency));
86 }
87 
88 inline SkColor toSkColorWithIntensity(Color color, int intensity)
89 {
90  return SkColorSetARGB(color.GetAlpha(), color.GetRed() * intensity / 100,
91  color.GetGreen() * intensity / 100, color.GetBlue() * intensity / 100);
92 }
93 
94 inline Color fromSkColor(SkColor color)
95 {
96  return Color(ColorAlpha, SkColorGetA(color), SkColorGetR(color), SkColorGetG(color),
97  SkColorGetB(color));
98 }
99 
100 // Whether to use GetSkImage() that checks for delayed scaling or whether to access
101 // the stored image directly without checks.
103 {
106 };
107 
108 // Sets SkBlender that will do an invert operation.
109 void setBlenderInvert(SkPaint* paint);
110 // Sets SkBlender that will do a xor operation.
111 void setBlenderXor(SkPaint* paint);
112 
113 // Must be called in any VCL backend before any Skia functionality is used.
114 // If not set, Skia will be disabled.
115 VCL_DLLPUBLIC void
116  prepareSkia(std::unique_ptr<sk_app::WindowContext> (*createGpuWindowContext)(bool));
117 
118 // Shared cache of images.
119 void addCachedImage(const OString& key, sk_sp<SkImage> image);
120 sk_sp<SkImage> findCachedImage(const OString& key);
121 void removeCachedImage(sk_sp<SkImage> image);
123 
124 // Get checksum of the image content, only for raster images. Is cached,
125 // but may still be somewhat expensive.
126 uint32_t getSkImageChecksum(sk_sp<SkImage> image);
127 
128 // SkSurfaceProps to be used by all Skia surfaces.
129 VCL_DLLPUBLIC const SkSurfaceProps* surfaceProps();
130 // Set pixel geometry to be used by SkSurfaceProps.
131 VCL_DLLPUBLIC void setPixelGeometry(SkPixelGeometry pixelGeometry);
132 
133 inline bool isUnitTestRunning(const char* name = nullptr)
134 {
135  if (name == nullptr)
136  {
137  static const char* const testname = getenv("LO_TESTNAME");
138  if (testname != nullptr)
139  return true;
140  return !vcl::test::activeGraphicsRenderTest().isEmpty();
141  }
142  const char* const testname = getenv("LO_TESTNAME");
143  if (testname != nullptr && std::string_view(name) == testname)
144  return true;
145  return vcl::test::activeGraphicsRenderTest().equalsAscii(name);
146 }
147 
148 // Scaling done on the GPU is fast, but bicubic done in raster mode can be slow
149 // if done too much, and it generally shouldn't be needed for to-screen drawing.
150 // In that case use only BmpScaleFlag::Default, which is bilinear+mipmap,
151 // which should be good enough (and that's what the "super" bitmap scaling
152 // algorithm done by VCL does as well).
154 {
156 }
157 
158 // Normal scaling algorithms have a poor quality when downscaling a lot.
159 // https://bugs.chromium.org/p/skia/issues/detail?id=11810 suggests to use mipmaps
160 // in such a case, which is annoying to do explicitly instead of Skia deciding which
161 // algorithm would be the best, but now with Skia removing SkFilterQuality and requiring
162 // explicitly being told what algorithm to use this appears to be the best we can do.
163 // Anything scaled down at least this ratio will use linear+mipmaps.
164 constexpr int downscaleRatioThreshold = 4;
165 
166 inline SkSamplingOptions makeSamplingOptions(BmpScaleFlag scalingType, SkMatrix matrix,
167  int scalingFactor)
168 {
169  switch (scalingType)
170  {
172  if (scalingFactor != 1)
173  matrix.postScale(scalingFactor, scalingFactor);
174  if (matrix.getScaleX() <= 1.0 / downscaleRatioThreshold
175  || matrix.getScaleY() <= 1.0 / downscaleRatioThreshold)
176  return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
177  return SkSamplingOptions(SkCubicResampler::Mitchell());
179  // Use SkMipmapMode::kNearest for better quality when downscaling. SkMipmapMode::kLinear
180  // would be even better, but it is not specially optimized in raster mode.
181  return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest);
182  case BmpScaleFlag::Fast:
184  return SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone);
185  default:
186  assert(false);
187  return SkSamplingOptions();
188  }
189 }
190 
191 inline SkSamplingOptions makeSamplingOptions(BmpScaleFlag scalingType, const Size& srcSize,
192  Size destSize, int scalingFactor)
193 {
194  switch (scalingType)
195  {
197  if (scalingFactor != 1)
198  destSize *= scalingFactor;
199  if (srcSize.Width() / destSize.Width() >= downscaleRatioThreshold
200  || srcSize.Height() / destSize.Height() >= downscaleRatioThreshold)
201  return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
202  return SkSamplingOptions(SkCubicResampler::Mitchell());
204  // As in the first overload, use kNearest.
205  return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest);
206  case BmpScaleFlag::Fast:
208  return SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone);
209  default:
210  assert(false);
211  return SkSamplingOptions();
212  }
213 }
214 
215 inline SkSamplingOptions makeSamplingOptions(const SalTwoRect& rPosAry, int scalingFactor,
216  int srcScalingFactor, bool isGPU)
217 {
218  // If there will be scaling, make it smooth, but not in unittests, as those often
219  // require exact color values and would be confused by this.
220  if (isUnitTestRunning())
221  return SkSamplingOptions(); // none
222  Size srcSize(rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
223  Size destSize(rPosAry.mnDestWidth, rPosAry.mnDestHeight);
224  if (scalingFactor != 1)
225  destSize *= scalingFactor;
226  if (srcScalingFactor != 1)
227  srcSize *= srcScalingFactor;
228  if (srcSize != destSize)
229  return makeSamplingOptions(goodScalingQuality(isGPU), srcSize, destSize, 1);
230  return SkSamplingOptions(); // none
231 }
232 
233 inline SkRect scaleRect(const SkRect& rect, int scaling)
234 {
235  return SkRect::MakeXYWH(rect.x() * scaling, rect.y() * scaling, rect.width() * scaling,
236  rect.height() * scaling);
237 }
238 
239 inline SkIRect scaleRect(const SkIRect& rect, int scaling)
240 {
241  return SkIRect::MakeXYWH(rect.x() * scaling, rect.y() * scaling, rect.width() * scaling,
242  rect.height() * scaling);
243 }
244 
245 #ifdef DBG_UTIL
246 void prefillSurface(const sk_sp<SkSurface>& surface);
247 #endif
248 
249 VCL_DLLPUBLIC void dump(const SkBitmap& bitmap, const char* file);
250 VCL_DLLPUBLIC void dump(const sk_sp<SkImage>& image, const char* file);
251 VCL_DLLPUBLIC void dump(const sk_sp<SkSurface>& surface, const char* file);
252 
253 VCL_DLLPUBLIC extern uint32_t vendorId;
254 
256 {
257  return DriverBlocklist::GetVendorFromId(vendorId);
258 }
259 
260 } // namespace SkiaHelper
261 
262 // For unittests.
263 namespace SkiaTests
264 {
265 VCL_DLLPUBLIC bool matrixNeedsHighQuality(const SkMatrix& matrix);
266 }
267 
268 template <typename charT, typename traits>
269 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream,
270  const SkRect& rectangle)
271 {
272  if (rectangle.isEmpty())
273  return stream << "EMPTY";
274  else
275  return stream << rectangle.width() << 'x' << rectangle.height() << "@(" << rectangle.x()
276  << ',' << rectangle.y() << ")";
277 }
278 
279 template <typename charT, typename traits>
280 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream,
281  const SkIRect& rectangle)
282 {
283  if (rectangle.isEmpty())
284  return stream << "EMPTY";
285  else
286  return stream << rectangle.width() << 'x' << rectangle.height() << "@(" << rectangle.x()
287  << ',' << rectangle.y() << ")";
288 }
289 
290 template <typename charT, typename traits>
291 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream,
292  const SkRegion& region)
293 {
294  if (region.isEmpty())
295  return stream << "EMPTY";
296  stream << "(";
297  SkRegion::Iterator it(region);
298  for (int i = 0; !it.done(); it.next(), ++i)
299  stream << "[" << i << "] " << it.rect();
300  stream << ")";
301  return stream;
302 }
303 
304 template <typename charT, typename traits>
305 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream,
306  const SkMatrix& matrix)
307 {
308  return stream << "[" << matrix[0] << " " << matrix[1] << " " << matrix[2] << "]"
309  << "[" << matrix[3] << " " << matrix[4] << " " << matrix[5] << "]"
310  << "[" << matrix[6] << " " << matrix[7] << " " << matrix[8] << "]";
311 }
312 
313 template <typename charT, typename traits>
314 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream,
315  const SkImage& image)
316 {
317  // G - on GPU
318  return stream << static_cast<const void*>(&image) << " " << Size(image.width(), image.height())
319  << "/" << (SkColorTypeBytesPerPixel(image.imageInfo().colorType()) * 8)
320  << (image.isTextureBacked() ? "G" : "");
321 }
322 template <typename charT, typename traits>
323 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream,
324  const sk_sp<SkImage>& image)
325 {
326  if (image == nullptr)
327  return stream << "(null)";
328  return stream << *image;
329 }
330 
331 #endif // INCLUDED_VCL_INC_SKIA_UTILS_H
332 
333 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void setBlenderInvert(SkPaint *paint)
sal_uInt8 GetAlpha() const
sal_uInt8 GetRed() const
GrDirectContext * getSharedGrDirectContext()
VCL_DLLPUBLIC sk_sp< SkImage > makeCheckedImageSnapshot(sk_sp< SkSurface > surface)
BmpScaleFlag goodScalingQuality(bool isGPU)
Definition: utils.hxx:153
#define VCL_DLLPUBLIC
Definition: dllapi.h:29
void setBlenderXor(SkPaint *paint)
long Long
Size imageSize(const sk_sp< SkImage > &image)
Definition: utils.hxx:76
SkColor toSkColorWithTransparency(Color aColor, double fTransparency)
Definition: utils.hxx:83
VCL_DLLPUBLIC const SkSurfaceProps * surfaceProps()
VCL_DLLPUBLIC void setPixelGeometry(SkPixelGeometry pixelGeometry)
const OUString & activeGraphicsRenderTest()
tools::Long mnSrcHeight
Definition: salgtype.hxx:43
tools::Long mnSrcWidth
Definition: salgtype.hxx:42
bool isUnitTestRunning(const char *name=nullptr)
Definition: utils.hxx:133
sk_sp< SkImage > findCachedImage(const OString &key)
DeviceVendor GetVendorFromId(uint32_t id)
Returns vendor for the given vendor ID, or VendorAll if not known.
tools::Long mnDestWidth
Definition: salgtype.hxx:46
constexpr tools::Long Width() const
VCL_DLLPUBLIC bool matrixNeedsHighQuality(const SkMatrix &matrix)
VCL_DLLPUBLIC sk_sp< SkImage > createSkImage(const SkBitmap &bitmap)
constexpr int downscaleRatioThreshold
Definition: utils.hxx:164
sal_uInt8 GetBlue() const
tools::Long mnDestHeight
Definition: salgtype.hxx:47
tools::Long maxImageCacheSize()
int i
uint32_t getSkImageChecksum(sk_sp< SkImage > image)
void disableRenderMethod(RenderMethod method)
SkSamplingOptions makeSamplingOptions(BmpScaleFlag scalingType, SkMatrix matrix, int scalingFactor)
Definition: utils.hxx:166
DriverBlocklist::DeviceVendor getVendor()
Definition: utils.hxx:255
SkColor toSkColorWithIntensity(Color color, int intensity)
Definition: utils.hxx:88
void prefillSurface(const sk_sp< SkSurface > &surface)
VCL_DLLPUBLIC void dump(const SkBitmap &bitmap, const char *file)
Reference< XOutputStream > stream
Color fromSkColor(SkColor color)
Definition: utils.hxx:94
sal_uInt8 GetGreen() const
VCL_DLLPUBLIC uint32_t vendorId
def rectangle(l)
constexpr tools::Long Height() const
VCL_DLLPUBLIC sk_sp< SkSurface > createSkSurface(int width, int height, SkColorType type=kN32_SkColorType, SkAlphaType alpha=kPremul_SkAlphaType)
VCL_DLLPUBLIC void prepareSkia(std::unique_ptr< sk_app::WindowContext >(*createGpuWindowContext)(bool))
const char * name
void removeCachedImage(sk_sp< SkImage > image)
SkColor toSkColor(Color color)
Definition: utils.hxx:78
SkRect scaleRect(const SkRect &rect, int scaling)
Definition: utils.hxx:233
ResultType type
void addCachedImage(const OString &key, sk_sp< SkImage > image)
ColorAlpha