external/skia/UnpackedTarball_skia.mk | 1 external/skia/allow-no-es2restrictions.patch.1 | 13 ++ vcl/inc/skia/gdiimpl.hxx | 123 ++++++++++++++------- vcl/inc/skia/utils.hxx | 5 vcl/inc/skia/x11/gdiimpl.hxx | 4 vcl/skia/SkiaHelper.cxx | 64 +++++++++++ vcl/skia/gdiimpl.cxx | 143 ++++--------------------- vcl/unx/generic/gdi/salgdi.cxx | 2 8 files changed, 193 insertions(+), 162 deletions(-)
New commits: commit f7a628f8efe037c1fd7e594eb4b8fc6a44573384 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Fri Nov 26 09:10:57 2021 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Nov 29 21:49:10 2021 +0100 implement xor drawing directly using Skia (tdf#141090) Up until now this has been implemented like in almost all other VCL backends by manually xor-ing pixel values. But that required fetching pixel values from the GPU in Vulkan mode, which is relatively slow. Since some time Skia now has supported writing custom blending modes using the SkBlender class, so it's now possible to drop the hack and support xor drawing directly using a blender that does the operation. This should be both faster and simpler. Change-Id: Id751d0ed4034852ce68697ecf56cc6dfac95307f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126051 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/external/skia/UnpackedTarball_skia.mk b/external/skia/UnpackedTarball_skia.mk index c6e27ecf4183..cbaa37895061 100644 --- a/external/skia/UnpackedTarball_skia.mk +++ b/external/skia/UnpackedTarball_skia.mk @@ -37,6 +37,7 @@ skia_patches := \ disable-freetype-colrv1.1 \ windows-libraries-system32.patch.1 \ fix-graphite-ifdef.patch.1 \ + allow-no-es2restrictions.patch.1 \ $(eval $(call gb_UnpackedTarball_set_patchlevel,skia,1)) diff --git a/external/skia/allow-no-es2restrictions.patch.1 b/external/skia/allow-no-es2restrictions.patch.1 new file mode 100644 index 000000000000..0195ad3d2ac8 --- /dev/null +++ b/external/skia/allow-no-es2restrictions.patch.1 @@ -0,0 +1,13 @@ +diff --git a/include/effects/SkRuntimeEffect.h b/include/effects/SkRuntimeEffect.h +index b3f21b1d58..dddc8d16dc 100644 +--- a/include/effects/SkRuntimeEffect.h ++++ b/include/effects/SkRuntimeEffect.h +@@ -97,7 +97,7 @@ public: + // run the inliner directly, but they still get an inlining pass once they are painted.) + bool forceNoInline = false; + +- private: ++// private: + friend class SkRuntimeEffect; + friend class SkRuntimeEffectPriv; + diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx index cc4cda4b2ebd..2473d0918284 100644 --- a/vcl/inc/skia/gdiimpl.hxx +++ b/vcl/inc/skia/gdiimpl.hxx @@ -221,8 +221,8 @@ protected: void preDraw(); // To be called after any drawing. void postDraw(); - // The canvas to draw to. Will be diverted to a temporary for Xor mode. - SkCanvas* getDrawCanvas() { return mXorMode ? getXorCanvas() : mSurface->getCanvas(); } + // The canvas to draw to. + SkCanvas* getDrawCanvas() { return mSurface->getCanvas(); } // Call before makeImageSnapshot(), ensures the content is up to date. void flushDrawing(); @@ -261,22 +261,10 @@ protected: // Get the global HiDPI scaling factor. virtual int getWindowScaling() const; - SkCanvas* getXorCanvas(); - void applyXor(); - // NOTE: This must be called before the operation does any drawing. void addUpdateRegion(const SkRect& rect) { // Make slightly larger, just in case (rounding, antialiasing,...). SkIRect addedRect = rect.makeOutset(2, 2).round(); - if (mXorMode) - { - // Two xor operations should cancel each other out. We batch xor operations, - // but if they can overlap, apply xor now, since applyXor() does the operation - // just once. - if (mXorRegion.intersects(addedRect)) - applyXor(); - mXorRegion.op(addedRect, SkRegion::kUnion_Op); - } // 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); @@ -308,31 +296,22 @@ protected: void performDrawPolyPolygon(const basegfx::B2DPolyPolygon& polygon, double transparency, bool useAA); + // 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 - { - assert(mLineColor != SALCOLOR_NONE); - SkPaint paint; - paint.setColor(transparency == 0 - ? SkiaHelper::toSkColor(mLineColor) - : SkiaHelper::toSkColorWithTransparency(mLineColor, transparency)); - paint.setStyle(SkPaint::kStroke_Style); - return paint; - } + SkPaint makeLinePaint(double transparency = 0) const; // Create SkPaint set up for filling (using mFillColor etc.). - SkPaint makeFillPaint(double transparency = 0) const - { - assert(mFillColor != SALCOLOR_NONE); - SkPaint paint; - paint.setColor(transparency == 0 - ? SkiaHelper::toSkColor(mFillColor) - : SkiaHelper::toSkColorWithTransparency(mFillColor, transparency)); - if (mLineColor == mFillColor) - paint.setStyle(SkPaint::kStrokeAndFill_Style); - else - paint.setStyle(SkPaint::kFill_Style); - return paint; - } + 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(Color color) const; + // Create SkPaint for unspecified pixel drawing. Avoid if possible. + SkPaint makePixelPaint(Color color) const; template <typename charT, typename traits> friend inline std::basic_ostream<charT, traits>& @@ -360,12 +339,15 @@ protected: // 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; - SkRegion mXorRegion; // The area that needs updating for the xor operation. Color mLineColor; Color mFillColor; - bool mXorMode; - SkBitmap mXorBitmap; - std::unique_ptr<SkCanvas> mXorCanvas; + 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 @@ -379,6 +361,65 @@ protected: int mScaling; // The scale factor for HiDPI screens. }; +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(mLineColor != SALCOLOR_NONE); + SkPaint paint = makePaintInternal(); + paint.setColor(transparency == 0 + ? SkiaHelper::toSkColor(mLineColor) + : SkiaHelper::toSkColorWithTransparency(mLineColor, transparency)); + paint.setStyle(SkPaint::kStroke_Style); + return paint; +} + +inline SkPaint SkiaSalGraphicsImpl::makeFillPaint(double transparency) const +{ + assert(mFillColor != SALCOLOR_NONE); + SkPaint paint = makePaintInternal(); + paint.setColor(transparency == 0 + ? SkiaHelper::toSkColor(mFillColor) + : SkiaHelper::toSkColorWithTransparency(mFillColor, transparency)); + if (mLineColor == mFillColor) + 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(Color color) const +{ + assert(color != SALCOLOR_NONE); + SkPaint paint = makePaintInternal(); + paint.setColor(SkiaHelper::toSkColor(color)); + return paint; +} + +inline SkPaint SkiaSalGraphicsImpl::makePixelPaint(Color color) const +{ + assert(color != SALCOLOR_NONE); + SkPaint paint = makePaintInternal(); + paint.setColor(SkiaHelper::toSkColor(color)); + return paint; +} + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/utils.hxx b/vcl/inc/skia/utils.hxx index ac8a185e711e..c4d671ed6b7e 100644 --- a/vcl/inc/skia/utils.hxx +++ b/vcl/inc/skia/utils.hxx @@ -103,6 +103,11 @@ enum DirectImage 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 diff --git a/vcl/inc/skia/x11/gdiimpl.hxx b/vcl/inc/skia/x11/gdiimpl.hxx index b7e9fe2615e0..c2cb69649dab 100644 --- a/vcl/inc/skia/x11/gdiimpl.hxx +++ b/vcl/inc/skia/x11/gdiimpl.hxx @@ -14,6 +14,10 @@ #include <unx/salgdi.h> #include <unx/x11/x11gdiimpl.h> +// X11 headers +constexpr int XNone = None; +#undef None +constexpr int None = XNone; #include <skia/gdiimpl.hxx> class VCL_PLUGIN_PUBLIC X11SkiaSalGraphicsImpl final : public SkiaSalGraphicsImpl, diff --git a/vcl/skia/SkiaHelper.cxx b/vcl/skia/SkiaHelper.cxx index d082b6799129..5b022d51b50d 100644 --- a/vcl/skia/SkiaHelper.cxx +++ b/vcl/skia/SkiaHelper.cxx @@ -644,11 +644,75 @@ tools::Long maxImageCacheSize() return officecfg::Office::Common::Cache::Skia::ImageCacheSize::get(); } +static sk_sp<SkBlender> invertBlender; +static sk_sp<SkBlender> xorBlender; + +// This does the invert operation, i.e. result = color(255-R,255-G,255-B,A). +void setBlenderInvert(SkPaint* paint) +{ + if (!invertBlender) + { + // Note that the colors are premultiplied, so '1 - dst.r' must be + // written as 'dst.a - dst.r', since premultiplied R is in the range (0-A). + const char* const diff = R"( + vec4 main( vec4 src, vec4 dst ) + { + return vec4( dst.a - dst.r, dst.a - dst.g, dst.a - dst.b, dst.a ); + } + )"; + auto effect = SkRuntimeEffect::MakeForBlender(SkString(diff)); + if (!effect.effect) + { + SAL_WARN("vcl.skia", + "SKRuntimeEffect::MakeForBlender failed: " << effect.errorText.c_str()); + abort(); + } + invertBlender = effect.effect->makeBlender(nullptr); + } + paint->setBlender(invertBlender); +} + +// This does the xor operation, i.e. bitwise xor of RGB values of both colors. +void setBlenderXor(SkPaint* paint) +{ + if (!xorBlender) + { + // Note that the colors are premultiplied, converting to 0-255 range + // must also unpremultiply. + const char* const diff = R"( + vec4 main( vec4 src, vec4 dst ) + { + return vec4( + float(int(src.r * src.a * 255.0) ^ int(dst.r * dst.a * 255.0)) / 255.0 / dst.a, + float(int(src.g * src.a * 255.0) ^ int(dst.g * dst.a * 255.0)) / 255.0 / dst.a, + float(int(src.b * src.a * 255.0) ^ int(dst.b * dst.a * 255.0)) / 255.0 / dst.a, + dst.a ); + } + )"; + SkRuntimeEffect::Options opts; + // Skia does not allow binary operators in the default ES2Strict mode, but that's only + // because of OpenGL support. We don't use OpenGL, and it's safe for all modes that we do use. + // https://groups.google.com/g/skia-discuss/c/EPLuQbg64Kc/m/2uDXFIGhAwAJ + opts.enforceES2Restrictions = false; + auto effect = SkRuntimeEffect::MakeForBlender(SkString(diff), opts); + if (!effect.effect) + { + SAL_WARN("vcl.skia", + "SKRuntimeEffect::MakeForBlender failed: " << effect.errorText.c_str()); + abort(); + } + xorBlender = effect.effect->makeBlender(nullptr); + } + paint->setBlender(xorBlender); +} + void cleanup() { sharedWindowContext.reset(); imageCache.clear(); imageCacheSize = 0; + invertBlender.reset(); + xorBlender.reset(); } static SkSurfaceProps commonSurfaceProps; diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index 63d588aa913e..f1670e8c6db5 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -263,7 +263,7 @@ SkiaSalGraphicsImpl::SkiaSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvid , mIsGPU(false) , mLineColor(SALCOLOR_NONE) , mFillColor(SALCOLOR_NONE) - , mXorMode(false) + , mXorMode(XorMode::None) , mFlush(new SkiaFlushIdle(this)) , mPendingOperationsToFlush(0) , mScaling(1) @@ -540,8 +540,6 @@ void SkiaSalGraphicsImpl::flushDrawing() if (!mSurface) return; checkPendingDrawing(); - if (mXorMode) - applyXor(); mSurface->flushAndSubmit(); mPendingOperationsToFlush = 0; } @@ -553,7 +551,7 @@ void SkiaSalGraphicsImpl::setCanvasScalingAndClipping() // If HiDPI scaling is active, simply set a scaling matrix for the canvas. This means // that all painting can use VCL coordinates and they'll be automatically translated to mSurface // scaled coordinates. If that is not wanted, the scale() state needs to be temporarily unset. - // State such as mDirtyRect and mXorRegion is not scaled, the scaling matrix applies to clipping too, + // State such as mDirtyRect is not scaled, the scaling matrix applies to clipping too, // and the rest needs to be handled explicitly. // When reading mSurface contents there's no automatic scaling and it needs to be handled explicitly. canvas->save(); // keep the original state without any scaling @@ -645,109 +643,14 @@ void SkiaSalGraphicsImpl::SetFillColor(Color nColor) mFillColor = nColor; } -void SkiaSalGraphicsImpl::SetXORMode(bool set, bool) +void SkiaSalGraphicsImpl::SetXORMode(bool set, bool invert) { - if (mXorMode == set) + XorMode newMode = set ? (invert ? XorMode::Invert : XorMode::Xor) : XorMode::None; + if (newMode == mXorMode) return; checkPendingDrawing(); - SAL_INFO("vcl.skia.trace", "setxormode(" << this << "): " << set); - if (set) - mXorRegion.setEmpty(); - else - applyXor(); - mXorMode = set; -} - -SkCanvas* SkiaSalGraphicsImpl::getXorCanvas() -{ - SkiaZone zone; - assert(mXorMode); - // Skia does not implement xor drawing, so we need to handle it manually by redirecting - // to a temporary SkBitmap and then doing the xor operation on the data ourselves. - // There's no point in using SkSurface for GPU, we'd immediately need to get the pixels back. - if (!mXorCanvas) - { - // Use unpremultiplied alpha (see xor applying in applyXor()). - if (!mXorBitmap.tryAllocPixels(mSurface->imageInfo().makeAlphaType(kUnpremul_SkAlphaType))) - abort(); - mXorBitmap.eraseARGB(0, 0, 0, 0); - mXorCanvas = std::make_unique<SkCanvas>(mXorBitmap); - if (mScaling != 1) - mXorCanvas->scale(mScaling, mScaling); - setCanvasClipRegion(mXorCanvas.get(), mClipRegion); - } - return mXorCanvas.get(); -} - -void SkiaSalGraphicsImpl::applyXor() -{ - // Apply the result from the temporary bitmap manually. This is indeed - // slow, but it doesn't seem to be needed often and is optimized - // in each operation by extending mXorRegion with the area that should be - // updated. - assert(mXorMode); - if (mScaling != 1 && !mXorRegion.isEmpty()) - { - // Scale mXorRegion to mSurface coordinates if needed. - std::vector<SkIRect> rects; - for (SkRegion::Iterator it(mXorRegion); !it.done(); it.next()) - rects.push_back(scaleRect(it.rect(), mScaling)); - mXorRegion.setRects(rects.data(), rects.size()); - } - if (!mSurface || !mXorCanvas - || !mXorRegion.op(SkIRect::MakeXYWH(0, 0, mSurface->width(), mSurface->height()), - SkRegion::kIntersect_Op)) - { - mXorRegion.setEmpty(); - return; - } - SAL_INFO("vcl.skia.trace", "applyxor(" << this << "): " << mXorRegion); - // Copy the surface contents to another pixmap. - SkBitmap surfaceBitmap; - // Use unpremultiplied alpha format, so that we do not have to do the conversions to get - // the RGB and back (Skia will do it when converting, but it'll be presumably faster at it). - if (!surfaceBitmap.tryAllocPixels(mSurface->imageInfo().makeAlphaType(kUnpremul_SkAlphaType))) - abort(); - SkPaint paint; - paint.setBlendMode(SkBlendMode::kSrc); // copy as is - SkRect area = SkRect::Make(mXorRegion.getBounds()); - { - SkCanvas canvas(surfaceBitmap); - canvas.drawImageRect(makeCheckedImageSnapshot(mSurface), area, area, SkSamplingOptions(), - &paint, SkCanvas::kFast_SrcRectConstraint); - } - // xor to surfaceBitmap - assert(surfaceBitmap.info().alphaType() == kUnpremul_SkAlphaType); - assert(mXorBitmap.info().alphaType() == kUnpremul_SkAlphaType); - assert(surfaceBitmap.bytesPerPixel() == 4); - assert(mXorBitmap.bytesPerPixel() == 4); - for (SkRegion::Iterator it(mXorRegion); !it.done(); it.next()) - { - for (int y = it.rect().top(); y < it.rect().bottom(); ++y) - { - uint8_t* data = static_cast<uint8_t*>(surfaceBitmap.getAddr(it.rect().x(), y)); - const uint8_t* xordata = static_cast<uint8_t*>(mXorBitmap.getAddr(it.rect().x(), y)); - for (int x = 0; x < it.rect().width(); ++x) - { - *data++ ^= *xordata++; - *data++ ^= *xordata++; - *data++ ^= *xordata++; - // alpha is not xor-ed - data++; - xordata++; - } - } - } - surfaceBitmap.notifyPixelsChanged(); - surfaceBitmap.setImmutable(); - // Copy without any clipping or scaling. - resetCanvasScalingAndClipping(); - mSurface->getCanvas()->drawImageRect(surfaceBitmap.asImage(), area, area, SkSamplingOptions(), - &paint, SkCanvas::kFast_SrcRectConstraint); - setCanvasScalingAndClipping(); - mXorCanvas.reset(); - mXorBitmap.reset(); - mXorRegion.setEmpty(); + SAL_INFO("vcl.skia.trace", "setxormode(" << this << "): " << set << "/" << invert); + mXorMode = newMode; } void SkiaSalGraphicsImpl::SetROPLineColor(SalROPColor nROPColor) @@ -796,8 +699,7 @@ void SkiaSalGraphicsImpl::drawPixel(tools::Long nX, tools::Long nY, Color nColor preDraw(); SAL_INFO("vcl.skia.trace", "drawpixel(" << this << "): " << Point(nX, nY) << ":" << nColor); addUpdateRegion(SkRect::MakeXYWH(nX, nY, 1, 1)); - SkPaint paint; - paint.setColor(toSkColor(nColor)); + SkPaint paint = makePixelPaint(nColor); // Apparently drawPixel() is actually expected to set the pixel and not draw it. paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha if (mScaling != 1 && isUnitTestRunning()) @@ -1290,7 +1192,7 @@ void SkiaSalGraphicsImpl::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcG else { src = this; - assert(!mXorMode); + assert(mXorMode == XorMode::None); } auto srcDebug = [&]() -> std::string { if (src == this) @@ -1309,7 +1211,7 @@ void SkiaSalGraphicsImpl::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcG void SkiaSalGraphicsImpl::privateCopyBits(const SalTwoRect& rPosAry, SkiaSalGraphicsImpl* src) { - assert(!mXorMode); + assert(mXorMode == XorMode::None); addUpdateRegion(SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight)); SkPaint paint; @@ -1499,7 +1401,7 @@ void SkiaSalGraphicsImpl::invert(basegfx::B2DPolygon const& rPoly, SalInvert eFl { preDraw(); SAL_INFO("vcl.skia.trace", "invert(" << this << "): " << rPoly << ":" << int(eFlags)); - assert(!mXorMode); + assert(mXorMode == XorMode::None); SkPath aPath; aPath.incReserve(rPoly.count()); addPolygonToPath(rPoly, aPath); @@ -1847,7 +1749,7 @@ void SkiaSalGraphicsImpl::drawImage(const SalTwoRect& rPosAry, const sk_sp<SkIma SkRect aDestinationRect = SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight); - SkPaint aPaint; + SkPaint aPaint = makeBitmapPaint(); aPaint.setBlendMode(eBlendMode); preDraw(); @@ -1871,7 +1773,7 @@ void SkiaSalGraphicsImpl::drawShader(const SalTwoRect& rPosAry, const sk_sp<SkSh SkRect destinationRect = SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight); addUpdateRegion(destinationRect); - SkPaint paint; + SkPaint paint = makeBitmapPaint(); paint.setBlendMode(blendMode); paint.setShader(shader); SkCanvas* canvas = getDrawCanvas(); @@ -1994,12 +1896,13 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, // Specify sizes to scale the image size back if needed (because of mScaling). SkRect dstRect = SkRect::MakeWH(imageSize.Width(), imageSize.Height()); SkRect srcRect = SkRect::MakeWH(imageToDraw->width(), imageToDraw->height()); - canvas->drawImageRect(imageToDraw, srcRect, dstRect, samplingOptions, nullptr, + SkPaint paint = makeBitmapPaint(); + canvas->drawImageRect(imageToDraw, srcRect, dstRect, samplingOptions, &paint, SkCanvas::kFast_SrcRectConstraint); } else { - SkPaint paint; + SkPaint paint = makeBitmapPaint(); // Scale the image size back if needed. SkMatrix scale = SkMatrix::Scale(1.0 / mScaling, 1.0 / mScaling); paint.setShader(SkShaders::Blend( @@ -2026,7 +1929,7 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, samplingOptions = makeSamplingOptions(BmpScaleFlag::BestQuality, matrix, mScaling); if (pSkiaAlphaBitmap) { - SkPaint paint; + SkPaint paint = makeBitmapPaint(); paint.setShader(SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha. rSkiaBitmap.GetSkShader(samplingOptions), pSkiaAlphaBitmap->GetAlphaSkShader(samplingOptions))); @@ -2038,7 +1941,7 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, } else if (rSkiaBitmap.PreferSkShader() || fAlpha != 1.0) { - SkPaint paint; + SkPaint paint = makeBitmapPaint(); paint.setShader(rSkiaBitmap.GetSkShader(samplingOptions)); if (fAlpha != 1.0) paint.setShader( @@ -2048,7 +1951,8 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, } else { - canvas->drawImage(rSkiaBitmap.GetSkImage(), 0, 0, samplingOptions); + SkPaint paint = makeBitmapPaint(); + canvas->drawImage(rSkiaBitmap.GetSkImage(), 0, 0, samplingOptions, &paint); } } postDraw(); @@ -2135,7 +2039,7 @@ bool SkiaSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPolygon, shader = SkGradientShader::MakeRadial(center, radius, colors, pos, 2, SkTileMode::kClamp); } - SkPaint paint; + SkPaint paint = makeGradientPaint(); paint.setAntiAlias(mParent.getAntiAlias()); paint.setShader(shader); getDrawCanvas()->drawPath(path, paint); @@ -2168,7 +2072,7 @@ bool SkiaSalGraphicsImpl::implDrawGradient(const basegfx::B2DPolyPolygon& rPolyP } sk_sp<SkShader> shader = SkGradientShader::MakeLinear(points, colors.data(), pos.data(), colors.size(), SkTileMode::kDecal); - SkPaint paint; + SkPaint paint = makeGradientPaint(); paint.setAntiAlias(mParent.getAntiAlias()); paint.setShader(shader); getDrawCanvas()->drawPath(path, paint); @@ -2229,8 +2133,7 @@ void SkiaSalGraphicsImpl::drawGenericLayout(const GenericSalLayout& layout, Colo glyphIds.data() + index, count * sizeof(SkGlyphID), glyphForms.data() + index, verticalRun ? verticalFont : font, SkTextEncoding::kGlyphID); addUpdateRegion(textBlob->bounds()); - SkPaint paint; - paint.setColor(toSkColor(textColor)); + SkPaint paint = makeTextPaint(textColor); getDrawCanvas()->drawTextBlob(textBlob, 0, 0, paint); pos = rangeEnd; } diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx index 43198c579bae..fd930bd10cfd 100644 --- a/vcl/unx/generic/gdi/salgdi.cxx +++ b/vcl/unx/generic/gdi/salgdi.cxx @@ -105,7 +105,7 @@ void X11SalGraphics::freeResources() if( mpClipRegion ) { XDestroyRegion( mpClipRegion ); - mpClipRegion = None; + mpClipRegion = nullptr; } mxImpl->freeResources();