[Libreoffice-commits] core.git: vcl/inc vcl/source
Libreoffice Gerrit user
logerrit at kemper.freedesktop.org
Wed Mar 6 18:36:33 UTC 2019
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.vajngerl at collabora.co.uk>
AuthorDate: Sun Mar 3 00:11:54 2019 +0100
Commit: Tomaž Vajngerl <quikee at 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 <quikee at 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();
More information about the Libreoffice-commits
mailing list