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_SKIA_GDIIMPL_HXX
21 #define INCLUDED_VCL_SKIA_GDIIMPL_HXX
23 #include <vcl/dllapi.h>
25 #include <salgdiimpl.hxx>
26 #include <salgeom.hxx>
28 #include <skia/utils.hxx>
31 #include <SkBlendMode.h>
35 class GenericSalLayout
;
39 class VCL_DLLPUBLIC SkiaSalGraphicsImpl
: public SalGraphicsImpl
42 SkiaSalGraphicsImpl(SalGraphics
& pParent
, SalGeometryProvider
* pProvider
);
43 virtual ~SkiaSalGraphicsImpl() override
;
45 virtual void Init() override
;
47 virtual void DeInit() override
;
49 virtual OUString
getRenderBackendName() const override
{ return "skia"; }
51 const vcl::Region
& getClipRegion() const;
52 virtual void setClipRegion(const vcl::Region
&) override
;
55 // get the depth of the device
56 virtual sal_uInt16
GetBitCount() const override
;
58 // get the width of the device
59 virtual tools::Long
GetGraphicsWidth() const override
;
61 // set the clip region to empty
62 virtual void ResetClipRegion() override
;
64 // set the line color to transparent (= don't draw lines)
66 virtual void SetLineColor() override
;
68 // set the line color to a specific color
69 virtual void SetLineColor(Color nColor
) override
;
71 // set the fill color to transparent (= don't fill)
72 virtual void SetFillColor() override
;
74 // set the fill color to a specific color, shapes will be
76 virtual void SetFillColor(Color nColor
) override
;
78 // enable/disable XOR drawing
79 virtual void SetXORMode(bool bSet
, bool bInvertOnly
) override
;
81 // set line color for raster operations
82 virtual void SetROPLineColor(SalROPColor nROPColor
) override
;
84 // set fill color for raster operations
85 virtual void SetROPFillColor(SalROPColor nROPColor
) override
;
87 // draw --> LineColor and FillColor and RasterOp and ClipRegion
88 virtual void drawPixel(tools::Long nX
, tools::Long nY
) override
;
89 virtual void drawPixel(tools::Long nX
, tools::Long nY
, Color nColor
) override
;
91 virtual void drawLine(tools::Long nX1
, tools::Long nY1
, tools::Long nX2
,
92 tools::Long nY2
) override
;
94 virtual void drawRect(tools::Long nX
, tools::Long nY
, tools::Long nWidth
,
95 tools::Long nHeight
) override
;
97 virtual void drawPolyLine(sal_uInt32 nPoints
, const Point
* pPtAry
) override
;
99 virtual void drawPolygon(sal_uInt32 nPoints
, const Point
* pPtAry
) override
;
101 virtual void drawPolyPolygon(sal_uInt32 nPoly
, const sal_uInt32
* pPoints
,
102 const Point
** pPtAry
) override
;
104 virtual void drawPolyPolygon(const basegfx::B2DHomMatrix
& rObjectToDevice
,
105 const basegfx::B2DPolyPolygon
&, double fTransparency
) override
;
107 virtual bool drawPolyLine(const basegfx::B2DHomMatrix
& rObjectToDevice
,
108 const basegfx::B2DPolygon
&, double fTransparency
, double fLineWidth
,
109 const std::vector
<double>* pStroke
, basegfx::B2DLineJoin
,
110 css::drawing::LineCap
, double fMiterMinimumAngle
,
111 bool bPixelSnapHairline
) override
;
113 virtual bool drawPolyLineBezier(sal_uInt32 nPoints
, const Point
* pPtAry
,
114 const PolyFlags
* pFlgAry
) override
;
116 virtual bool drawPolygonBezier(sal_uInt32 nPoints
, const Point
* pPtAry
,
117 const PolyFlags
* pFlgAry
) override
;
119 virtual bool drawPolyPolygonBezier(sal_uInt32 nPoly
, const sal_uInt32
* pPoints
,
120 const Point
* const* pPtAry
,
121 const PolyFlags
* const* pFlgAry
) override
;
123 // CopyArea --> No RasterOp, but ClipRegion
124 virtual void copyArea(tools::Long nDestX
, tools::Long nDestY
, tools::Long nSrcX
,
125 tools::Long nSrcY
, tools::Long nSrcWidth
, tools::Long nSrcHeight
,
126 bool bWindowInvalidate
) override
;
128 virtual void copyBits(const SalTwoRect
& rPosAry
, SalGraphics
* pSrcGraphics
) override
;
130 virtual bool blendBitmap(const SalTwoRect
&, const SalBitmap
& rBitmap
) override
;
132 virtual bool blendAlphaBitmap(const SalTwoRect
&, const SalBitmap
& rSrcBitmap
,
133 const SalBitmap
& rMaskBitmap
,
134 const SalBitmap
& rAlphaBitmap
) override
;
136 virtual void drawBitmap(const SalTwoRect
& rPosAry
, const SalBitmap
& rSalBitmap
) override
;
138 virtual void drawBitmap(const SalTwoRect
& rPosAry
, const SalBitmap
& rSalBitmap
,
139 const SalBitmap
& rMaskBitmap
) override
;
141 virtual void drawMask(const SalTwoRect
& rPosAry
, const SalBitmap
& rSalBitmap
,
142 Color nMaskColor
) override
;
144 virtual std::shared_ptr
<SalBitmap
> getBitmap(tools::Long nX
, tools::Long nY
, tools::Long nWidth
,
145 tools::Long nHeight
) override
;
147 virtual Color
getPixel(tools::Long nX
, tools::Long nY
) override
;
149 // invert --> ClipRegion (only Windows or VirDevs)
150 virtual void invert(tools::Long nX
, tools::Long nY
, tools::Long nWidth
, tools::Long nHeight
,
151 SalInvert nFlags
) override
;
153 virtual void invert(sal_uInt32 nPoints
, const Point
* pPtAry
, SalInvert nFlags
) override
;
155 virtual bool drawEPS(tools::Long nX
, tools::Long nY
, tools::Long nWidth
, tools::Long nHeight
,
156 void* pPtr
, sal_uInt32 nSize
) override
;
158 /** Render bitmap with alpha channel
161 Source bitmap to blit
164 Alpha channel to use for blitting
166 @return true, if the operation succeeded, and false
167 otherwise. In this case, clients should try to emulate alpha
168 compositing themselves
170 virtual bool drawAlphaBitmap(const SalTwoRect
&, const SalBitmap
& rSourceBitmap
,
171 const SalBitmap
& rAlphaBitmap
) override
;
173 /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */
174 virtual bool drawTransformedBitmap(const basegfx::B2DPoint
& rNull
, const basegfx::B2DPoint
& rX
,
175 const basegfx::B2DPoint
& rY
, const SalBitmap
& rSourceBitmap
,
176 const SalBitmap
* pAlphaBitmap
, double fAlpha
) override
;
178 virtual bool hasFastDrawTransformedBitmap() const override
;
180 /** Render solid rectangle with given transparency
182 @param nX Top left coordinate of rectangle
184 @param nY Bottom right coordinate of rectangle
186 @param nWidth Width of rectangle
188 @param nHeight Height of rectangle
190 @param nTransparency Transparency value (0-255) to use. 0 blits and opaque, 255 a
191 fully transparent rectangle
193 @returns true if successfully drawn, false if not able to draw rectangle
195 virtual bool drawAlphaRect(tools::Long nX
, tools::Long nY
, tools::Long nWidth
,
196 tools::Long nHeight
, sal_uInt8 nTransparency
) override
;
198 virtual bool drawGradient(const tools::PolyPolygon
& rPolygon
,
199 const Gradient
& rGradient
) override
;
200 virtual bool implDrawGradient(const basegfx::B2DPolyPolygon
& rPolyPolygon
,
201 const SalGradient
& rGradient
) override
;
203 virtual bool supportsOperation(OutDevSupportType eType
) const override
;
205 // Dump contents to a file for debugging.
206 void dump(const char* file
) const;
208 // Default blend mode for SkPaint is SkBlendMode::kSrcOver
209 void drawBitmap(const SalTwoRect
& rPosAry
, const SkiaSalBitmap
& bitmap
,
210 SkBlendMode blendMode
= SkBlendMode::kSrcOver
);
212 void drawImage(const SalTwoRect
& rPosAry
, const sk_sp
<SkImage
>& aImage
, int srcScaling
= 1,
213 SkBlendMode eBlendMode
= SkBlendMode::kSrcOver
);
215 void drawShader(const SalTwoRect
& rPosAry
, const sk_sp
<SkShader
>& shader
,
216 SkBlendMode blendMode
= SkBlendMode::kSrcOver
);
218 void drawGenericLayout(const GenericSalLayout
& layout
, Color textColor
, const SkFont
& font
,
219 const SkFont
& verticalFont
);
222 // To be called before any drawing.
224 // To be called after any drawing.
226 // The canvas to draw to.
227 SkCanvas
* getDrawCanvas() { return mSurface
->getCanvas(); }
228 // Call before makeImageSnapshot(), ensures the content is up to date.
231 virtual void createSurface();
232 // Call to ensure that mSurface is valid. If mSurface is going to be modified,
233 // use preDraw() instead of this.
235 void destroySurface();
236 // Reimplemented for X11.
237 virtual bool avoidRecreateByResize() const;
238 void createWindowSurface(bool forceRaster
= false);
239 virtual void createWindowSurfaceInternal(bool forceRaster
= false) = 0;
240 void createOffscreenSurface();
241 virtual void flushSurfaceToWindowContext();
243 void privateDrawAlphaRect(tools::Long nX
, tools::Long nY
, tools::Long nWidth
,
244 tools::Long nHeight
, double nTransparency
, bool blockAA
= false);
245 void privateCopyBits(const SalTwoRect
& rPosAry
, SkiaSalGraphicsImpl
* src
);
247 void setProvider(SalGeometryProvider
* provider
) { mProvider
= provider
; }
249 bool isOffscreen() const;
250 bool isGPU() const { return mIsGPU
; }
252 void invert(basegfx::B2DPolygon
const& rPoly
, SalInvert eFlags
);
254 // Called by SkiaFlushIdle.
256 void scheduleFlush();
257 friend class SkiaFlushIdle
;
259 // get the width of the device
260 int GetWidth() const { return mProvider
? mProvider
->GetWidth() : 1; }
261 // get the height of the device
262 int GetHeight() const { return mProvider
? mProvider
->GetHeight() : 1; }
263 // Get the global HiDPI scaling factor.
264 virtual int getWindowScaling() const;
266 void addUpdateRegion(const SkRect
& rect
)
268 // Make slightly larger, just in case (rounding, antialiasing,...).
269 SkIRect addedRect
= rect
.makeOutset(2, 2).round();
270 // Using SkIRect should be enough, SkRegion would be too slow with many operations
271 // and swapping to the screen is not _that_slow.
272 mDirtyRect
.join(addedRect
);
274 void setCanvasScalingAndClipping();
275 void resetCanvasScalingAndClipping();
276 static void setCanvasClipRegion(SkCanvas
* canvas
, const vcl::Region
& region
);
277 sk_sp
<SkImage
> mergeCacheBitmaps(const SkiaSalBitmap
& bitmap
, const SkiaSalBitmap
* alphaBitmap
,
278 const Size
& targetSize
);
279 using DirectImage
= SkiaHelper::DirectImage
;
280 static OString
makeCachedImageKey(const SkiaSalBitmap
& bitmap
, const SkiaSalBitmap
* alphaBitmap
,
281 const Size
& targetSize
, DirectImage bitmapType
,
282 DirectImage alphaBitmapType
);
284 // Skia uses floating point coordinates, so when we use integer coordinates, sometimes
285 // rounding results in off-by-one errors (down), especially when drawing using GPU,
286 // see https://bugs.chromium.org/p/skia/issues/detail?id=9611 . Compensate for
287 // it by using centers of pixels. Using 0.5 may sometimes round up, so go with 0.495 .
288 static constexpr SkScalar
toSkX(tools::Long x
) { return x
+ 0.495; }
289 static constexpr SkScalar
toSkY(tools::Long y
) { return y
+ 0.495; }
290 // Value to add to be exactly in the middle of the pixel.
291 static constexpr SkScalar toSkXYFix
= SkScalar(0.005);
293 // Perform any pending drawing such as delayed merging of polygons. Called by preDraw()
294 // and anything that means the next operation cannot be another one in a series (e.g.
296 void checkPendingDrawing();
297 bool delayDrawPolyPolygon(const basegfx::B2DPolyPolygon
& polygon
, double transparency
);
298 void performDrawPolyPolygon(const basegfx::B2DPolyPolygon
& polygon
, double transparency
,
301 BmpScaleFlag
goodScalingQuality() const { return SkiaHelper::goodScalingQuality(isGPU()); }
302 SkSamplingOptions
makeSamplingOptions(const SalTwoRect
& rPosAry
, int scalingFactor
,
303 int srcScalingFactor
= 1)
305 return SkiaHelper::makeSamplingOptions(rPosAry
, scalingFactor
, srcScalingFactor
, isGPU());
307 SkSamplingOptions
makeSamplingOptions(const SkMatrix
& matrix
, int scalingFactor
)
309 return SkiaHelper::makeSamplingOptions(goodScalingQuality(), matrix
, scalingFactor
);
312 // Create SkPaint to use when drawing to the surface. It is not to be used
313 // when doing internal drawing such as when merging two bitmaps together.
314 // This may apply some default settings to the paint as necessary.
315 SkPaint
makePaintInternal() const;
316 // Create SkPaint set up for drawing lines (using mLineColor etc.).
317 SkPaint
makeLinePaint(double transparency
= 0) const;
318 // Create SkPaint set up for filling (using mFillColor etc.).
319 SkPaint
makeFillPaint(double transparency
= 0) const;
320 // Create SkPaint set up for bitmap drawing.
321 SkPaint
makeBitmapPaint() const;
322 // Create SkPaint set up for gradient drawing.
323 SkPaint
makeGradientPaint() const;
324 // Create SkPaint set up for text drawing.
325 SkPaint
makeTextPaint(std::optional
<Color
> color
) const;
326 // Create SkPaint for unspecified pixel drawing. Avoid if possible.
327 SkPaint
makePixelPaint(std::optional
<Color
> color
) const;
329 template <typename charT
, typename traits
>
330 friend inline std::basic_ostream
<charT
, traits
>&
331 operator<<(std::basic_ostream
<charT
, traits
>& stream
, const SkiaSalGraphicsImpl
* graphics
)
333 if (graphics
== nullptr)
334 return stream
<< "(null)";
335 // O - offscreen, G - GPU-based, R - raster
336 stream
<< static_cast<const void*>(graphics
) << " "
337 << Size(graphics
->GetWidth(), graphics
->GetHeight());
338 if (graphics
->mScaling
!= 1)
339 stream
<< "*" << graphics
->mScaling
;
340 stream
<< (graphics
->isGPU() ? "G" : "R") << (graphics
->isOffscreen() ? "O" : "");
344 void windowBackingPropertiesChanged();
346 SalGraphics
& mParent
;
347 /// Pointer to the SalFrame or SalVirtualDevice
348 SalGeometryProvider
* mProvider
;
349 // The Skia surface that is target of all the rendering.
350 sk_sp
<SkSurface
> mSurface
;
351 // Note that mSurface may be a proxy surface and not the one from the window context.
352 std::unique_ptr
<sk_app::WindowContext
> mWindowContext
;
353 bool mIsGPU
; // whether the surface is GPU-backed
354 // Note that we generally use VCL coordinates, which is not mSurface coordinates if mScaling!=1.
355 SkIRect mDirtyRect
; // The area that has been changed since the last performFlush().
356 vcl::Region mClipRegion
;
357 std::optional
<Color
> moLineColor
;
358 std::optional
<Color
> moFillColor
;
366 std::unique_ptr
<SkiaFlushIdle
> mFlush
;
367 // Info about pending polygons to draw (we try to merge adjacent polygons into one).
368 struct LastPolyPolygonInfo
370 basegfx::B2DPolyPolygonVector polygons
;
371 basegfx::B2DRange bounds
;
374 LastPolyPolygonInfo mLastPolyPolygonInfo
;
375 inline static int pendingOperationsToFlush
= 0;
376 int mScaling
; // The scale factor for HiDPI screens.
377 bool mInWindowBackingPropertiesChanged
;
380 inline SkPaint
SkiaSalGraphicsImpl::makePaintInternal() const
383 // Invert could be done using a blend mode like invert() does, but
384 // intentionally use SkBlender to make sure it's not overwritten
385 // by a blend mode set later (which would be probably a mistake),
386 // and so that the drawing color does not actually matter.
387 if (mXorMode
== XorMode::Invert
)
388 SkiaHelper::setBlenderInvert(&paint
);
389 else if (mXorMode
== XorMode::Xor
)
390 SkiaHelper::setBlenderXor(&paint
);
394 inline SkPaint
SkiaSalGraphicsImpl::makeLinePaint(double transparency
) const
396 assert(moLineColor
.has_value());
397 SkPaint paint
= makePaintInternal();
398 paint
.setColor(transparency
== 0
399 ? SkiaHelper::toSkColor(*moLineColor
)
400 : SkiaHelper::toSkColorWithTransparency(*moLineColor
, transparency
));
401 paint
.setStyle(SkPaint::kStroke_Style
);
405 inline SkPaint
SkiaSalGraphicsImpl::makeFillPaint(double transparency
) const
407 assert(moFillColor
.has_value());
408 SkPaint paint
= makePaintInternal();
409 paint
.setColor(transparency
== 0
410 ? SkiaHelper::toSkColor(*moFillColor
)
411 : SkiaHelper::toSkColorWithTransparency(*moFillColor
, transparency
));
412 if (moLineColor
== moFillColor
)
413 paint
.setStyle(SkPaint::kStrokeAndFill_Style
);
415 paint
.setStyle(SkPaint::kFill_Style
);
419 inline SkPaint
SkiaSalGraphicsImpl::makeBitmapPaint() const { return makePaintInternal(); }
421 inline SkPaint
SkiaSalGraphicsImpl::makeGradientPaint() const { return makePaintInternal(); }
423 inline SkPaint
SkiaSalGraphicsImpl::makeTextPaint(std::optional
<Color
> color
) const
425 assert(color
.has_value());
426 SkPaint paint
= makePaintInternal();
427 paint
.setColor(SkiaHelper::toSkColor(*color
));
431 inline SkPaint
SkiaSalGraphicsImpl::makePixelPaint(std::optional
<Color
> color
) const
433 assert(color
.has_value());
434 SkPaint paint
= makePaintInternal();
435 paint
.setColor(SkiaHelper::toSkColor(*color
));
441 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */