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/.
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>
32 #include <SkSurface.h>
33 #include <tools/sk_app/WindowContext.h>
36 #include <string_view>
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
),
98 // Whether to use GetSkImage() that checks for delayed scaling or whether to access
99 // the stored image directly without checks.
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.
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)
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
,
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
);
163 return SkSamplingOptions();
167 inline SkSamplingOptions
makeSamplingOptions(BmpScaleFlag scalingType
, const Size
& srcSize
,
168 Size destSize
, int scalingFactor
)
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
);
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
);
226 void prefillSurface(const sk_sp
<SkSurface
>& surface
);
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
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";
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";
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";
277 SkRegion::Iterator
it(region
);
278 for (int i
= 0; !it
.done(); it
.next(), ++i
)
279 stream
<< "[" << i
<< "] " << it
.rect();
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
)
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: */