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