From 389c8239c93663fa5546b2f0227a118a3ad091bf Mon Sep 17 00:00:00 2001 From: Tomaž Vajngerl Date: Mon, 4 Nov 2019 18:36:51 +0100 Subject: widget theme: Gradient support when drawing widgets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I29239348e36e4963d9708a22ac649b2b1d68bf02 Reviewed-on: https://gerrit.libreoffice.org/82207 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl --- include/basegfx/DrawCommands.hxx | 46 +++++++++++++++++++++++++++++ svgio/source/svgreader/svgvisitor.cxx | 37 +++++++++++++++++++++++ vcl/headless/svpgdi.cxx | 34 +++++++++++++++++++++ vcl/inc/SalGradient.hxx | 36 ++++++++++++++++++++++ vcl/inc/headless/svpgdi.hxx | 2 ++ vcl/inc/salgdi.hxx | 9 ++++++ vcl/source/gdi/FileDefinitionWidgetDraw.cxx | 46 +++++++++++++++++++++++++++++ vcl/source/gdi/salgdilayout.cxx | 5 ++++ 8 files changed, 215 insertions(+) create mode 100644 vcl/inc/SalGradient.hxx diff --git a/include/basegfx/DrawCommands.hxx b/include/basegfx/DrawCommands.hxx index f72d17011c0b..30e7cfbf4a05 100644 --- a/include/basegfx/DrawCommands.hxx +++ b/include/basegfx/DrawCommands.hxx @@ -16,6 +16,8 @@ #include #include #include +#include +#include namespace gfx { @@ -34,6 +36,48 @@ enum class DrawCommandType Path }; +enum class GradientType +{ + Linear +}; + +class GradientStop +{ +public: + float mfOffset; + basegfx::BColor maColor; + float mfOpacity; +}; + +class GradientInfo +{ +public: + GradientType meType; + + std::vector maGradientStops; + + GradientInfo(GradientType eType) + : meType(eType) + { + } +}; + +class LinearGradientInfo : public GradientInfo +{ +public: + LinearGradientInfo() + : GradientInfo(GradientType::Linear) + { + } + + double x1; + double y1; + double x2; + double y2; + + basegfx::B2DHomMatrix maMatrix; +}; + class DrawBase : public DrawCommand { private: @@ -70,6 +114,7 @@ public: double mnOpacity; std::shared_ptr mpFillColor; std::shared_ptr mpStrokeColor; + std::shared_ptr mpFillGradient; DrawRectangle(basegfx::B2DRange const& rRectangle) : DrawBase(DrawCommandType::Rectangle) @@ -91,6 +136,7 @@ public: double mnOpacity; std::shared_ptr mpFillColor; std::shared_ptr mpStrokeColor; + std::shared_ptr mpFillGradient; DrawPath(basegfx::B2DPolyPolygon const& rPolyPolygon) : DrawBase(DrawCommandType::Path) diff --git a/svgio/source/svgreader/svgvisitor.cxx b/svgio/source/svgreader/svgvisitor.cxx index 011ce5492fa3..52247be8dd43 100644 --- a/svgio/source/svgreader/svgvisitor.cxx +++ b/svgio/source/svgreader/svgvisitor.cxx @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -77,8 +78,44 @@ void SvgDrawVisitor::visit(svgio::svgreader::SvgNode const& rNode) pRectangle->mnOpacity = rRectNode.getSvgStyleAttributes()->getOpacity().getNumber(); const basegfx::BColor* pFillColor = rRectNode.getSvgStyleAttributes()->getFill(); + const SvgGradientNode* pFillGradient + = rRectNode.getSvgStyleAttributes()->getSvgGradientNodeFill(); if (pFillColor) + { pRectangle->mpFillColor = std::make_shared(*pFillColor); + } + else if (pFillGradient) + { + drawinglayer::primitive2d::SvgGradientEntryVector aSvgGradientEntryVector; + pFillGradient->collectGradientEntries(aSvgGradientEntryVector); + if (!aSvgGradientEntryVector.empty()) + { + auto aGradientInfo = std::make_shared(); + + aGradientInfo->x1 = pFillGradient->getX1().getNumber(); + aGradientInfo->y1 = pFillGradient->getY1().getNumber(); + aGradientInfo->x2 = pFillGradient->getX2().getNumber(); + aGradientInfo->y2 = pFillGradient->getY2().getNumber(); + + const basegfx::B2DHomMatrix* pGradientTransform + = pFillGradient->getGradientTransform(); + if (pGradientTransform) + { + aGradientInfo->maMatrix = *pGradientTransform; + } + + pRectangle->mpFillGradient = aGradientInfo; + + for (auto const& rEntry : aSvgGradientEntryVector) + { + gfx::GradientStop aStop; + aStop.maColor = rEntry.getColor(); + aStop.mfOffset = rEntry.getOffset(); + aStop.mfOpacity = rEntry.getOpacity(); + pRectangle->mpFillGradient->maGradientStops.push_back(aStop); + } + } + } const basegfx::BColor* pStrokeColor = rRectNode.getSvgStyleAttributes()->getStroke(); if (pStrokeColor) diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx index 5c1f0daab194..57f66d4fabf6 100644 --- a/vcl/headless/svpgdi.cxx +++ b/vcl/headless/svpgdi.cxx @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1494,6 +1495,39 @@ bool SvpSalGraphics::drawPolyPolygon( return true; } +bool SvpSalGraphics::implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient) +{ + cairo_t* cr = getCairoContext(true); + clipRegion(cr); + + basegfx::B2DHomMatrix rObjectToDevice; + + for (auto const & rPolygon : rPolyPolygon) + AddPolygonToPath(cr, rPolygon, rObjectToDevice, !getAntiAliasB2DDraw(), false); + + cairo_pattern_t* pattern; + pattern = cairo_pattern_create_linear(rGradient.maPoint1.getX(), rGradient.maPoint1.getY(), rGradient.maPoint2.getX(), rGradient.maPoint2.getY()); + + for (SalGradientStop const & rStop : rGradient.maStops) + { + double r = rStop.maColor.GetRed() / 255.0; + double g = rStop.maColor.GetGreen() / 255.0; + double b = rStop.maColor.GetBlue() / 255.0; + double a = (0xFF - rStop.maColor.GetTransparency()) / 255.0; + double offset = rStop.mfOffset; + + cairo_pattern_add_color_stop_rgba(pattern, offset, r, g, b, a); + } + cairo_set_source(cr, pattern); + + basegfx::B2DRange extents = getClippedFillDamage(cr); + cairo_fill_preserve(cr); + + releaseCairoContext(cr, true, extents); + + return true; +} + void SvpSalGraphics::applyColor(cairo_t *cr, Color aColor, double fTransparency) { if (cairo_surface_get_content(m_pSurface) == CAIRO_CONTENT_COLOR_ALPHA) diff --git a/vcl/inc/SalGradient.hxx b/vcl/inc/SalGradient.hxx new file mode 100644 index 000000000000..1b4a47f9a6ff --- /dev/null +++ b/vcl/inc/SalGradient.hxx @@ -0,0 +1,36 @@ +/* -*- 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_SALGRADIENT_HXX +#define INCLUDED_VCL_INC_SALGRADIENT_HXX + +#include + +struct SalGradientStop +{ + Color maColor; + float mfOffset; + + SalGradientStop(Color const& rColor, float fOffset) + : maColor(rColor) + , mfOffset(fOffset) + { + } +}; + +struct SalGradient +{ + basegfx::B2DPoint maPoint1; + basegfx::B2DPoint maPoint2; + std::vector maStops; +}; + +#endif // INCLUDED_VCL_INC_SALGRADIENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx index b0e4aac4adad..d06c138a0284 100644 --- a/vcl/inc/headless/svpgdi.hxx +++ b/vcl/inc/headless/svpgdi.hxx @@ -232,6 +232,8 @@ public: const PolyFlags* const* pFlgAry ) override; virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) override { return false; }; + virtual bool implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient) override; + virtual void copyArea( long nDestX, long nDestY, long nSrcX, diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx index d61c00cd9654..6b5899a4ce10 100644 --- a/vcl/inc/salgdi.hxx +++ b/vcl/inc/salgdi.hxx @@ -25,6 +25,7 @@ #include "impfontmetricdata.hxx" #include "salgdiimpl.hxx" #include "sallayout.hxx" +#include "SalGradient.hxx" #include #include "WidgetDrawInterface.hxx" @@ -275,6 +276,8 @@ public: const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient ); + bool DrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, + SalGradient const & rGradient); // CopyArea --> No RasterOp, but ClipRegion void CopyArea( @@ -486,6 +489,12 @@ protected: const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient ) = 0; + virtual bool implDrawGradient(basegfx::B2DPolyPolygon const & /*rPolyPolygon*/, + SalGradient const & /*rGradient*/) + { + return false; + } + // CopyArea --> No RasterOp, but ClipRegion virtual void copyArea( long nDestX, long nDestY, diff --git a/vcl/source/gdi/FileDefinitionWidgetDraw.cxx b/vcl/source/gdi/FileDefinitionWidgetDraw.cxx index 653a369a1e3d..40d443bb0edf 100644 --- a/vcl/source/gdi/FileDefinitionWidgetDraw.cxx +++ b/vcl/source/gdi/FileDefinitionWidgetDraw.cxx @@ -19,11 +19,13 @@ #include #include +#include #include #include #include #include +#include #include #include @@ -221,6 +223,50 @@ void drawFromDrawCommands(gfx::DrawRoot const& rDrawRoot, SalGraphics& rGraphics basegfx::B2DPolyPolygon(aB2DPolygon), 1.0 - rRectangle.mnOpacity, nullptr); } + else if (rRectangle.mpFillGradient) + { + rGraphics.SetLineColor(); + rGraphics.SetFillColor(); + if (rRectangle.mpFillGradient->meType == gfx::GradientType::Linear) + { + auto* pLinearGradient = static_cast( + rRectangle.mpFillGradient.get()); + SalGradient aGradient; + double x, y; + + x = pLinearGradient->x1; + y = pLinearGradient->y1; + + if (x > aSVGRect.getCenterX()) + x = x + fDeltaX; + if (y > aSVGRect.getCenterY()) + y = y + fDeltaY; + + aGradient.maPoint1 = basegfx::B2DPoint(x, y); + aGradient.maPoint1 *= basegfx::utils::createTranslateB2DHomMatrix( + aTargetSurface.getMinX() - 0.5, aTargetSurface.getMinY() - 0.5); + + x = pLinearGradient->x2; + y = pLinearGradient->y2; + + if (x > aSVGRect.getCenterX()) + x = x + fDeltaX; + if (y > aSVGRect.getCenterY()) + y = y + fDeltaY; + + aGradient.maPoint2 = basegfx::B2DPoint(x, y); + aGradient.maPoint2 *= basegfx::utils::createTranslateB2DHomMatrix( + aTargetSurface.getMinX() - 0.5, aTargetSurface.getMinY() - 0.5); + + for (gfx::GradientStop const& rStop : pLinearGradient->maGradientStops) + { + Color aColor(rStop.maColor); + aColor.SetTransparency(rStop.mfOpacity * (1.0f - rRectangle.mnOpacity)); + aGradient.maStops.emplace_back(aColor, rStop.mfOffset); + } + rGraphics.DrawGradient(basegfx::B2DPolyPolygon(aB2DPolygon), aGradient); + } + } if (rRectangle.mpStrokeColor) { rGraphics.SetLineColor(Color(*rRectangle.mpStrokeColor)); diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx index c3c3c306d19e..b0fefa665bd5 100644 --- a/vcl/source/gdi/salgdilayout.cxx +++ b/vcl/source/gdi/salgdilayout.cxx @@ -652,6 +652,11 @@ bool SalGraphics::DrawGradient( const tools::PolyPolygon& rPolyPoly, const Gradi return drawGradient( rPolyPoly, rGradient ); } +bool SalGraphics::DrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rSalGradient) +{ + return implDrawGradient(rPolyPolygon, rSalGradient); +} + void SalGraphics::CopyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, long nSrcHeight, -- cgit v1.2.3