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 // Do 'paint->setBlendMode(SkBlendMode::kDifference)' (workaround for buggy drivers).
77 void setBlendModeDifference(SkPaint
* paint
);
79 // Must be called in any VCL backend before any Skia functionality is used.
80 // If not set, Skia will be disabled.
82 prepareSkia(std::unique_ptr
<sk_app::WindowContext
> (*createGpuWindowContext
)(bool));
84 // Shared cache of images.
85 void addCachedImage(const OString
& key
, sk_sp
<SkImage
> image
);
86 sk_sp
<SkImage
> findCachedImage(const OString
& key
);
87 void removeCachedImage(sk_sp
<SkImage
> image
);
88 tools::Long
maxImageCacheSize();
90 // SkSurfaceProps to be used by all Skia surfaces.
91 VCL_DLLPUBLIC
const SkSurfaceProps
* surfaceProps();
92 // Set pixel geometry to be used by SkSurfaceProps.
93 VCL_DLLPUBLIC
void setPixelGeometry(SkPixelGeometry pixelGeometry
);
95 inline bool isUnitTestRunning(const char* name
= nullptr)
99 static const char* const testname
= getenv("LO_TESTNAME");
100 return testname
!= nullptr;
102 const char* const testname
= getenv("LO_TESTNAME");
103 return testname
!= nullptr && std::string_view(name
) == testname
;
106 // Normal scaling algorithms have a poor quality when downscaling a lot.
107 // https://bugs.chromium.org/p/skia/issues/detail?id=11810 suggests to use mipmaps
108 // in such a case, which is annoying to do explicitly instead of Skia deciding which
109 // algorithm would be the best, but now with Skia removing SkFilterQuality and requiring
110 // explicitly being told what algorithm to use this appears to be the best we can do.
111 // Anything scaled down at least this ratio will use linear+mipmaps.
112 constexpr int downscaleRatioThreshold
= 4;
114 inline SkSamplingOptions
makeSamplingOptions(BmpScaleFlag scalingType
, SkMatrix matrix
,
119 case BmpScaleFlag::BestQuality
:
120 if (scalingFactor
!= 1)
121 matrix
.postScale(scalingFactor
, scalingFactor
);
122 if (matrix
.getScaleX() <= 1.0 / downscaleRatioThreshold
123 || matrix
.getScaleY() <= 1.0 / downscaleRatioThreshold
)
124 return SkSamplingOptions(SkFilterMode::kLinear
, SkMipmapMode::kLinear
);
125 return SkSamplingOptions(SkCubicResampler::Mitchell());
126 case BmpScaleFlag::Default
:
127 return SkSamplingOptions(SkFilterMode::kLinear
, SkMipmapMode::kNone
);
128 case BmpScaleFlag::Fast
:
129 case BmpScaleFlag::NearestNeighbor
:
130 return SkSamplingOptions(SkFilterMode::kNearest
, SkMipmapMode::kNone
);
133 return SkSamplingOptions();
137 inline SkSamplingOptions
makeSamplingOptions(BmpScaleFlag scalingType
, const Size
& srcSize
,
138 Size destSize
, int scalingFactor
)
142 case BmpScaleFlag::BestQuality
:
143 if (scalingFactor
!= 1)
144 destSize
*= scalingFactor
;
145 if (srcSize
.Width() / destSize
.Width() >= downscaleRatioThreshold
146 || srcSize
.Height() / destSize
.Height() >= downscaleRatioThreshold
)
147 return SkSamplingOptions(SkFilterMode::kLinear
, SkMipmapMode::kLinear
);
148 return SkSamplingOptions(SkCubicResampler::Mitchell());
149 case BmpScaleFlag::Default
:
150 return SkSamplingOptions(SkFilterMode::kLinear
, SkMipmapMode::kNone
);
151 case BmpScaleFlag::Fast
:
152 case BmpScaleFlag::NearestNeighbor
:
153 return SkSamplingOptions(SkFilterMode::kNearest
, SkMipmapMode::kNone
);
156 return SkSamplingOptions();
160 inline SkSamplingOptions
makeSamplingOptions(const SalTwoRect
& rPosAry
, int scalingFactor
,
161 int srcScalingFactor
= 1)
163 // If there will be scaling, make it smooth, but not in unittests, as those often
164 // require exact color values and would be confused by this.
165 if (isUnitTestRunning())
166 return SkSamplingOptions(); // none
167 Size
srcSize(rPosAry
.mnSrcWidth
, rPosAry
.mnSrcHeight
);
168 Size
destSize(rPosAry
.mnDestWidth
, rPosAry
.mnDestHeight
);
169 if (scalingFactor
!= 1)
170 destSize
*= scalingFactor
;
171 if (srcScalingFactor
!= 1)
172 srcSize
*= srcScalingFactor
;
173 if (srcSize
!= destSize
)
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()); // best
180 return SkSamplingOptions(); // none
183 inline SkRect
scaleRect(const SkRect
& rect
, int scaling
)
185 return SkRect::MakeXYWH(rect
.x() * scaling
, rect
.y() * scaling
, rect
.width() * scaling
,
186 rect
.height() * scaling
);
189 inline SkIRect
scaleRect(const SkIRect
& rect
, int scaling
)
191 return SkIRect::MakeXYWH(rect
.x() * scaling
, rect
.y() * scaling
, rect
.width() * scaling
,
192 rect
.height() * scaling
);
196 void prefillSurface(const sk_sp
<SkSurface
>& surface
);
199 VCL_DLLPUBLIC
void dump(const SkBitmap
& bitmap
, const char* file
);
200 VCL_DLLPUBLIC
void dump(const sk_sp
<SkImage
>& image
, const char* file
);
201 VCL_DLLPUBLIC
void dump(const sk_sp
<SkSurface
>& surface
, const char* file
);
203 VCL_DLLPUBLIC
extern uint32_t vendorId
;
205 inline DriverBlocklist::DeviceVendor
getVendor()
207 return DriverBlocklist::GetVendorFromId(vendorId
);
210 } // namespace SkiaHelper
215 VCL_DLLPUBLIC
bool matrixNeedsHighQuality(const SkMatrix
& matrix
);
218 template <typename charT
, typename traits
>
219 inline std::basic_ostream
<charT
, traits
>& operator<<(std::basic_ostream
<charT
, traits
>& stream
,
220 const SkRect
& rectangle
)
222 if (rectangle
.isEmpty())
223 return stream
<< "EMPTY";
225 return stream
<< rectangle
.width() << 'x' << rectangle
.height() << "@(" << rectangle
.x()
226 << ',' << rectangle
.y() << ")";
229 template <typename charT
, typename traits
>
230 inline std::basic_ostream
<charT
, traits
>& operator<<(std::basic_ostream
<charT
, traits
>& stream
,
231 const SkIRect
& rectangle
)
233 if (rectangle
.isEmpty())
234 return stream
<< "EMPTY";
236 return stream
<< rectangle
.width() << 'x' << rectangle
.height() << "@(" << rectangle
.x()
237 << ',' << rectangle
.y() << ")";
240 template <typename charT
, typename traits
>
241 inline std::basic_ostream
<charT
, traits
>& operator<<(std::basic_ostream
<charT
, traits
>& stream
,
242 const SkRegion
& region
)
244 if (region
.isEmpty())
245 return stream
<< "EMPTY";
247 SkRegion::Iterator
it(region
);
248 for (int i
= 0; !it
.done(); it
.next(), ++i
)
249 stream
<< "[" << i
<< "] " << it
.rect();
254 template <typename charT
, typename traits
>
255 inline std::basic_ostream
<charT
, traits
>& operator<<(std::basic_ostream
<charT
, traits
>& stream
,
256 const SkMatrix
& matrix
)
258 return stream
<< "[" << matrix
[0] << " " << matrix
[1] << " " << matrix
[2] << "]"
259 << "[" << matrix
[3] << " " << matrix
[4] << " " << matrix
[5] << "]"
260 << "[" << matrix
[6] << " " << matrix
[7] << " " << matrix
[8] << "]";
263 template <typename charT
, typename traits
>
264 inline std::basic_ostream
<charT
, traits
>& operator<<(std::basic_ostream
<charT
, traits
>& stream
,
265 const SkImage
& image
)
268 return stream
<< static_cast<const void*>(&image
) << " " << Size(image
.width(), image
.height())
269 << "/" << (SkColorTypeBytesPerPixel(image
.imageInfo().colorType()) * 8)
270 << (image
.isTextureBacked() ? "G" : "");
272 template <typename charT
, typename traits
>
273 inline std::basic_ostream
<charT
, traits
>& operator<<(std::basic_ostream
<charT
, traits
>& stream
,
274 const sk_sp
<SkImage
>& image
)
276 if (image
== nullptr)
277 return stream
<< "(null)";
278 return stream
<< *image
;
281 #endif // INCLUDED_VCL_INC_SKIA_UTILS_H
283 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */