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_SKIA_GDIIMPL_HXX
21 #define INCLUDED_VCL_SKIA_GDIIMPL_HXX
22 
23 #include <vcl/dllapi.h>
24 
25 #include <salgdiimpl.hxx>
26 #include <salgeom.hxx>
27 
28 #include <SkSurface.h>
29 #include <SkRegion.h>
30 
31 #include <prewin.h>
32 #include <tools/sk_app/WindowContext.h>
33 #include <postwin.h>
34 
35 class SkiaFlushIdle;
36 class GenericSalLayout;
37 class SkFont;
38 class SkiaSalBitmap;
39 
40 class VCL_DLLPUBLIC SkiaSalGraphicsImpl : public SalGraphicsImpl
41 {
42 public:
43     SkiaSalGraphicsImpl(SalGraphics& pParent, SalGeometryProvider* pProvider);
44     virtual ~SkiaSalGraphicsImpl() override;
45 
46     virtual void Init() override;
47 
48     virtual void DeInit() override;
49 
getRenderBackendName() const50     virtual OUString getRenderBackendName() const override { return "skia"; }
51 
52     const vcl::Region& getClipRegion() const;
53     virtual bool setClipRegion(const vcl::Region&) override;
54 
55     //
56     // get the depth of the device
57     virtual sal_uInt16 GetBitCount() const override;
58 
59     // get the width of the device
60     virtual tools::Long GetGraphicsWidth() const override;
61 
62     // set the clip region to empty
63     virtual void ResetClipRegion() override;
64 
65     // set the line color to transparent (= don't draw lines)
66 
67     virtual void SetLineColor() override;
68 
69     // set the line color to a specific color
70     virtual void SetLineColor(Color nColor) override;
71 
72     // set the fill color to transparent (= don't fill)
73     virtual void SetFillColor() override;
74 
75     // set the fill color to a specific color, shapes will be
76     // filled accordingly
77     virtual void SetFillColor(Color nColor) override;
78 
79     // enable/disable XOR drawing
80     virtual void SetXORMode(bool bSet, bool bInvertOnly) override;
81 
82     // set line color for raster operations
83     virtual void SetROPLineColor(SalROPColor nROPColor) override;
84 
85     // set fill color for raster operations
86     virtual void SetROPFillColor(SalROPColor nROPColor) override;
87 
88     // draw --> LineColor and FillColor and RasterOp and ClipRegion
89     virtual void drawPixel(tools::Long nX, tools::Long nY) override;
90     virtual void drawPixel(tools::Long nX, tools::Long nY, Color nColor) override;
91 
92     virtual void drawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2,
93                           tools::Long nY2) override;
94 
95     virtual void drawRect(tools::Long nX, tools::Long nY, tools::Long nWidth,
96                           tools::Long nHeight) override;
97 
98     virtual void drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry) override;
99 
100     virtual void drawPolygon(sal_uInt32 nPoints, const Point* pPtAry) override;
101 
102     virtual void drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPoints,
103                                  const Point** pPtAry) override;
104 
105     virtual bool drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice,
106                                  const basegfx::B2DPolyPolygon&, double fTransparency) override;
107 
108     virtual bool drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice,
109                               const basegfx::B2DPolygon&, double fTransparency, double fLineWidth,
110                               const std::vector<double>* pStroke, basegfx::B2DLineJoin,
111                               css::drawing::LineCap, double fMiterMinimumAngle,
112                               bool bPixelSnapHairline) override;
113 
114     virtual bool drawPolyLineBezier(sal_uInt32 nPoints, const Point* pPtAry,
115                                     const PolyFlags* pFlgAry) override;
116 
117     virtual bool drawPolygonBezier(sal_uInt32 nPoints, const Point* pPtAry,
118                                    const PolyFlags* pFlgAry) override;
119 
120     virtual bool drawPolyPolygonBezier(sal_uInt32 nPoly, const sal_uInt32* pPoints,
121                                        const Point* const* pPtAry,
122                                        const PolyFlags* const* pFlgAry) override;
123 
124     // CopyArea --> No RasterOp, but ClipRegion
125     virtual void copyArea(tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX,
126                           tools::Long nSrcY, tools::Long nSrcWidth, tools::Long nSrcHeight,
127                           bool bWindowInvalidate) override;
128 
129     virtual void copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics) override;
130 
131     virtual bool blendBitmap(const SalTwoRect&, const SalBitmap& rBitmap) override;
132 
133     virtual bool blendAlphaBitmap(const SalTwoRect&, const SalBitmap& rSrcBitmap,
134                                   const SalBitmap& rMaskBitmap,
135                                   const SalBitmap& rAlphaBitmap) override;
136 
137     virtual void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) override;
138 
139     virtual void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap,
140                             const SalBitmap& rMaskBitmap) override;
141 
142     virtual void drawMask(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap,
143                           Color nMaskColor) override;
144 
145     virtual std::shared_ptr<SalBitmap> getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth,
146                                                  tools::Long nHeight) override;
147 
148     virtual Color getPixel(tools::Long nX, tools::Long nY) override;
149 
150     // invert --> ClipRegion (only Windows or VirDevs)
151     virtual void invert(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight,
152                         SalInvert nFlags) override;
153 
154     virtual void invert(sal_uInt32 nPoints, const Point* pPtAry, SalInvert nFlags) override;
155 
156     virtual bool drawEPS(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight,
157                          void* pPtr, sal_uInt32 nSize) override;
158 
159     /** Render bitmap with alpha channel
160 
161         @param rSourceBitmap
162         Source bitmap to blit
163 
164         @param rAlphaBitmap
165         Alpha channel to use for blitting
166 
167         @return true, if the operation succeeded, and false
168         otherwise. In this case, clients should try to emulate alpha
169         compositing themselves
170      */
171     virtual bool drawAlphaBitmap(const SalTwoRect&, const SalBitmap& rSourceBitmap,
172                                  const SalBitmap& rAlphaBitmap) override;
173 
174     /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */
175     virtual bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX,
176                                        const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap,
177                                        const SalBitmap* pAlphaBitmap, double fAlpha) override;
178 
179     virtual bool hasFastDrawTransformedBitmap() const override;
180 
181     /** Render solid rectangle with given transparency
182 
183       @param nX             Top left coordinate of rectangle
184 
185       @param nY             Bottom right coordinate of rectangle
186 
187       @param nWidth         Width of rectangle
188 
189       @param nHeight        Height of rectangle
190 
191       @param nTransparency  Transparency value (0-255) to use. 0 blits and opaque, 255 a
192                             fully transparent rectangle
193 
194       @returns true if successfully drawn, false if not able to draw rectangle
195      */
196     virtual bool drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth,
197                                tools::Long nHeight, sal_uInt8 nTransparency) override;
198 
199     virtual bool drawGradient(const tools::PolyPolygon& rPolygon,
200                               const Gradient& rGradient) override;
201     virtual bool implDrawGradient(const basegfx::B2DPolyPolygon& rPolyPolygon,
202                                   const SalGradient& rGradient) override;
203 
204     virtual bool supportsOperation(OutDevSupportType eType) const override;
205 
206 #ifdef DBG_UTIL
207     void dump(const char* file) const;
208 #endif
209 
210     // Default blend mode for SkPaint is SkBlendMode::kSrcOver
211     void drawBitmap(const SalTwoRect& rPosAry, const SkiaSalBitmap& bitmap,
212                     SkBlendMode blendMode = SkBlendMode::kSrcOver);
213 
214     void drawImage(const SalTwoRect& rPosAry, const sk_sp<SkImage>& aImage,
215                    SkBlendMode eBlendMode = SkBlendMode::kSrcOver);
216 
217     void drawShader(const SalTwoRect& rPosAry, const sk_sp<SkShader>& shader,
218                     SkBlendMode blendMode = SkBlendMode::kSrcOver);
219 
220     void drawGenericLayout(const GenericSalLayout& layout, Color textColor, const SkFont& font,
221                            const SkFont& verticalFont);
222 
223 protected:
224     // To be called before any drawing.
225     void preDraw();
226     // To be called after any drawing.
227     void postDraw();
228     // The canvas to draw to. Will be diverted to a temporary for Xor mode.
getDrawCanvas()229     SkCanvas* getDrawCanvas() { return mXorMode ? getXorCanvas() : mSurface->getCanvas(); }
230     // Call before makeImageSnapshot(), ensures the content is up to date.
231     void flushDrawing();
232 
233     virtual void createSurface();
234     // Call to ensure that mSurface is valid. If mSurface is going to be modified,
235     // use preDraw() instead of this.
236     void checkSurface();
237     void destroySurface();
238     // Reimplemented for X11.
239     virtual bool avoidRecreateByResize() const;
240     void createWindowSurface(bool forceRaster = false);
241     virtual void createWindowContext(bool forceRaster = false) = 0;
242     void createOffscreenSurface();
243 
244     void privateDrawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth,
245                               tools::Long nHeight, double nTransparency, bool blockAA = false);
246 
setProvider(SalGeometryProvider * provider)247     void setProvider(SalGeometryProvider* provider) { mProvider = provider; }
248 
249     bool isOffscreen() const;
isGPU() const250     bool isGPU() const { return mIsGPU; }
251 
252     void invert(basegfx::B2DPolygon const& rPoly, SalInvert eFlags);
253 
254     // Called by SkiaFlushIdle.
255     virtual void performFlush() = 0;
256     void scheduleFlush();
257     friend class SkiaFlushIdle;
258 
259     // get the width of the device
GetWidth() const260     int GetWidth() const { return mProvider ? mProvider->GetWidth() : 1; }
261     // get the height of the device
GetHeight() const262     int GetHeight() const { return mProvider ? mProvider->GetHeight() : 1; }
263 
264     SkCanvas* getXorCanvas();
265     void applyXor();
266     // NOTE: This must be called before the operation does any drawing.
addUpdateRegion(const SkRect & rect)267     void addUpdateRegion(const SkRect& rect)
268     {
269         // Make slightly larger, just in case (rounding, antialiasing,...).
270         SkIRect addedRect = rect.makeOutset(2, 2).round();
271         if (mXorMode)
272         {
273             // Two xor operations should cancel each other out. We batch xor operations,
274             // but if they can overlap, apply xor now, since applyXor() does the operation
275             // just once.
276             if (mXorRegion.intersects(addedRect))
277                 applyXor();
278             mXorRegion.op(addedRect, SkRegion::kUnion_Op);
279         }
280         // Using SkIRect should be enough, SkRegion would be too slow with many operations
281         // and swapping to the screen is not _that_slow.
282         mDirtyRect.join(addedRect);
283     }
284     static void setCanvasClipRegion(SkCanvas* canvas, const vcl::Region& region);
285     sk_sp<SkImage> mergeCacheBitmaps(const SkiaSalBitmap& bitmap, const SkiaSalBitmap* alphaBitmap,
286                                      const Size targetSize);
287 
288     // Skia uses floating point coordinates, so when we use integer coordinates, sometimes
289     // rounding results in off-by-one errors (down), especially when drawing using GPU,
290     // see https://bugs.chromium.org/p/skia/issues/detail?id=9611 . Compensate for
291     // it by using centers of pixels. Using 0.5 may sometimes round up, so go with 0.495 .
toSkX(tools::Long x)292     static constexpr SkScalar toSkX(tools::Long x) { return x + 0.495; }
toSkY(tools::Long y)293     static constexpr SkScalar toSkY(tools::Long y) { return y + 0.495; }
294     // Value to add to be exactly in the middle of the pixel.
295     static constexpr SkScalar toSkXYFix = SkScalar(0.005);
296 
297     // Perform any pending drawing such as delayed merging of polygons. Called by preDraw()
298     // and anything that means the next operation cannot be another one in a series (e.g.
299     // changing colors).
300     void checkPendingDrawing();
301     bool delayDrawPolyPolygon(const basegfx::B2DPolyPolygon& polygon, double transparency);
302     void performDrawPolyPolygon(const basegfx::B2DPolyPolygon& polygon, double transparency,
303                                 bool useAA);
304 
305     template <typename charT, typename traits>
306     friend inline std::basic_ostream<charT, traits>&
operator <<(std::basic_ostream<charT,traits> & stream,const SkiaSalGraphicsImpl * graphics)307     operator<<(std::basic_ostream<charT, traits>& stream, const SkiaSalGraphicsImpl* graphics)
308     {
309         if (graphics == nullptr)
310             return stream << "(null)";
311         // O - offscreen, G - GPU-based, R - raster
312         return stream << static_cast<const void*>(graphics) << " "
313                       << Size(graphics->GetWidth(), graphics->GetHeight())
314                       << (graphics->isGPU() ? "G" : "R") << (graphics->isOffscreen() ? "O" : "");
315     }
316 
317     SalGraphics& mParent;
318     /// Pointer to the SalFrame or SalVirtualDevice
319     SalGeometryProvider* mProvider;
320     std::unique_ptr<sk_app::WindowContext> mWindowContext;
321     // The Skia surface that is target of all the rendering.
322     sk_sp<SkSurface> mSurface;
323     bool mIsGPU; // whether the surface is GPU-backed
324     SkIRect mDirtyRect; // the area that has been changed since the last performFlush()
325     vcl::Region mClipRegion;
326     Color mLineColor;
327     Color mFillColor;
328     bool mXorMode;
329     SkBitmap mXorBitmap;
330     std::unique_ptr<SkCanvas> mXorCanvas;
331     SkRegion mXorRegion; // the area that needs updating for the xor operation
332     std::unique_ptr<SkiaFlushIdle> mFlush;
333     // Info about pending polygons to draw (we try to merge adjacent polygons into one).
334     struct LastPolyPolygonInfo
335     {
336         basegfx::B2DPolyPolygonVector polygons;
337         basegfx::B2DRange bounds;
338         double transparency;
339     };
340     LastPolyPolygonInfo mLastPolyPolygonInfo;
341     int mPendingOperationsToFlush;
342 };
343 
344 #endif
345 
346 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
347