diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /vcl/inc/skia | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/inc/skia')
-rw-r--r-- | vcl/inc/skia/gdiimpl.hxx | 441 | ||||
-rw-r--r-- | vcl/inc/skia/osx/bitmap.hxx | 26 | ||||
-rw-r--r-- | vcl/inc/skia/osx/gdiimpl.hxx | 57 | ||||
-rw-r--r-- | vcl/inc/skia/quartz/cgutils.h | 40 | ||||
-rw-r--r-- | vcl/inc/skia/salbmp.hxx | 231 | ||||
-rw-r--r-- | vcl/inc/skia/utils.hxx | 341 | ||||
-rw-r--r-- | vcl/inc/skia/win/font.hxx | 40 | ||||
-rw-r--r-- | vcl/inc/skia/win/gdiimpl.hxx | 91 | ||||
-rw-r--r-- | vcl/inc/skia/x11/gdiimpl.hxx | 45 | ||||
-rw-r--r-- | vcl/inc/skia/x11/salvd.hxx | 48 | ||||
-rw-r--r-- | vcl/inc/skia/x11/textrender.hxx | 39 | ||||
-rw-r--r-- | vcl/inc/skia/zone.hxx | 33 |
12 files changed, 1432 insertions, 0 deletions
diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx new file mode 100644 index 0000000000..b879872a8b --- /dev/null +++ b/vcl/inc/skia/gdiimpl.hxx @@ -0,0 +1,441 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_SKIA_GDIIMPL_HXX +#define INCLUDED_VCL_SKIA_GDIIMPL_HXX + +#include <vcl/dllapi.h> + +#include <salgdiimpl.hxx> +#include <salgeom.hxx> + +#include <skia/utils.hxx> + +#include <SkPaint.h> +#include <SkBlendMode.h> +#include <optional> + +class SkiaFlushIdle; +class GenericSalLayout; +class SkFont; +class SkiaSalBitmap; + +class VCL_DLLPUBLIC SkiaSalGraphicsImpl : public SalGraphicsImpl +{ +public: + SkiaSalGraphicsImpl(SalGraphics& pParent, SalGeometryProvider* pProvider); + virtual ~SkiaSalGraphicsImpl() override; + + virtual void Init() override; + + virtual void DeInit() override; + + virtual OUString getRenderBackendName() const override { return "skia"; } + + const vcl::Region& getClipRegion() const; + virtual void setClipRegion(const vcl::Region&) override; + + // + // get the depth of the device + virtual sal_uInt16 GetBitCount() const override; + + // get the width of the device + virtual tools::Long GetGraphicsWidth() const override; + + // set the clip region to empty + virtual void ResetClipRegion() override; + + // set the line color to transparent (= don't draw lines) + + virtual void SetLineColor() override; + + // set the line color to a specific color + virtual void SetLineColor(Color nColor) override; + + // set the fill color to transparent (= don't fill) + virtual void SetFillColor() override; + + // set the fill color to a specific color, shapes will be + // filled accordingly + virtual void SetFillColor(Color nColor) override; + + // enable/disable XOR drawing + virtual void SetXORMode(bool bSet, bool bInvertOnly) override; + + // set line color for raster operations + virtual void SetROPLineColor(SalROPColor nROPColor) override; + + // set fill color for raster operations + virtual void SetROPFillColor(SalROPColor nROPColor) override; + + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel(tools::Long nX, tools::Long nY) override; + virtual void drawPixel(tools::Long nX, tools::Long nY, Color nColor) override; + + virtual void drawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2, + tools::Long nY2) override; + + virtual void drawRect(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight) override; + + virtual void drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry) override; + + virtual void drawPolygon(sal_uInt32 nPoints, const Point* pPtAry) override; + + virtual void drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPoints, + const Point** pPtAry) override; + + virtual void drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, double fTransparency) override; + + virtual bool drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon&, double fTransparency, double fLineWidth, + const std::vector<double>* pStroke, basegfx::B2DLineJoin, + css::drawing::LineCap, double fMiterMinimumAngle, + bool bPixelSnapHairline) override; + + virtual bool drawPolyLineBezier(sal_uInt32 nPoints, const Point* pPtAry, + const PolyFlags* pFlgAry) override; + + virtual bool drawPolygonBezier(sal_uInt32 nPoints, const Point* pPtAry, + const PolyFlags* pFlgAry) override; + + virtual bool drawPolyPolygonBezier(sal_uInt32 nPoly, const sal_uInt32* pPoints, + const Point* const* pPtAry, + const PolyFlags* const* pFlgAry) override; + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea(tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX, + tools::Long nSrcY, tools::Long nSrcWidth, tools::Long nSrcHeight, + bool bWindowInvalidate) override; + + virtual void copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics) override; + + virtual bool blendBitmap(const SalTwoRect&, const SalBitmap& rBitmap) override; + + virtual bool blendAlphaBitmap(const SalTwoRect&, const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap, + const SalBitmap& rAlphaBitmap) override; + + virtual void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) override; + + virtual void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap) override; + + virtual void drawMask(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, + Color nMaskColor) override; + + virtual std::shared_ptr<SalBitmap> getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight) override; + + virtual Color getPixel(tools::Long nX, tools::Long nY) override; + + // invert --> ClipRegion (only Windows or VirDevs) + virtual void invert(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, + SalInvert nFlags) override; + + virtual void invert(sal_uInt32 nPoints, const Point* pPtAry, SalInvert nFlags) override; + + virtual bool drawEPS(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, + void* pPtr, sal_uInt32 nSize) override; + + /** Render bitmap with alpha channel + + @param rSourceBitmap + Source bitmap to blit + + @param rAlphaBitmap + Alpha channel to use for blitting + + @return true, if the operation succeeded, and false + otherwise. In this case, clients should try to emulate alpha + compositing themselves + */ + virtual bool drawAlphaBitmap(const SalTwoRect&, const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap) override; + + /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ + virtual bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap, double fAlpha) override; + + virtual bool hasFastDrawTransformedBitmap() const override; + + /** Render solid rectangle with given transparency + + @param nX Top left coordinate of rectangle + + @param nY Bottom right coordinate of rectangle + + @param nWidth Width of rectangle + + @param nHeight Height of rectangle + + @param nTransparency Transparency value (0-255) to use. 0 blits and opaque, 255 a + fully transparent rectangle + + @returns true if successfully drawn, false if not able to draw rectangle + */ + virtual bool drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight, sal_uInt8 nTransparency) override; + + virtual bool drawGradient(const tools::PolyPolygon& rPolygon, + const Gradient& rGradient) override; + virtual bool implDrawGradient(const basegfx::B2DPolyPolygon& rPolyPolygon, + const SalGradient& rGradient) override; + + virtual bool supportsOperation(OutDevSupportType eType) const override; + + // Dump contents to a file for debugging. + void dump(const char* file) const; + + // Default blend mode for SkPaint is SkBlendMode::kSrcOver + void drawBitmap(const SalTwoRect& rPosAry, const SkiaSalBitmap& bitmap, + SkBlendMode blendMode = SkBlendMode::kSrcOver); + + void drawImage(const SalTwoRect& rPosAry, const sk_sp<SkImage>& aImage, int srcScaling = 1, + SkBlendMode eBlendMode = SkBlendMode::kSrcOver); + + void drawShader(const SalTwoRect& rPosAry, const sk_sp<SkShader>& shader, + SkBlendMode blendMode = SkBlendMode::kSrcOver); + + void drawGenericLayout(const GenericSalLayout& layout, Color textColor, const SkFont& font, + const SkFont& verticalFont); + +protected: + // To be called before any drawing. + void preDraw(); + // To be called after any drawing. + void postDraw(); + // The canvas to draw to. + SkCanvas* getDrawCanvas() { return mSurface->getCanvas(); } + // Call before makeImageSnapshot(), ensures the content is up to date. + void flushDrawing(); + + virtual void createSurface(); + // Call to ensure that mSurface is valid. If mSurface is going to be modified, + // use preDraw() instead of this. + void checkSurface(); + void destroySurface(); + // Reimplemented for X11. + virtual bool avoidRecreateByResize() const; + void createWindowSurface(bool forceRaster = false); + virtual void createWindowSurfaceInternal(bool forceRaster = false) = 0; + void createOffscreenSurface(); + virtual void flushSurfaceToWindowContext(); + + void privateDrawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, + tools::Long nHeight, double nTransparency, bool blockAA = false); + void privateCopyBits(const SalTwoRect& rPosAry, SkiaSalGraphicsImpl* src); + + void setProvider(SalGeometryProvider* provider) { mProvider = provider; } + + bool isOffscreen() const; + bool isGPU() const { return mIsGPU; } + + void invert(basegfx::B2DPolygon const& rPoly, SalInvert eFlags); + + // Called by SkiaFlushIdle. + void performFlush(); + void scheduleFlush(); + friend class SkiaFlushIdle; + + // get the width of the device + int GetWidth() const { return mProvider ? mProvider->GetWidth() : 1; } + // get the height of the device + int GetHeight() const { return mProvider ? mProvider->GetHeight() : 1; } + // Get the global HiDPI scaling factor. + virtual int getWindowScaling() const; + + void addUpdateRegion(const SkRect& rect) + { + // Make slightly larger, just in case (rounding, antialiasing,...). + SkIRect addedRect = rect.makeOutset(2, 2).round(); + // Using SkIRect should be enough, SkRegion would be too slow with many operations + // and swapping to the screen is not _that_slow. + mDirtyRect.join(addedRect); + } + void setCanvasScalingAndClipping(); + void resetCanvasScalingAndClipping(); + static void setCanvasClipRegion(SkCanvas* canvas, const vcl::Region& region); + sk_sp<SkImage> mergeCacheBitmaps(const SkiaSalBitmap& bitmap, const SkiaSalBitmap* alphaBitmap, + const Size& targetSize); + using DirectImage = SkiaHelper::DirectImage; + static OString makeCachedImageKey(const SkiaSalBitmap& bitmap, const SkiaSalBitmap* alphaBitmap, + const Size& targetSize, DirectImage bitmapType, + DirectImage alphaBitmapType); + + // Skia uses floating point coordinates, so when we use integer coordinates, sometimes + // rounding results in off-by-one errors (down), especially when drawing using GPU, + // see https://bugs.chromium.org/p/skia/issues/detail?id=9611 . Compensate for + // it by using centers of pixels. Using 0.5 may sometimes round up, so go with 0.495 . + static constexpr SkScalar toSkX(tools::Long x) { return x + 0.495; } + static constexpr SkScalar toSkY(tools::Long y) { return y + 0.495; } + // Value to add to be exactly in the middle of the pixel. + static constexpr SkScalar toSkXYFix = SkScalar(0.005); + + // Perform any pending drawing such as delayed merging of polygons. Called by preDraw() + // and anything that means the next operation cannot be another one in a series (e.g. + // changing colors). + void checkPendingDrawing(); + bool delayDrawPolyPolygon(const basegfx::B2DPolyPolygon& polygon, double transparency); + void performDrawPolyPolygon(const basegfx::B2DPolyPolygon& polygon, double transparency, + bool useAA); + + BmpScaleFlag goodScalingQuality() const { return SkiaHelper::goodScalingQuality(isGPU()); } + SkSamplingOptions makeSamplingOptions(const SalTwoRect& rPosAry, int scalingFactor, + int srcScalingFactor = 1) + { + return SkiaHelper::makeSamplingOptions(rPosAry, scalingFactor, srcScalingFactor, isGPU()); + } + SkSamplingOptions makeSamplingOptions(const SkMatrix& matrix, int scalingFactor) + { + return SkiaHelper::makeSamplingOptions(goodScalingQuality(), matrix, scalingFactor); + } + + // Create SkPaint to use when drawing to the surface. It is not to be used + // when doing internal drawing such as when merging two bitmaps together. + // This may apply some default settings to the paint as necessary. + SkPaint makePaintInternal() const; + // Create SkPaint set up for drawing lines (using mLineColor etc.). + SkPaint makeLinePaint(double transparency = 0) const; + // Create SkPaint set up for filling (using mFillColor etc.). + SkPaint makeFillPaint(double transparency = 0) const; + // Create SkPaint set up for bitmap drawing. + SkPaint makeBitmapPaint() const; + // Create SkPaint set up for gradient drawing. + SkPaint makeGradientPaint() const; + // Create SkPaint set up for text drawing. + SkPaint makeTextPaint(std::optional<Color> color) const; + // Create SkPaint for unspecified pixel drawing. Avoid if possible. + SkPaint makePixelPaint(std::optional<Color> color) const; + + template <typename charT, typename traits> + friend inline std::basic_ostream<charT, traits>& + operator<<(std::basic_ostream<charT, traits>& stream, const SkiaSalGraphicsImpl* graphics) + { + if (graphics == nullptr) + return stream << "(null)"; + // O - offscreen, G - GPU-based, R - raster + stream << static_cast<const void*>(graphics) << " " + << Size(graphics->GetWidth(), graphics->GetHeight()); + if (graphics->mScaling != 1) + stream << "*" << graphics->mScaling; + stream << (graphics->isGPU() ? "G" : "R") << (graphics->isOffscreen() ? "O" : ""); + return stream; + } + + void windowBackingPropertiesChanged(); + + SalGraphics& mParent; + /// Pointer to the SalFrame or SalVirtualDevice + SalGeometryProvider* mProvider; + // The Skia surface that is target of all the rendering. + sk_sp<SkSurface> mSurface; + // Note that mSurface may be a proxy surface and not the one from the window context. + std::unique_ptr<sk_app::WindowContext> mWindowContext; + bool mIsGPU; // whether the surface is GPU-backed + // Note that we generally use VCL coordinates, which is not mSurface coordinates if mScaling!=1. + SkIRect mDirtyRect; // The area that has been changed since the last performFlush(). + vcl::Region mClipRegion; + std::optional<Color> moLineColor; + std::optional<Color> moFillColor; + enum class XorMode + { + None, + Invert, + Xor + }; + XorMode mXorMode; + std::unique_ptr<SkiaFlushIdle> mFlush; + // Info about pending polygons to draw (we try to merge adjacent polygons into one). + struct LastPolyPolygonInfo + { + basegfx::B2DPolyPolygonVector polygons; + basegfx::B2DRange bounds; + double transparency; + }; + LastPolyPolygonInfo mLastPolyPolygonInfo; + inline static int pendingOperationsToFlush = 0; + int mScaling; // The scale factor for HiDPI screens. + bool mInWindowBackingPropertiesChanged; +}; + +inline SkPaint SkiaSalGraphicsImpl::makePaintInternal() const +{ + SkPaint paint; + // Invert could be done using a blend mode like invert() does, but + // intentionally use SkBlender to make sure it's not overwritten + // by a blend mode set later (which would be probably a mistake), + // and so that the drawing color does not actually matter. + if (mXorMode == XorMode::Invert) + SkiaHelper::setBlenderInvert(&paint); + else if (mXorMode == XorMode::Xor) + SkiaHelper::setBlenderXor(&paint); + return paint; +} + +inline SkPaint SkiaSalGraphicsImpl::makeLinePaint(double transparency) const +{ + assert(moLineColor.has_value()); + SkPaint paint = makePaintInternal(); + paint.setColor(transparency == 0 + ? SkiaHelper::toSkColor(*moLineColor) + : SkiaHelper::toSkColorWithTransparency(*moLineColor, transparency)); + paint.setStyle(SkPaint::kStroke_Style); + return paint; +} + +inline SkPaint SkiaSalGraphicsImpl::makeFillPaint(double transparency) const +{ + assert(moFillColor.has_value()); + SkPaint paint = makePaintInternal(); + paint.setColor(transparency == 0 + ? SkiaHelper::toSkColor(*moFillColor) + : SkiaHelper::toSkColorWithTransparency(*moFillColor, transparency)); + if (moLineColor == moFillColor) + paint.setStyle(SkPaint::kStrokeAndFill_Style); + else + paint.setStyle(SkPaint::kFill_Style); + return paint; +} + +inline SkPaint SkiaSalGraphicsImpl::makeBitmapPaint() const { return makePaintInternal(); } + +inline SkPaint SkiaSalGraphicsImpl::makeGradientPaint() const { return makePaintInternal(); } + +inline SkPaint SkiaSalGraphicsImpl::makeTextPaint(std::optional<Color> color) const +{ + assert(color.has_value()); + SkPaint paint = makePaintInternal(); + paint.setColor(SkiaHelper::toSkColor(*color)); + return paint; +} + +inline SkPaint SkiaSalGraphicsImpl::makePixelPaint(std::optional<Color> color) const +{ + assert(color.has_value()); + SkPaint paint = makePaintInternal(); + paint.setColor(SkiaHelper::toSkColor(*color)); + return paint; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/osx/bitmap.hxx b/vcl/inc/skia/osx/bitmap.hxx new file mode 100644 index 0000000000..0c0b1ee09b --- /dev/null +++ b/vcl/inc/skia/osx/bitmap.hxx @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_SKIA_OSX_BITMAP_HXX +#define INCLUDED_VCL_INC_SKIA_OSX_BITMAP_HXX + +#include <vcl/dllapi.h> + +#include <osx/osxvcltypes.h> + +class Image; + +namespace SkiaHelper +{ +VCL_PLUGIN_PUBLIC CGImageRef createCGImage(const Image& rImage); +}; + +#endif // INCLUDED_VCL_INC_SKIA_OSX_BITMAP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/osx/gdiimpl.hxx b/vcl/inc/skia/osx/gdiimpl.hxx new file mode 100644 index 0000000000..b97245e86e --- /dev/null +++ b/vcl/inc/skia/osx/gdiimpl.hxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_SKIA_OSX_GDIIMPL_HXX +#define INCLUDED_VCL_INC_SKIA_OSX_GDIIMPL_HXX + +#include <vcl/dllapi.h> + +#include <quartz/salgdi.h> + +#include <skia/gdiimpl.hxx> +#include <skia/utils.hxx> + +#include <SkFontMgr.h> + +class VCL_PLUGIN_PUBLIC AquaSkiaSalGraphicsImpl final : public SkiaSalGraphicsImpl, + public AquaGraphicsBackendBase +{ +public: + AquaSkiaSalGraphicsImpl(AquaSalGraphics& rParent, AquaSharedAttributes& rShared); + virtual ~AquaSkiaSalGraphicsImpl() override; + + virtual void freeResources() override; + + virtual void UpdateGeometryProvider(SalGeometryProvider* provider) override + { + setProvider(provider); + } + static void prepareSkia(); + + virtual bool drawNativeControl(ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRegion, ControlState nState, + const ImplControlValue& aValue) override; + + virtual void drawTextLayout(const GenericSalLayout& layout) override; + + virtual void Flush() override; + virtual void Flush(const tools::Rectangle&) override; + virtual void WindowBackingPropertiesChanged() override; + +private: + virtual int getWindowScaling() const override; + virtual void createWindowSurfaceInternal(bool forceRaster = false) override; + virtual void flushSurfaceToWindowContext() override; + void flushSurfaceToScreenCG(); + static inline sk_sp<SkFontMgr> fontManager; +}; + +#endif // INCLUDED_VCL_INC_SKIA_OSX_GDIIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/quartz/cgutils.h b/vcl/inc/skia/quartz/cgutils.h new file mode 100644 index 0000000000..cb43a31dcd --- /dev/null +++ b/vcl/inc/skia/quartz/cgutils.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +constexpr uint32_t SkiaToCGBitmapType(SkColorType color, SkAlphaType alpha) +{ + if (alpha == kPremul_SkAlphaType) + { + return color == kBGRA_8888_SkColorType + ? (uint32_t(kCGImageAlphaPremultipliedFirst) + | uint32_t(kCGBitmapByteOrder32Little)) + : (uint32_t(kCGImageAlphaPremultipliedLast) | uint32_t(kCGBitmapByteOrder32Big)); + } + else + { + assert(alpha == kOpaque_SkAlphaType); + return color == kBGRA_8888_SkColorType + ? (uint32_t(kCGImageAlphaNoneSkipFirst) | uint32_t(kCGBitmapByteOrder32Little)) + : (uint32_t(kCGImageAlphaNoneSkipLast) | uint32_t(kCGBitmapByteOrder32Big)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/salbmp.hxx b/vcl/inc/skia/salbmp.hxx new file mode 100644 index 0000000000..c42aa30f46 --- /dev/null +++ b/vcl/inc/skia/salbmp.hxx @@ -0,0 +1,231 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SKIA_SALBMP_H +#define INCLUDED_VCL_INC_SKIA_SALBMP_H + +#include <salbmp.hxx> +#include <vcl/bitmap.hxx> + +#include <boost/shared_ptr.hpp> + +#include <skia/utils.hxx> + +#include <SkImage.h> + +class VCL_PLUGIN_PUBLIC SkiaSalBitmap final : public SalBitmap +{ +public: + SkiaSalBitmap(); + SkiaSalBitmap(const sk_sp<SkImage>& image); + virtual ~SkiaSalBitmap() override; + + // SalBitmap methods + virtual bool Create(const Size& rSize, vcl::PixelFormat ePixelFormat, + const BitmapPalette& rPal) override; + virtual bool Create(const SalBitmap& rSalBmp) override; + virtual bool Create(const SalBitmap& rSalBmp, SalGraphics* pGraphics) override; + virtual bool Create(const SalBitmap& rSalBmp, vcl::PixelFormat eNewPixelFormat) override; + virtual bool Create(const css::uno::Reference<css::rendering::XBitmapCanvas>& rBitmapCanvas, + Size& rSize, bool bMask = false) override; + + virtual void Destroy() final override; + + virtual Size GetSize() const override; + virtual sal_uInt16 GetBitCount() const override; + + virtual BitmapBuffer* AcquireBuffer(BitmapAccessMode nMode) override; + virtual void ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) override; + + virtual bool GetSystemData(BitmapSystemData& rData) override; + + virtual bool ScalingSupported() const override; + virtual bool Scale(const double& rScaleX, const double& rScaleY, + BmpScaleFlag nScaleFlag) override; + virtual bool Replace(const Color& rSearchColor, const Color& rReplaceColor, + sal_uInt8 nTol) override; + virtual bool InterpretAs8Bit() override; + virtual bool ConvertToGreyscale() override; + virtual bool Erase(const Color& color) override; + virtual bool AlphaBlendWith(const SalBitmap& rSalBmp) override; + virtual bool Invert() override; +#if defined MACOSX || defined IOS + virtual CGImageRef CreateWithMask(const SalBitmap& rMask, int nX, int nY, int nWidth, + int nHeight) const override; + virtual CGImageRef CreateColorMask(int nX, int nY, int nWidth, int nHeight, + Color nMaskColor) const override; + virtual CGImageRef CreateCroppedImage(int nX, int nY, int nWidth, int nHeight) const override; +#endif + + const BitmapPalette& Palette() const { return mPalette; } + + // True if GetSkShader() should be preferred to GetSkImage() (or the Alpha variants). + bool PreferSkShader() const; + + // Direct image means direct access to the stored SkImage, without checking + // if its size is up to date. This should be used only in special cases with care. + using DirectImage = SkiaHelper::DirectImage; + // Returns the contents as SkImage (possibly GPU-backed). + const sk_sp<SkImage>& GetSkImage(DirectImage direct = DirectImage::No) const; + sk_sp<SkShader> GetSkShader(const SkSamplingOptions& samplingOptions, + DirectImage direct = DirectImage::No) const; + // Returns the contents as alpha SkImage (possibly GPU-backed) + const sk_sp<SkImage>& GetAlphaSkImage(DirectImage direct = DirectImage::No) const; + sk_sp<SkShader> GetAlphaSkShader(const SkSamplingOptions& samplingOptions, + DirectImage direct = DirectImage::No) const; + + // Key for caching/hashing. + OString GetImageKey(DirectImage direct = DirectImage::No) const; + OString GetAlphaImageKey(DirectImage direct = DirectImage::No) const; + + // Returns true if it is known that this bitmap can be ignored if it's to be used + // as an alpha bitmap. An optimization, not guaranteed to return true for all such cases. + bool IsFullyOpaqueAsAlpha() const; + // Alpha type best suitable for the content. + SkAlphaType alphaType() const; + + // Tries to create direct GetAlphaSkImage() from direct GetSkImage(). + void TryDirectConvertToAlphaNoScaling(); + + // Dump contents to a file for debugging. + void dump(const char* file) const; + + // These are to be used only by unittests. + bool unittestHasBuffer() const { return mBuffer.get(); } + bool unittestHasImage() const { return mImage.get(); } + bool unittestHasAlphaImage() const { return mAlphaImage.get(); } + bool unittestHasEraseColor() const { return mEraseColorSet; } + bool unittestHasPendingScale() const { return mSize != mPixelsSize; } + const sal_uInt8* unittestGetBuffer() const { return mBuffer.get(); } + const SkImage* unittestGetImage() const { return mImage.get(); } + const SkImage* unittestGetAlphaImage() const { return mAlphaImage.get(); } + void unittestResetToImage() { ResetToSkImage(GetSkImage()); } + +private: + // This should be called whenever the contents have (possibly) changed. + // It may reset some cached data such as the checksum. + void DataChanged(); + // Reset the state to pixel data (resets cached images allocated in GetSkImage()/GetAlphaSkImage()). + void ResetToBuffer(); + // Sets the data only as SkImage (will be converted as needed). + void ResetToSkImage(sk_sp<SkImage> image); + // Resets all data (buffer and images). + void ResetAllData(); + // Call to ensure mBuffer has data (will convert from mImage if necessary). + void EnsureBitmapData(); + void EnsureBitmapData() const { return const_cast<SkiaSalBitmap*>(this)->EnsureBitmapData(); } + // Like EnsureBitmapData(), but will also make any shared data unique. + // Call before changing the data. + void EnsureBitmapUniqueData(); + // Allocate mBuffer (with uninitialized contents). + void CreateBitmapData(); + // Should be called whenever mPixelsSize or mBitCount is set/changed. + bool ComputeScanlineSize(); + // Resets information about pending scaling. To be called when mBuffer is resized or created. + void ResetPendingScaling(); + // Sets bitmap to be erased on demand. + void EraseInternal(const Color& color); + // Sets pixels to the erase color. + void PerformErase(); + // Try to find out if the content is completely black. Used for optimizations, + // not guaranteed to always return true for such bitmaps. + bool IsAllBlack() const; + void ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode, bool dontChangeToErase); + SkBitmap GetAsSkBitmap() const; + bool ConserveMemory() const; + void verify() const +#ifdef DBG_UTIL + ; +#else + { + } +#endif + + template <typename charT, typename traits> + friend std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, + const SkiaSalBitmap* bitmap) + { + if (bitmap == nullptr) + return stream << "(null)"; + // p - has (non-trivial) palette + // I/i - has SkImage (on GPU/CPU), + // A/a - has alpha SkImage (on GPU/CPU) + // E - has erase color + // B - has pixel buffer + // (wxh) - has pending scaling (after each item) + stream << static_cast<const void*>(bitmap) << " " << bitmap->GetSize() << "x" + << bitmap->GetBitCount(); + if (bitmap->GetBitCount() <= 8 && !bitmap->Palette().IsGreyPalette8Bit()) + stream << "p"; + stream << "/"; + if (bitmap->mImage) + { + stream << (bitmap->mImage->isTextureBacked() ? "I" : "i"); + if (SkiaHelper::imageSize(bitmap->mImage) != bitmap->mSize) + stream << "(" << SkiaHelper::imageSize(bitmap->mImage) << ")"; + } + if (bitmap->mAlphaImage) + { + stream << (bitmap->mAlphaImage->isTextureBacked() ? "A" : "a"); + if (SkiaHelper::imageSize(bitmap->mAlphaImage) != bitmap->mSize) + stream << "(" << SkiaHelper::imageSize(bitmap->mAlphaImage) << ")"; + } + if (bitmap->mEraseColorSet) + stream << "E" << bitmap->mEraseColor; + if (bitmap->mBuffer) + { + stream << "B"; + if (bitmap->mSize != bitmap->mPixelsSize) + stream << "(" << bitmap->mPixelsSize << ")"; + } + return stream; + } + + BitmapPalette mPalette; + int mBitCount = 0; // bpp + Size mSize; + // The contents of the bitmap may be stored in several different ways: + // As mBuffer buffer, which normally stores pixels in the given format. + // As SkImage, as cached GPU-backed data, but sometimes also a result of some operation. + // There is no "master" storage that the other would be derived from. The usual + // mode of operation is that mBuffer holds the data, mImage is created + // on demand as GPU-backed cached data by calling GetSkImage(), and the cached mImage + // is reset by ResetCachedImage(). But sometimes only mImage will be set and in that case + // mBuffer must be filled from it on demand if necessary by EnsureBitmapData(). + boost::shared_ptr<sal_uInt8[]> mBuffer; + int mScanlineSize; // size of one row in mBuffer (based on mPixelsSize) + sk_sp<SkImage> mImage; // possibly GPU-backed + bool mImageImmutable = false; + sk_sp<SkImage> mAlphaImage; // cached contents as alpha image, possibly GPU-backed + // Actual scaling triggered by scale() is done on-demand. This is the size of the pixel + // data in mBuffer, if it differs from mSize, then there is a scaling operation pending. + Size mPixelsSize; + BmpScaleFlag mScaleQuality = BmpScaleFlag::BestQuality; // quality for on-demand scaling + // Erase() is delayed, just sets these two instead of filling the buffer. + bool mEraseColorSet = false; + Color mEraseColor; + int mReadAccessCount = 0; // number of read AcquireAccess() that have not been released +#ifdef DBG_UTIL + int mWriteAccessCount = 0; // number of write AcquireAccess() that have not been released +#endif +}; + +#endif // INCLUDED_VCL_INC_SKIA_SALBMP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/utils.hxx b/vcl/inc/skia/utils.hxx new file mode 100644 index 0000000000..3c19192e1c --- /dev/null +++ b/vcl/inc/skia/utils.hxx @@ -0,0 +1,341 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SKIA_UTILS_H +#define INCLUDED_VCL_INC_SKIA_UTILS_H + +#include <vcl/skia/SkiaHelper.hxx> + +#include <tools/gen.hxx> +#include <driverblocklist.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/salgtype.hxx> + +#include <test/GraphicsRenderTests.hxx> + +#include <premac.h> +#include <SkRegion.h> +#include <SkSurface.h> +#if defined __GNUC__ && !defined __clang__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#pragma GCC diagnostic ignored "-Wshadow" +#endif +#include <tools/sk_app/WindowContext.h> +#if defined __GNUC__ && !defined __clang__ +#pragma GCC diagnostic pop +#endif +#include <postmac.h> + +#include <string_view> + +namespace SkiaHelper +{ +// Get the one shared GrDirectContext instance. +GrDirectContext* getSharedGrDirectContext(); + +void disableRenderMethod(RenderMethod method); + +// Create SkSurface, GPU-backed if possible. +VCL_DLLPUBLIC sk_sp<SkSurface> createSkSurface(int width, int height, + SkColorType type = kN32_SkColorType, + SkAlphaType alpha = kPremul_SkAlphaType); + +inline sk_sp<SkSurface> createSkSurface(const Size& size, SkColorType type = kN32_SkColorType, + SkAlphaType alpha = kPremul_SkAlphaType) +{ + return createSkSurface(size.Width(), size.Height(), type, alpha); +} + +inline sk_sp<SkSurface> createSkSurface(int width, int height, SkAlphaType alpha) +{ + return createSkSurface(width, height, kN32_SkColorType, alpha); +} + +inline sk_sp<SkSurface> createSkSurface(const Size& size, SkAlphaType alpha) +{ + return createSkSurface(size.Width(), size.Height(), kN32_SkColorType, alpha); +} + +// Create SkImage, GPU-backed if possible. +VCL_DLLPUBLIC sk_sp<SkImage> createSkImage(const SkBitmap& bitmap); + +// Call surface->makeImageSnapshot() and abort on failure. +VCL_DLLPUBLIC sk_sp<SkImage> makeCheckedImageSnapshot(sk_sp<SkSurface> surface); +VCL_DLLPUBLIC sk_sp<SkImage> makeCheckedImageSnapshot(sk_sp<SkSurface> surface, + const SkIRect& bounds); + +inline Size imageSize(const sk_sp<SkImage>& image) { return Size(image->width(), image->height()); } + +inline SkColor toSkColor(Color color) +{ + return SkColorSetARGB(color.GetAlpha(), color.GetRed(), color.GetGreen(), color.GetBlue()); +} + +inline SkColor toSkColorWithTransparency(Color aColor, double fTransparency) +{ + return SkColorSetA(toSkColor(aColor), 255 * (1.0 - fTransparency)); +} + +inline SkColor toSkColorWithIntensity(Color color, int intensity) +{ + return SkColorSetARGB(color.GetAlpha(), color.GetRed() * intensity / 100, + color.GetGreen() * intensity / 100, color.GetBlue() * intensity / 100); +} + +inline Color fromSkColor(SkColor color) +{ + return Color(ColorAlpha, SkColorGetA(color), SkColorGetR(color), SkColorGetG(color), + SkColorGetB(color)); +} + +// Whether to use GetSkImage() that checks for delayed scaling or whether to access +// the stored image directly without checks. +enum DirectImage +{ + Yes, + No +}; + +// Sets SkBlender that will do an invert operation. +void setBlenderInvert(SkPaint* paint); +// Sets SkBlender that will do a xor operation. +void setBlenderXor(SkPaint* paint); + +// Must be called in any VCL backend before any Skia functionality is used. +// If not set, Skia will be disabled. +VCL_DLLPUBLIC void + prepareSkia(std::unique_ptr<sk_app::WindowContext> (*createGpuWindowContext)(bool)); + +// Shared cache of images. +void addCachedImage(const OString& key, sk_sp<SkImage> image); +sk_sp<SkImage> findCachedImage(const OString& key); +void removeCachedImage(sk_sp<SkImage> image); +tools::Long maxImageCacheSize(); + +// Get checksum of the image content, only for raster images. Is cached, +// but may still be somewhat expensive. +uint32_t getSkImageChecksum(sk_sp<SkImage> image); + +// SkSurfaceProps to be used by all Skia surfaces. +VCL_DLLPUBLIC const SkSurfaceProps* surfaceProps(); +// Set pixel geometry to be used by SkSurfaceProps. +VCL_DLLPUBLIC void setPixelGeometry(SkPixelGeometry pixelGeometry); + +inline bool isUnitTestRunning(const char* name = nullptr) +{ + if (name == nullptr) + { + static const char* const testname = getenv("LO_TESTNAME"); + if (testname != nullptr) + return true; + return !vcl::test::activeGraphicsRenderTest().isEmpty(); + } + const char* const testname = getenv("LO_TESTNAME"); + if (testname != nullptr && std::string_view(name) == testname) + return true; + return vcl::test::activeGraphicsRenderTest().equalsAscii(name); +} + +// Scaling done on the GPU is fast, but bicubic done in raster mode can be slow +// if done too much, and it generally shouldn't be needed for to-screen drawing. +// In that case use only BmpScaleFlag::Default, which is bilinear+mipmap, +// which should be good enough (and that's what the "super" bitmap scaling +// algorithm done by VCL does as well). +inline BmpScaleFlag goodScalingQuality(bool isGPU) +{ + return isGPU ? BmpScaleFlag::BestQuality : BmpScaleFlag::Default; +} + +// Normal scaling algorithms have a poor quality when downscaling a lot. +// https://bugs.chromium.org/p/skia/issues/detail?id=11810 suggests to use mipmaps +// in such a case, which is annoying to do explicitly instead of Skia deciding which +// algorithm would be the best, but now with Skia removing SkFilterQuality and requiring +// explicitly being told what algorithm to use this appears to be the best we can do. +// Anything scaled down at least this ratio will use linear+mipmaps. +constexpr int downscaleRatioThreshold = 4; + +inline SkSamplingOptions makeSamplingOptions(BmpScaleFlag scalingType, SkMatrix matrix, + int scalingFactor) +{ + switch (scalingType) + { + case BmpScaleFlag::BestQuality: + if (scalingFactor != 1) + matrix.postScale(scalingFactor, scalingFactor); + if (matrix.getScaleX() <= 1.0 / downscaleRatioThreshold + || matrix.getScaleY() <= 1.0 / downscaleRatioThreshold) + return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear); + return SkSamplingOptions(SkCubicResampler::Mitchell()); + case BmpScaleFlag::Default: + // Use SkMipmapMode::kNearest for better quality when downscaling. SkMipmapMode::kLinear + // would be even better, but it is not specially optimized in raster mode. + return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest); + case BmpScaleFlag::Fast: + case BmpScaleFlag::NearestNeighbor: + return SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone); + default: + assert(false); + return SkSamplingOptions(); + } +} + +inline SkSamplingOptions makeSamplingOptions(BmpScaleFlag scalingType, const Size& srcSize, + Size destSize, int scalingFactor) +{ + switch (scalingType) + { + case BmpScaleFlag::BestQuality: + if (scalingFactor != 1) + destSize *= scalingFactor; + if (srcSize.Width() / destSize.Width() >= downscaleRatioThreshold + || srcSize.Height() / destSize.Height() >= downscaleRatioThreshold) + return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear); + return SkSamplingOptions(SkCubicResampler::Mitchell()); + case BmpScaleFlag::Default: + // As in the first overload, use kNearest. + return SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest); + case BmpScaleFlag::Fast: + case BmpScaleFlag::NearestNeighbor: + return SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNone); + default: + assert(false); + return SkSamplingOptions(); + } +} + +inline SkSamplingOptions makeSamplingOptions(const SalTwoRect& rPosAry, int scalingFactor, + int srcScalingFactor, bool isGPU) +{ + // If there will be scaling, make it smooth, but not in unittests, as those often + // require exact color values and would be confused by this. + if (isUnitTestRunning()) + return SkSamplingOptions(); // none + Size srcSize(rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); + Size destSize(rPosAry.mnDestWidth, rPosAry.mnDestHeight); + if (scalingFactor != 1) + destSize *= scalingFactor; + if (srcScalingFactor != 1) + srcSize *= srcScalingFactor; + if (srcSize != destSize) + return makeSamplingOptions(goodScalingQuality(isGPU), srcSize, destSize, 1); + return SkSamplingOptions(); // none +} + +inline SkRect scaleRect(const SkRect& rect, int scaling) +{ + return SkRect::MakeXYWH(rect.x() * scaling, rect.y() * scaling, rect.width() * scaling, + rect.height() * scaling); +} + +inline SkIRect scaleRect(const SkIRect& rect, int scaling) +{ + return SkIRect::MakeXYWH(rect.x() * scaling, rect.y() * scaling, rect.width() * scaling, + rect.height() * scaling); +} + +#ifdef DBG_UTIL +void prefillSurface(const sk_sp<SkSurface>& surface); +#endif + +VCL_DLLPUBLIC void dump(const SkBitmap& bitmap, const char* file); +VCL_DLLPUBLIC void dump(const sk_sp<SkImage>& image, const char* file); +VCL_DLLPUBLIC void dump(const sk_sp<SkSurface>& surface, const char* file); + +VCL_DLLPUBLIC extern uint32_t vendorId; + +inline DriverBlocklist::DeviceVendor getVendor() +{ + return DriverBlocklist::GetVendorFromId(vendorId); +} + +} // namespace SkiaHelper + +// For unittests. +namespace SkiaTests +{ +VCL_DLLPUBLIC bool matrixNeedsHighQuality(const SkMatrix& matrix); +} + +template <typename charT, typename traits> +inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, + const SkRect& rectangle) +{ + if (rectangle.isEmpty()) + return stream << "EMPTY"; + else + return stream << rectangle.width() << 'x' << rectangle.height() << "@(" << rectangle.x() + << ',' << rectangle.y() << ")"; +} + +template <typename charT, typename traits> +inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, + const SkIRect& rectangle) +{ + if (rectangle.isEmpty()) + return stream << "EMPTY"; + else + return stream << rectangle.width() << 'x' << rectangle.height() << "@(" << rectangle.x() + << ',' << rectangle.y() << ")"; +} + +template <typename charT, typename traits> +inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, + const SkRegion& region) +{ + if (region.isEmpty()) + return stream << "EMPTY"; + stream << "("; + SkRegion::Iterator it(region); + for (int i = 0; !it.done(); it.next(), ++i) + stream << "[" << i << "] " << it.rect(); + stream << ")"; + return stream; +} + +template <typename charT, typename traits> +inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, + const SkMatrix& matrix) +{ + return stream << "[" << matrix[0] << " " << matrix[1] << " " << matrix[2] << "]" + << "[" << matrix[3] << " " << matrix[4] << " " << matrix[5] << "]" + << "[" << matrix[6] << " " << matrix[7] << " " << matrix[8] << "]"; +} + +template <typename charT, typename traits> +inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, + const SkImage& image) +{ + // G - on GPU + return stream << static_cast<const void*>(&image) << " " << Size(image.width(), image.height()) + << "/" << (SkColorTypeBytesPerPixel(image.imageInfo().colorType()) * 8) + << (image.isTextureBacked() ? "G" : ""); +} +template <typename charT, typename traits> +inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& stream, + const sk_sp<SkImage>& image) +{ + if (image == nullptr) + return stream << "(null)"; + return stream << *image; +} + +#endif // INCLUDED_VCL_INC_SKIA_UTILS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/win/font.hxx b/vcl/inc/skia/win/font.hxx new file mode 100644 index 0000000000..b63c5cba47 --- /dev/null +++ b/vcl/inc/skia/win/font.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include <sal/config.h> + +#include <win/winlayout.hxx> + +#include <SkTypeface.h> + +// This class only adds SkTypeface in order to allow its caching. +class SkiaWinFontInstance : public WinFontInstance +{ + friend rtl::Reference<LogicalFontInstance> + WinFontFace::CreateFontInstance(const vcl::font::FontSelectPattern&) const; + +public: + sk_sp<SkTypeface> GetSkiaTypeface() const { return m_skiaTypeface; } + bool GetSkiaDWrite() const { return m_skiaDWrite; } + void SetSkiaTypeface(const sk_sp<SkTypeface>& typeface, bool dwrite) + { + m_skiaTypeface = typeface; + m_skiaDWrite = dwrite; + } + +private: + using WinFontInstance::WinFontInstance; + sk_sp<SkTypeface> m_skiaTypeface; + bool m_skiaDWrite; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx new file mode 100644 index 0000000000..c5b12d0881 --- /dev/null +++ b/vcl/inc/skia/win/gdiimpl.hxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_SKIA_WIN_GDIIMPL_HXX +#define INCLUDED_VCL_INC_SKIA_WIN_GDIIMPL_HXX + +#include <memory> +#include <systools/win32/comtools.hxx> + +#include <vcl/dllapi.h> +#include <skia/gdiimpl.hxx> +#include <skia/utils.hxx> +#include <win/salgdi.h> +#include <win/wingdiimpl.hxx> +#include <o3tl/lru_map.hxx> +#include <ControlCacheKey.hxx> +#include <svdata.hxx> + +#include <SkFont.h> +#include <SkFontMgr.h> + +#include <dwrite_3.h> + +class SkTypeface; +class ControlCacheKey; + +class SkiaCompatibleDC : public CompatibleDC +{ +public: + SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int width, int height); + + sk_sp<SkImage> getAsImageDiff(const SkiaCompatibleDC& white) const; +}; + +class WinSkiaSalGraphicsImpl : public SkiaSalGraphicsImpl, public WinSalGraphicsImplBase +{ +private: + WinSalGraphics& mWinParent; + +public: + WinSkiaSalGraphicsImpl(WinSalGraphics& rGraphics, SalGeometryProvider* mpProvider); + + virtual bool UseRenderNativeControl() const override { return true; } + virtual bool TryRenderCachedNativeControl(ControlCacheKey const& rControlCacheKey, int nX, + int nY) override; + virtual bool RenderAndCacheNativeControl(CompatibleDC& rWhite, CompatibleDC& rBlack, int nX, + int nY, ControlCacheKey& aControlCacheKey) override; + + virtual bool DrawTextLayout(const GenericSalLayout& layout) override; + virtual void ClearDevFontCache() override; + virtual void ClearNativeControlCache() override; + + virtual void freeResources() override; + virtual void Flush() override; + + static void prepareSkia(); + +protected: + virtual void createWindowSurfaceInternal(bool forceRaster = false) override; + static sk_sp<SkTypeface> createDirectWriteTypeface(const WinFontInstance* pWinFont); + static void initFontInfo(); + inline static sal::systools::COMReference<IDWriteFontSetBuilder> dwriteFontSetBuilder; + inline static sal::systools::COMReference<IDWriteFontCollection1> dwritePrivateCollection; + inline static sk_sp<SkFontMgr> dwriteFontMgr; + inline static bool dwriteDone = false; + static SkFont::Edging fontEdging; +}; + +typedef std::pair<ControlCacheKey, sk_sp<SkImage>> SkiaControlCachePair; +typedef o3tl::lru_map<ControlCacheKey, sk_sp<SkImage>, ControlCacheHashFunction> + SkiaControlCacheType; + +class SkiaControlsCache +{ + SkiaControlCacheType cache; + + SkiaControlsCache(); + +public: + static SkiaControlCacheType& get(); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/x11/gdiimpl.hxx b/vcl/inc/skia/x11/gdiimpl.hxx new file mode 100644 index 0000000000..f7198671b4 --- /dev/null +++ b/vcl/inc/skia/x11/gdiimpl.hxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_SKIA_X11_GDIIMPL_HXX +#define INCLUDED_VCL_INC_SKIA_X11_GDIIMPL_HXX + +#include <vcl/dllapi.h> + +#include <skia/gdiimpl.hxx> +#include <unx/salgdi.h> +#include <unx/x11/x11gdiimpl.h> + +class VCL_PLUGIN_PUBLIC X11SkiaSalGraphicsImpl final : public SkiaSalGraphicsImpl, + public X11GraphicsImpl +{ +private: + X11SalGraphics& mX11Parent; + +public: + X11SkiaSalGraphicsImpl(X11SalGraphics& rParent); + + virtual void Init() override; + virtual void freeResources() override; + virtual void Flush() override; + + static void prepareSkia(); + +private: + virtual void createWindowSurfaceInternal(bool forceRaster = false) override; + virtual bool avoidRecreateByResize() const override; + static std::unique_ptr<sk_app::WindowContext> + createWindowContext(Display* display, Drawable drawable, const XVisualInfo* visual, int width, + int height, SkiaHelper::RenderMethod renderMethod, bool temporary); + friend std::unique_ptr<sk_app::WindowContext> createVulkanWindowContext(bool); +}; + +#endif // INCLUDED_VCL_INC_SKIA_X11_GDIIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/x11/salvd.hxx b/vcl/inc/skia/x11/salvd.hxx new file mode 100644 index 0000000000..137a58ae67 --- /dev/null +++ b/vcl/inc/skia/x11/salvd.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_SKIA_X11_SALVD_H +#define INCLUDED_VCL_INC_SKIA_X11_SALVD_H + +#include <salvd.hxx> +#include <unx/saldisp.hxx> +#include <unx/salgdi.h> + +class X11SkiaSalVirtualDevice final : public SalVirtualDevice +{ + SalDisplay* mpDisplay; + std::unique_ptr<X11SalGraphics> mpGraphics; + bool mbGraphics; // is Graphics used + SalX11Screen mnXScreen; + int mnWidth; + int mnHeight; + +public: + X11SkiaSalVirtualDevice(const SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, + const SystemGraphicsData* pData, + std::unique_ptr<X11SalGraphics> pNewGraphics); + virtual ~X11SkiaSalVirtualDevice() override; + + // SalGeometryProvider + virtual tools::Long GetWidth() const override { return mnWidth; } + virtual tools::Long GetHeight() const override { return mnHeight; } + + SalDisplay* GetDisplay() const { return mpDisplay; } + const SalX11Screen& GetXScreenNumber() const { return mnXScreen; } + + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics(SalGraphics* pGraphics) override; + + // Set new size, without saving the old contents + virtual bool SetSize(tools::Long nNewDX, tools::Long nNewDY) override; +}; + +#endif // INCLUDED_VCL_INC_SKIA_X11_SALVD_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/x11/textrender.hxx b/vcl/inc/skia/x11/textrender.hxx new file mode 100644 index 0000000000..623e229e8e --- /dev/null +++ b/vcl/inc/skia/x11/textrender.hxx @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SKIA_TEXTRENDER_HXX +#define INCLUDED_VCL_INC_SKIA_TEXTRENDER_HXX + +#include <unx/freetypetextrender.hxx> + +#include <SkFontMgr.h> + +class VCL_DLLPUBLIC SkiaTextRender final : public FreeTypeTextRenderImpl +{ +public: + virtual void DrawTextLayout(const GenericSalLayout&, const SalGraphics&) override; + virtual void ClearDevFontCache() override; + +private: + static inline sk_sp<SkFontMgr> fontManager; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/zone.hxx b/vcl/inc/skia/zone.hxx new file mode 100644 index 0000000000..6d503e7eb8 --- /dev/null +++ b/vcl/inc/skia/zone.hxx @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_SKIA_ZONE_H +#define INCLUDED_VCL_INC_SKIA_ZONE_H + +#include <comphelper/crashzone.hxx> + +#include <vcl/dllapi.h> + +#include <comphelper/solarmutex.hxx> + +// Used around calls to Skia code to detect crashes in drivers. +class VCL_DLLPUBLIC SkiaZone : public CrashZone<SkiaZone> +{ +public: + SkiaZone() { assert(comphelper::SolarMutex::get()->IsCurrentThread()); } + static void hardDisable(); + static void relaxWatchdogTimings(); + static const CrashWatchdogTimingsValues& getCrashWatchdogTimingsValues(); + static void checkDebug(int nUnchanged, const CrashWatchdogTimingsValues& aTimingValues); + static const char* name() { return "Skia"; } +}; + +#endif // INCLUDED_VCL_INC_SKIA_ZONE_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |