diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2020-09-23 23:21:42 +0200 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2020-09-25 12:05:59 +0200 |
commit | eb2753560d9238f60131ff9f64aaf1eb4ae2d764 (patch) | |
tree | 632539e5239a9d8597c7004fbe2ea513c5734497 /vcl | |
parent | eed2f45806fdc14e1dcc8a2820496b1d66379a75 (diff) |
draw linear and radial gradients directly with Skia
Change-Id: I592fd5d823d70c6ca01e90e96a30fb6925f63545
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103282
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/opengl/gdiimpl.hxx | 1 | ||||
-rw-r--r-- | vcl/inc/salgdiimpl.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/skia/gdiimpl.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/unx/salgdi.h | 2 | ||||
-rw-r--r-- | vcl/inc/win/salgdi.h | 3 | ||||
-rw-r--r-- | vcl/opengl/gdiimpl.cxx | 6 | ||||
-rw-r--r-- | vcl/skia/gdiimpl.cxx | 106 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/gdiimpl.cxx | 5 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/gdiimpl.hxx | 1 | ||||
-rw-r--r-- | vcl/unx/generic/gdi/salgdi.cxx | 5 | ||||
-rw-r--r-- | vcl/win/gdi/gdiimpl.cxx | 6 | ||||
-rw-r--r-- | vcl/win/gdi/gdiimpl.hxx | 2 | ||||
-rw-r--r-- | vcl/win/gdi/salgdi.cxx | 10 |
13 files changed, 149 insertions, 2 deletions
diff --git a/vcl/inc/opengl/gdiimpl.hxx b/vcl/inc/opengl/gdiimpl.hxx index a6de106a6018..da6ce6713998 100644 --- a/vcl/inc/opengl/gdiimpl.hxx +++ b/vcl/inc/opengl/gdiimpl.hxx @@ -379,6 +379,7 @@ public: sal_uInt8 nTransparency ) override; virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) override; + virtual bool implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient) override; virtual bool supportsOperation(OutDevSupportType eType) const override; diff --git a/vcl/inc/salgdiimpl.hxx b/vcl/inc/salgdiimpl.hxx index 0e62669d654e..1af6e68bc2b0 100644 --- a/vcl/inc/salgdiimpl.hxx +++ b/vcl/inc/salgdiimpl.hxx @@ -37,6 +37,7 @@ class SalFrame; class Gradient; class OpenGLContext; class SalVirtualDevice; +struct SalGradient; class VCL_PLUGIN_PUBLIC SalGraphicsImpl { @@ -202,6 +203,7 @@ public: sal_uInt8 nTransparency ) = 0; virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) = 0; + virtual bool implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient) = 0; virtual bool supportsOperation(OutDevSupportType eType) const = 0; }; diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx index 2d8086639a08..df0bef608a00 100644 --- a/vcl/inc/skia/gdiimpl.hxx +++ b/vcl/inc/skia/gdiimpl.hxx @@ -192,6 +192,8 @@ public: 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; diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h index 027d0aa6f061..eac9dad95bb8 100644 --- a/vcl/inc/unx/salgdi.h +++ b/vcl/inc/unx/salgdi.h @@ -178,6 +178,8 @@ public: bool bPixelSnapHairline) override; virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) override; + virtual bool implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, + SalGradient const & rGradient) override; #if 1 // TODO: remove these obsolete methods virtual bool drawPolyLineBezier( diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index bf89853e1a8e..f2560f3ade59 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -250,7 +250,8 @@ protected: virtual bool drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry ) override; virtual bool drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry ) override; virtual bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const PolyFlags* const* pFlgAry ) override; - virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) override { return false; }; + virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) override; + virtual bool implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient) override; // CopyArea --> No RasterOp, but ClipRegion virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx index 3125642aa44e..d656d5fdf789 100644 --- a/vcl/opengl/gdiimpl.cxx +++ b/vcl/opengl/gdiimpl.cxx @@ -2188,6 +2188,12 @@ bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly, return true; } +bool OpenGLSalGraphicsImpl::implDrawGradient(basegfx::B2DPolyPolygon const & /*rPolyPolygon*/, + SalGradient const & /*rGradient*/) +{ + return false; +} + void OpenGLSalGraphicsImpl::flush() { FlushDeferredDrawing(); diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index 7722a8018619..8daf50e87160 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -24,11 +24,13 @@ #include <vcl/idle.hxx> #include <vcl/svapp.hxx> #include <vcl/lazydelete.hxx> +#include <vcl/gradient.hxx> #include <vcl/skia/SkiaHelper.hxx> #include <skia/utils.hxx> #include <skia/zone.hxx> #include <SkCanvas.h> +#include <SkGradientShader.h> #include <SkPath.h> #include <SkRegion.h> #include <SkDashPathEffect.h> @@ -192,6 +194,12 @@ SkColor toSkColorWithTransparency(Color aColor, double fTransparency) return SkColorSetA(toSkColor(aColor), 255 * (1.0 - fTransparency)); } +SkColor toSkColorWithIntensity(Color color, int intensity) +{ + return SkColorSetARGB(255 - color.GetTransparency(), color.GetRed() * intensity / 100, + color.GetGreen() * intensity / 100, color.GetBlue() * intensity / 100); +} + Color fromSkColor(SkColor color) { return Color(255 - SkColorGetA(color), SkColorGetR(color), SkColorGetG(color), @@ -1758,7 +1766,103 @@ bool SkiaSalGraphicsImpl::drawAlphaRect(long nX, long nY, long nWidth, long nHei return true; } -bool SkiaSalGraphicsImpl::drawGradient(const tools::PolyPolygon&, const Gradient&) { return false; } +bool SkiaSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPolygon, + const Gradient& rGradient) +{ + if (rGradient.GetStyle() != GradientStyle::Linear + && rGradient.GetStyle() != GradientStyle::Radial) + return false; // unsupported + if (rGradient.GetSteps() != 0) + return false; // We can't tell Skia how many colors to use in the gradient. + preDraw(); + SAL_INFO("vcl.skia.trace", "drawgradient(" << this << "): " << rPolyPolygon.getB2DPolyPolygon() + << ":" << static_cast<int>(rGradient.GetStyle())); + tools::Rectangle boundRect(rPolyPolygon.GetBoundRect()); + if (boundRect.IsEmpty()) + return true; + SkPath path; + if (rPolyPolygon.IsRect()) + { + // Rect->Polygon conversion loses the right and bottom edge, fix that. + path.addRect(SkRect::MakeXYWH(boundRect.getX(), boundRect.getY(), boundRect.GetWidth(), + boundRect.GetHeight())); + boundRect.AdjustRight(1); + boundRect.AdjustBottom(1); + } + else + addPolyPolygonToPath(rPolyPolygon.getB2DPolyPolygon(), path); + path.setFillType(SkPathFillType::kEvenOdd); + addXorRegion(path.getBounds()); + + Gradient aGradient(rGradient); + tools::Rectangle aBoundRect; + Point aCenter; + aGradient.SetAngle(aGradient.GetAngle() + 2700); + aGradient.GetBoundRect(boundRect, aBoundRect, aCenter); + tools::Polygon aPoly(aBoundRect); + aPoly.Rotate(aCenter, aGradient.GetAngle() % 3600); + + SkColor startColor + = toSkColorWithIntensity(rGradient.GetStartColor(), rGradient.GetStartIntensity()); + SkColor endColor = toSkColorWithIntensity(rGradient.GetEndColor(), rGradient.GetEndIntensity()); + + sk_sp<SkShader> shader; + if (rGradient.GetStyle() == GradientStyle::Linear) + { + SkPoint points[2] = { SkPoint::Make(toSkX(aPoly[0].X()), toSkY(aPoly[0].Y())), + SkPoint::Make(toSkX(aPoly[1].X()), toSkY(aPoly[1].Y())) }; + SkColor colors[2] = { startColor, endColor }; + SkScalar pos[2] = { SkDoubleToScalar(aGradient.GetBorder() / 100.0), 1.0 }; + shader = SkGradientShader::MakeLinear(points, colors, pos, 2, SkTileMode::kClamp); + } + else + { + // Move the center by (-1,-1) (the default VCL algorithm is a bit off-center that way). + SkPoint center = SkPoint::Make(toSkX(aCenter.X()) - 1, toSkY(aCenter.Y()) - 1); + SkScalar radius = std::max(aBoundRect.GetWidth() / 2, aBoundRect.GetHeight() / 2); + SkColor colors[2] = { endColor, startColor }; + SkScalar pos[2] = { SkDoubleToScalar(aGradient.GetBorder() / 100.0), 1.0 }; + shader = SkGradientShader::MakeRadial(center, radius, colors, pos, 2, SkTileMode::kClamp); + } + + SkPaint paint; + paint.setShader(shader); + getDrawCanvas()->drawPath(path, paint); + postDraw(); + return true; +} + +bool SkiaSalGraphicsImpl::implDrawGradient(const basegfx::B2DPolyPolygon& rPolyPolygon, + const SalGradient& rGradient) +{ + preDraw(); + SAL_INFO("vcl.skia.trace", + "impldrawgradient(" << this << "): " << rPolyPolygon << ":" << rGradient.maPoint1 + << "->" << rGradient.maPoint2 << ":" << rGradient.maStops.size()); + + SkPath path; + addPolyPolygonToPath(rPolyPolygon, path); + path.setFillType(SkPathFillType::kEvenOdd); + + SkPoint points[2] + = { SkPoint::Make(toSkX(rGradient.maPoint1.getX()), toSkY(rGradient.maPoint1.getY())), + SkPoint::Make(toSkX(rGradient.maPoint2.getX()), toSkY(rGradient.maPoint2.getY())) }; + std::vector<SkColor> colors; + std::vector<SkScalar> pos; + for (const SalGradientStop& stop : rGradient.maStops) + { + colors.emplace_back(toSkColor(stop.maColor)); + pos.emplace_back(stop.mfOffset); + } + sk_sp<SkShader> shader = SkGradientShader::MakeLinear(points, colors.data(), pos.data(), + colors.size(), SkTileMode::kDecal); + SkPaint paint; + paint.setShader(shader); + getDrawCanvas()->drawPath(path, paint); + addXorRegion(path.getBounds()); + postDraw(); + return true; +} static double toRadian(int degree10th) { return (3600 - degree10th) * M_PI / 1800.0; } static double toCos(int degree10th) { return SkScalarCos(toRadian(degree10th)); } diff --git a/vcl/unx/generic/gdi/gdiimpl.cxx b/vcl/unx/generic/gdi/gdiimpl.cxx index a348b752dc89..5dede8f9dda6 100644 --- a/vcl/unx/generic/gdi/gdiimpl.cxx +++ b/vcl/unx/generic/gdi/gdiimpl.cxx @@ -1972,6 +1972,11 @@ bool X11SalGraphicsImpl::drawGradient(const tools::PolyPolygon& /*rPolygon*/, co return false; } +bool X11SalGraphicsImpl::implDrawGradient(basegfx::B2DPolyPolygon const & /*rPolyPolygon*/, SalGradient const & /*rGradient*/) +{ + return false; +} + bool X11SalGraphicsImpl::supportsOperation(OutDevSupportType eType) const { bool bRet = false; diff --git a/vcl/unx/generic/gdi/gdiimpl.hxx b/vcl/unx/generic/gdi/gdiimpl.hxx index 061993bb80df..6a9201cf9c6c 100644 --- a/vcl/unx/generic/gdi/gdiimpl.hxx +++ b/vcl/unx/generic/gdi/gdiimpl.hxx @@ -284,6 +284,7 @@ public: sal_uInt8 nTransparency ) override; virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) override; + virtual bool implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient) override; virtual bool supportsOperation(OutDevSupportType eType) const override; diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx index 79037c1b3a2a..719b07ef8f63 100644 --- a/vcl/unx/generic/gdi/salgdi.cxx +++ b/vcl/unx/generic/gdi/salgdi.cxx @@ -773,6 +773,11 @@ bool X11SalGraphics::drawGradient(const tools::PolyPolygon& rPoly, const Gradien return mxImpl->drawGradient(rPoly, rGradient); } +bool X11SalGraphics::implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient) +{ + return mxImpl->implDrawGradient(rPolyPolygon, rGradient); +} + SalGeometryProvider *X11SalGraphics::GetGeometryProvider() const { if (m_pFrame) diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx index e748fee84126..7c52bf36e879 100644 --- a/vcl/win/gdi/gdiimpl.cxx +++ b/vcl/win/gdi/gdiimpl.cxx @@ -2688,6 +2688,12 @@ bool WinSalGraphicsImpl::drawGradient(const tools::PolyPolygon& /*rPolygon*/, return false; } +bool WinSalGraphicsImpl::implDrawGradient(basegfx::B2DPolyPolygon const & /*rPolyPolygon*/, + SalGradient const & /*rGradient*/) +{ + return false; +} + bool WinSalGraphicsImpl::supportsOperation(OutDevSupportType eType) const { static bool bAllowForTest(true); diff --git a/vcl/win/gdi/gdiimpl.hxx b/vcl/win/gdi/gdiimpl.hxx index 748afbcf04d4..92ef89e3f221 100644 --- a/vcl/win/gdi/gdiimpl.hxx +++ b/vcl/win/gdi/gdiimpl.hxx @@ -241,6 +241,8 @@ public: virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) override; + virtual bool implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, + SalGradient const & rGradient) override; virtual bool supportsOperation(OutDevSupportType eType) const override; }; diff --git a/vcl/win/gdi/salgdi.cxx b/vcl/win/gdi/salgdi.cxx index 4b47b10b8f22..db4ea113b290 100644 --- a/vcl/win/gdi/salgdi.cxx +++ b/vcl/win/gdi/salgdi.cxx @@ -816,6 +816,16 @@ bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* return mpImpl->drawPolyPolygonBezier( nPoly, pPoints, pPtAry, pFlgAry ); } +bool WinSalGraphics::drawGradient(const tools::PolyPolygon& rPoly, const Gradient& rGradient) +{ + return mpImpl->drawGradient(rPoly, rGradient); +} + +bool WinSalGraphics::implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient) +{ + return mpImpl->implDrawGradient(rPolyPolygon, rGradient); +} + static BYTE* ImplSearchEntry( BYTE* pSource, BYTE const * pDest, sal_uLong nComp, sal_uLong nSize ) { while ( nComp-- >= nSize ) |