vcl/inc/widgetdraw/WidgetDefinition.hxx | 17 ++- vcl/source/gdi/FileDefinitionWidgetDraw.cxx | 143 ++++++++++++++++++++++++++++ vcl/source/gdi/WidgetDefinition.cxx | 9 + vcl/source/gdi/WidgetDefinitionReader.cxx | 6 + 4 files changed, 172 insertions(+), 3 deletions(-)
New commits: commit f7ea15720d4aaeb4c79c279da0f679d91c660a74 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Sun Mar 3 00:11:54 2019 +0100 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Wed Mar 6 19:36:03 2019 +0100 Support drawing widgets by interpreting an external SVG definition This uses SvgDrawVisitor and draw commands to draw widgets from an "external" SVG file. The difference to normal SVG drawing is that the shapes are adjusted and not just resized to the widget size. The result of such adjusted drawing is that the margins are preserved exactly just the dimensions of the shapes is adjusted to the desired size (if the shape bounding rectangle starts at {5,5}, so will also when it is adjusted), also the stroke widths are completely preserved. This enables us to use SVG to define also for dynamic widgets, like for example entry fields, listboxes, comboboxes,... which vary in size - depending on the dialog definition. Change-Id: I26fc9a37539d3675a77b48660d235a8a55b81156 Reviewed-on: https://gerrit.libreoffice.org/68816 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/vcl/inc/widgetdraw/WidgetDefinition.hxx b/vcl/inc/widgetdraw/WidgetDefinition.hxx index d3d6c1413992..50aaed65ff2e 100644 --- a/vcl/inc/widgetdraw/WidgetDefinition.hxx +++ b/vcl/inc/widgetdraw/WidgetDefinition.hxx @@ -29,7 +29,8 @@ enum class DrawCommandType RECTANGLE, CIRCLE, LINE, - IMAGE + IMAGE, + EXTERNAL }; class VCL_DLLPUBLIC DrawCommand @@ -114,6 +115,17 @@ public: } }; +class VCL_DLLPUBLIC ExternalSourceDrawCommand : public DrawCommand +{ +public: + OUString msSource; + + ExternalSourceDrawCommand() + : DrawCommand(DrawCommandType::EXTERNAL) + { + } +}; + struct VCL_DLLPUBLIC ControlTypeAndPart { ControlType const meType; @@ -175,7 +187,8 @@ public: void addDrawLine(Color aStrokeColor, sal_Int32 nStrokeWidth, float fX1, float fY1, float fX2, float fY2); - void addDrawImage(OUString sSource); + void addDrawImage(OUString const& sSource); + void addDrawExternal(OUString const& sSource); }; class VCL_DLLPUBLIC WidgetDefinitionPart diff --git a/vcl/source/gdi/FileDefinitionWidgetDraw.cxx b/vcl/source/gdi/FileDefinitionWidgetDraw.cxx index 15c10a16e1b9..c1e15bc9d9c9 100644 --- a/vcl/source/gdi/FileDefinitionWidgetDraw.cxx +++ b/vcl/source/gdi/FileDefinitionWidgetDraw.cxx @@ -17,11 +17,22 @@ #include <basegfx/range/b2drectangle.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <tools/stream.hxx> #include <vcl/bitmapex.hxx> #include <vcl/BitmapTools.hxx> +#include <vcl/pngwrite.hxx> + +#include <comphelper/seqstream.hxx> +#include <comphelper/processfactory.hxx> + +#include <com/sun/star/graphic/SvgTools.hpp> +#include <basegfx/DrawCommands.hxx> + +using namespace css; + namespace vcl { namespace @@ -121,6 +132,111 @@ bool FileDefinitionWidgetDraw::hitTestNativeControl( namespace { +void drawFromDrawCommands(gfx::DrawRoot const& rDrawRoot, SalGraphics& rGraphics, long nX, long nY, + long nWidth, long nHeight) +{ + basegfx::B2DRectangle aSVGRect = rDrawRoot.maRectangle; + + basegfx::B2DRange aTargetSurface(nX, nY, nX + nWidth + 1, nY + nHeight + 1); + + for (std::shared_ptr<gfx::DrawBase> const& pDrawBase : rDrawRoot.maChildren) + { + switch (pDrawBase->getType()) + { + case gfx::DrawCommandType::Rectangle: + { + auto const& rRectangle = static_cast<gfx::DrawRectangle const&>(*pDrawBase); + + basegfx::B2DRange aInputRectangle(rRectangle.maRectangle); + + basegfx::B2DRange aFinalRectangle( + aTargetSurface.getMinX() + aInputRectangle.getMinX(), + aTargetSurface.getMinY() + aInputRectangle.getMinY(), + aTargetSurface.getMaxX() - (aSVGRect.getMaxX() - aInputRectangle.getMaxX()), + aTargetSurface.getMaxY() - (aSVGRect.getMaxY() - aInputRectangle.getMaxY())); + + aInputRectangle.transform(basegfx::utils::createTranslateB2DHomMatrix( + -aInputRectangle.getMinX(), -aInputRectangle.getMinY())); + aInputRectangle.transform(basegfx::utils::createScaleB2DHomMatrix( + aFinalRectangle.getWidth() / aInputRectangle.getWidth(), + aFinalRectangle.getHeight() / aInputRectangle.getHeight())); + aInputRectangle.transform(basegfx::utils::createTranslateB2DHomMatrix( + aFinalRectangle.getMinX() - 0.5, + aFinalRectangle.getMinY() + - 0.5)); // compensate 0.5 for different interpretation of where the center of a pixel is + + basegfx::B2DPolygon aB2DPolygon = basegfx::utils::createPolygonFromRect( + aInputRectangle, rRectangle.mnRx / aFinalRectangle.getWidth() * 2.0, + rRectangle.mnRy / aFinalRectangle.getHeight() * 2.0); + + if (rRectangle.mpFillColor) + { + rGraphics.SetLineColor(); + rGraphics.SetFillColor(Color(*rRectangle.mpFillColor)); + rGraphics.DrawPolyPolygon(basegfx::B2DHomMatrix(), + basegfx::B2DPolyPolygon(aB2DPolygon), 0.0f, nullptr); + } + if (rRectangle.mpStrokeColor) + { + rGraphics.SetLineColor(Color(*rRectangle.mpStrokeColor)); + rGraphics.SetFillColor(); + rGraphics.DrawPolyLine( + basegfx::B2DHomMatrix(), aB2DPolygon, 0.0f, + basegfx::B2DVector(rRectangle.mnStrokeWidth, rRectangle.mnStrokeWidth), + basegfx::B2DLineJoin::Round, css::drawing::LineCap_ROUND, 0.0f, false, + nullptr); + } + } + break; + case gfx::DrawCommandType::Path: + { + auto const& rPath = static_cast<gfx::DrawPath const&>(*pDrawBase); + + basegfx::B2DRange aPolyPolygonRange(rPath.maPolyPolygon.getB2DRange()); + basegfx::B2DPolyPolygon aPolyPolygon(rPath.maPolyPolygon); + + basegfx::B2DRange aFinalRectangle( + aTargetSurface.getMinX() + aPolyPolygonRange.getMinX(), + aTargetSurface.getMinY() + aPolyPolygonRange.getMinY(), + aTargetSurface.getMaxX() - (aSVGRect.getMaxX() - aPolyPolygonRange.getMaxX()), + aTargetSurface.getMaxY() - (aSVGRect.getMaxY() - aPolyPolygonRange.getMaxY())); + + aPolyPolygon.transform(basegfx::utils::createTranslateB2DHomMatrix( + -aPolyPolygonRange.getMinX(), -aPolyPolygonRange.getMinY())); + aPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix( + aFinalRectangle.getWidth() / aPolyPolygonRange.getWidth(), + aFinalRectangle.getHeight() / aPolyPolygonRange.getHeight())); + aPolyPolygon.transform(basegfx::utils::createTranslateB2DHomMatrix( + aFinalRectangle.getMinX() - 0.5, aFinalRectangle.getMinY() - 0.5)); + + if (rPath.mpFillColor) + { + rGraphics.SetLineColor(); + rGraphics.SetFillColor(Color(*rPath.mpFillColor)); + rGraphics.DrawPolyPolygon(basegfx::B2DHomMatrix(), aPolyPolygon, 0.0f, nullptr); + } + if (rPath.mpStrokeColor) + { + rGraphics.SetLineColor(Color(*rPath.mpStrokeColor)); + rGraphics.SetFillColor(); + for (auto const& rPolygon : aPolyPolygon) + { + rGraphics.DrawPolyLine( + basegfx::B2DHomMatrix(), rPolygon, 0.0f, + basegfx::B2DVector(rPath.mnStrokeWidth, rPath.mnStrokeWidth), + basegfx::B2DLineJoin::Round, css::drawing::LineCap_ROUND, 0.0f, false, + nullptr); + } + } + } + break; + + default: + break; + } + } +} + void munchDrawCommands(std::vector<std::shared_ptr<DrawCommand>> const& rDrawCommands, SalGraphics& rGraphics, long nX, long nY, long nWidth, long nHeight) { @@ -210,6 +326,33 @@ void munchDrawCommands(std::vector<std::shared_ptr<DrawCommand>> const& rDrawCom *aBitmap.GetAlpha().ImplGetSalBitmap().get(), nullptr); } break; + case DrawCommandType::EXTERNAL: + { + auto const& rDrawCommand = static_cast<ImageDrawCommand const&>(*pDrawCommand); + SvFileStream aFileStream(rDrawCommand.msSource, StreamMode::READ); + + uno::Reference<uno::XComponentContext> xContext( + comphelper::getProcessComponentContext()); + const uno::Reference<graphic::XSvgParser> xSvgParser + = graphic::SvgTools::create(xContext); + + std::size_t nSize = aFileStream.remainingSize(); + std::vector<sal_Int8> aBuffer(nSize + 1); + aFileStream.ReadBytes(aBuffer.data(), nSize); + aBuffer[nSize] = 0; + + uno::Sequence<sal_Int8> aData(aBuffer.data(), nSize + 1); + uno::Reference<io::XInputStream> aInputStream( + new comphelper::SequenceInputStream(aData)); + + uno::Any aAny = xSvgParser->getDrawCommands(aInputStream, ""); + if (aAny.has<sal_uInt64>()) + { + auto* pDrawRoot = reinterpret_cast<gfx::DrawRoot*>(aAny.get<sal_uInt64>()); + drawFromDrawCommands(*pDrawRoot, rGraphics, nX, nY, nWidth, nHeight); + } + } + break; } } } diff --git a/vcl/source/gdi/WidgetDefinition.cxx b/vcl/source/gdi/WidgetDefinition.cxx index defcf0b84cd8..f861b9efb302 100644 --- a/vcl/source/gdi/WidgetDefinition.cxx +++ b/vcl/source/gdi/WidgetDefinition.cxx @@ -132,13 +132,20 @@ void WidgetDefinitionState::addDrawLine(Color aStrokeColor, sal_Int32 nStrokeWid mpDrawCommands.push_back(std::move(pCommand)); } -void WidgetDefinitionState::addDrawImage(OUString sSource) +void WidgetDefinitionState::addDrawImage(OUString const& sSource) { auto pCommand(std::make_shared<ImageDrawCommand>()); pCommand->msSource = sSource; mpDrawCommands.push_back(std::move(pCommand)); } +void WidgetDefinitionState::addDrawExternal(OUString const& sSource) +{ + auto pCommand(std::make_unique<ExternalSourceDrawCommand>()); + pCommand->msSource = sSource; + mpDrawCommands.push_back(std::move(pCommand)); +} + } // end vcl namespace /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/WidgetDefinitionReader.cxx b/vcl/source/gdi/WidgetDefinitionReader.cxx index 12161f00b7cd..cf361d8793ed 100644 --- a/vcl/source/gdi/WidgetDefinitionReader.cxx +++ b/vcl/source/gdi/WidgetDefinitionReader.cxx @@ -270,6 +270,12 @@ void WidgetDefinitionReader::readDrawingDefinition(tools::XmlWalker& rWalker, rpState->addDrawImage(m_rResourcePath + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8)); } + else if (rWalker.name() == "external") + { + OString sSource = rWalker.attribute("source"); + rpState->addDrawExternal(m_rResourcePath + + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8)); + } rWalker.next(); } rWalker.parent(); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits