move code to helper functions
[LibreOffice.git] / vcl / inc / skia / utils.hxx
blob0583e9ceb624f12ad09637f76a996a5dfad7c83b
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 #ifndef INCLUDED_VCL_INC_SKIA_UTILS_H
21 #define INCLUDED_VCL_INC_SKIA_UTILS_H
23 #include <vcl/skia/SkiaHelper.hxx>
25 #include <tools/gen.hxx>
26 #include <driverblocklist.hxx>
27 #include <vcl/bitmap.hxx>
28 #include <vcl/salgtype.hxx>
30 #include <premac.h>
31 #include <SkRegion.h>
32 #include <SkSurface.h>
33 #include <tools/sk_app/WindowContext.h>
34 #include <postmac.h>
36 #include <string_view>
38 namespace SkiaHelper
40 // Get the one shared GrDirectContext instance.
41 GrDirectContext* getSharedGrDirectContext();
43 void disableRenderMethod(RenderMethod method);
45 // Create SkSurface, GPU-backed if possible.
46 VCL_DLLPUBLIC sk_sp<SkSurface> createSkSurface(int width, int height,
47 SkColorType type = kN32_SkColorType,
48 SkAlphaType alpha = kPremul_SkAlphaType);
50 inline sk_sp<SkSurface> createSkSurface(const Size& size, SkColorType type = kN32_SkColorType,
51 SkAlphaType alpha = kPremul_SkAlphaType)
53 return createSkSurface(size.Width(), size.Height(), type, alpha);
56 inline sk_sp<SkSurface> createSkSurface(int width, int height, SkAlphaType alpha)
58 return createSkSurface(width, height, kN32_SkColorType, alpha);
61 inline sk_sp<SkSurface> createSkSurface(const Size& size, SkAlphaType alpha)
63 return createSkSurface(size.Width(), size.Height(), kN32_SkColorType, alpha);
66 // Create SkImage, GPU-backed if possible.
67 VCL_DLLPUBLIC sk_sp<SkImage> createSkImage(const SkBitmap& bitmap);
69 // Call surface->makeImageSnapshot() and abort on failure.
70 VCL_DLLPUBLIC sk_sp<SkImage> makeCheckedImageSnapshot(sk_sp<SkSurface> surface);
71 VCL_DLLPUBLIC sk_sp<SkImage> makeCheckedImageSnapshot(sk_sp<SkSurface> surface,
72 const SkIRect& bounds);
74 inline Size imageSize(const sk_sp<SkImage>& image) { return Size(image->width(), image->height()); }
76 inline SkColor toSkColor(Color color)
78 return SkColorSetARGB(color.GetAlpha(), color.GetRed(), color.GetGreen(), color.GetBlue());
81 inline SkColor toSkColorWithTransparency(Color aColor, double fTransparency)
83 return SkColorSetA(toSkColor(aColor), 255 * (1.0 - fTransparency));
86 inline SkColor toSkColorWithIntensity(Color color, int intensity)
88 return SkColorSetARGB(color.GetAlpha(), color.GetRed() * intensity / 100,
89 color.GetGreen() * intensity / 100, color.GetBlue() * intensity / 100);
92 inline Color fromSkColor(SkColor color)
94 return Color(ColorAlpha, SkColorGetA(color), SkColorGetR(color), SkColorGetG(color),
95 SkColorGetB(color));
98 // Whether to use GetSkImage() that checks for delayed scaling or whether to access
99 // the stored image directly without checks.
100 enum DirectImage
102 Yes,
106 // Do 'paint->setBlendMode(SkBlendMode::kDifference)' (workaround for buggy drivers).
107 void setBlendModeDifference(SkPaint* paint);
109 // Must be called in any VCL backend before any Skia functionality is used.
110 // If not set, Skia will be disabled.
111 VCL_DLLPUBLIC void
112 prepareSkia(std::unique_ptr<sk_app::WindowContext> (*createGpuWindowContext)(bool));
114 // Shared cache of images.
115 void addCachedImage(const OString& key, sk_sp<SkImage> image);
116 sk_sp<SkImage> findCachedImage(const OString& key);
117 void removeCachedImage(sk_sp<SkImage> image);
118 tools::Long maxImageCacheSize();
120 // SkSurfaceProps to be used by all Skia surfaces.
121 VCL_DLLPUBLIC const SkSurfaceProps* surfaceProps();
122 // Set pixel geometry to be used by SkSurfaceProps.
123 VCL_DLLPUBLIC void setPixelGeometry(SkPixelGeometry pixelGeometry);
125 inline bool isUnitTestRunning(const char* name = nullptr)
127 if (name == nullptr)
129 static const char* const testname = getenv("LO_TESTNAME");
130 return testname != nullptr;
132 const char* const testname = getenv("LO_TESTNAME");
133 return testname != nullptr && std::string_view(name) == testname;
136 // Normal scaling algorithms have a poor quality when downscaling a lot.
137 // https://bugs.chromium.org/p/skia/issues/detail?id=11810 suggests to use mipmaps
138 // in such a case, which is annoying to do explicitly instead of Skia deciding which
139 // algorithm would be the best, but now with Skia removing SkFilterQuality and requiring
140 // explicitly being told what algorithm to use this appears to be the best we can do.
141 // Anything scaled down at least this ratio will use linear+mipmaps.
142 constexpr int downscaleRatioThreshold = 4;
144 inline SkSamplingOptions makeSamplingOptions(BmpScaleFlag scalingType, SkMatrix matrix,
145 int scalingFactor)
147 switch (scalingType)
149 case BmpScaleFlag::BestQuality:
150 if (scalingFactor != 1)
151 matrix.postScale(scalingFactor, scalingFactor);
152 if (matrix.getScaleX() <= 1.0 / downscaleRatioThreshold
153 || matrix.getScaleY() <= 1.0 / downscaleRatioThreshold)
154 return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
155 return SkSamplingOptions(SkCubicResampler::Mitchell());
156 case BmpScaleFlag::Default:
157 return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone);
158 case BmpScaleFlag::Fast:
159 case BmpScaleFlag::NearestNeighbor:
160 return SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone);
161 default:
162 assert(false);
163 return SkSamplingOptions();
167 inline SkSamplingOptions makeSamplingOptions(BmpScaleFlag scalingType, const Size& srcSize,
168 Size destSize, int scalingFactor)
170 switch (scalingType)
172 case BmpScaleFlag::BestQuality:
173 if (scalingFactor != 1)
174 destSize *= scalingFactor;
175 if (srcSize.Width() / destSize.Width() >= downscaleRatioThreshold
176 || srcSize.Height() / destSize.Height() >= downscaleRatioThreshold)
177 return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
178 return SkSamplingOptions(SkCubicResampler::Mitchell());
179 case BmpScaleFlag::Default:
180 return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone);
181 case BmpScaleFlag::Fast:
182 case BmpScaleFlag::NearestNeighbor:
183 return SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone);
184 default:
185 assert(false);
186 return SkSamplingOptions();
190 inline SkSamplingOptions makeSamplingOptions(const SalTwoRect& rPosAry, int scalingFactor,
191 int srcScalingFactor = 1)
193 // If there will be scaling, make it smooth, but not in unittests, as those often
194 // require exact color values and would be confused by this.
195 if (isUnitTestRunning())
196 return SkSamplingOptions(); // none
197 Size srcSize(rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
198 Size destSize(rPosAry.mnDestWidth, rPosAry.mnDestHeight);
199 if (scalingFactor != 1)
200 destSize *= scalingFactor;
201 if (srcScalingFactor != 1)
202 srcSize *= srcScalingFactor;
203 if (srcSize != destSize)
205 if (srcSize.Width() / destSize.Width() >= downscaleRatioThreshold
206 || srcSize.Height() / destSize.Height() >= downscaleRatioThreshold)
207 return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
208 return SkSamplingOptions(SkCubicResampler::Mitchell()); // best
210 return SkSamplingOptions(); // none
213 inline SkRect scaleRect(const SkRect& rect, int scaling)
215 return SkRect::MakeXYWH(rect.x() * scaling, rect.y() * scaling, rect.width() * scaling,
216 rect.height() * scaling);
219 inline SkIRect scaleRect(const SkIRect& rect, int scaling)
221 return SkIRect::MakeXYWH(rect.x() * scaling, rect.y() * scaling, rect.width() * scaling,
222 rect.height() * scaling);
225 #ifdef DBG_UTIL
226 void prefillSurface(const sk_sp<SkSurface>& surface);
227 #endif
229 VCL_DLLPUBLIC void dump(const SkBitmap& bitmap, const char* file);
230 VCL_DLLPUBLIC void dump(const sk_sp<SkImage>& image, const char* file);
231 VCL_DLLPUBLIC void dump(const sk_sp<SkSurface>& surface, const char* file);
233 VCL_DLLPUBLIC extern uint32_t vendorId;
235 inline DriverBlocklist::DeviceVendor getVendor()
237 return DriverBlocklist::GetVendorFromId(vendorId);
240 } // namespace SkiaHelper
242 // For unittests.
243 namespace SkiaTests
245 VCL_DLLPUBLIC bool matrixNeedsHighQuality(const SkMatrix& matrix);
248 template <typename charT, typename traits>
249 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream,
250 const SkRect& rectangle)
252 if (rectangle.isEmpty())
253 return stream << "EMPTY";
254 else
255 return stream << rectangle.width() << 'x' << rectangle.height() << "@(" << rectangle.x()
256 << ',' << rectangle.y() << ")";
259 template <typename charT, typename traits>
260 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream,
261 const SkIRect& rectangle)
263 if (rectangle.isEmpty())
264 return stream << "EMPTY";
265 else
266 return stream << rectangle.width() << 'x' << rectangle.height() << "@(" << rectangle.x()
267 << ',' << rectangle.y() << ")";
270 template <typename charT, typename traits>
271 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream,
272 const SkRegion& region)
274 if (region.isEmpty())
275 return stream << "EMPTY";
276 stream << "(";
277 SkRegion::Iterator it(region);
278 for (int i = 0; !it.done(); it.next(), ++i)
279 stream << "[" << i << "] " << it.rect();
280 stream << ")";
281 return stream;
284 template <typename charT, typename traits>
285 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream,
286 const SkMatrix& matrix)
288 return stream << "[" << matrix[0] << " " << matrix[1] << " " << matrix[2] << "]"
289 << "[" << matrix[3] << " " << matrix[4] << " " << matrix[5] << "]"
290 << "[" << matrix[6] << " " << matrix[7] << " " << matrix[8] << "]";
293 template <typename charT, typename traits>
294 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream,
295 const SkImage& image)
297 // G - on GPU
298 return stream << static_cast<const void*>(&image) << " " << Size(image.width(), image.height())
299 << "/" << (SkColorTypeBytesPerPixel(image.imageInfo().colorType()) * 8)
300 << (image.isTextureBacked() ? "G" : "");
302 template <typename charT, typename traits>
303 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream,
304 const sk_sp<SkImage>& image)
306 if (image == nullptr)
307 return stream << "(null)";
308 return stream << *image;
311 #endif // INCLUDED_VCL_INC_SKIA_UTILS_H
313 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */