summaryrefslogtreecommitdiff
path: root/svgio
diff options
context:
space:
mode:
authorXisco Fauli <xiscofauli@libreoffice.org>2024-10-02 13:07:47 +0200
committerAdolfo Jayme Barrientos <fitojb@ubuntu.com>2024-10-05 20:03:52 +0200
commitfcd2db0dff13ac592573c53c7da5fa6844695514 (patch)
tree39dda15ce926cd9319942537a9b358a397bb997b /svgio
parent9f4571da1df09461a58a7a7d1a7f0efcb7ac4959 (diff)
tdf#163212: context-fill/context-stroke can also use gradients
Change-Id: Ic6f7f5e0817d8f5fccee64938004aa899bde47dc Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174382 Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org> Tested-by: Jenkins Signed-off-by: Xisco Fauli <xiscofauli@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174384 Reviewed-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
Diffstat (limited to 'svgio')
-rw-r--r--svgio/inc/svgmarkernode.hxx4
-rw-r--r--svgio/inc/svgstyleattributes.hxx15
-rw-r--r--svgio/qa/cppunit/SvgImportTest.cxx11
-rw-r--r--svgio/qa/cppunit/data/contextStrokeGradient.svg24
-rw-r--r--svgio/source/svgreader/svgmarkernode.cxx3
-rw-r--r--svgio/source/svgreader/svgstyleattributes.cxx169
6 files changed, 144 insertions, 82 deletions
diff --git a/svgio/inc/svgmarkernode.hxx b/svgio/inc/svgmarkernode.hxx
index b8fa7c000e68..489387dc07e7 100644
--- a/svgio/inc/svgmarkernode.hxx
+++ b/svgio/inc/svgmarkernode.hxx
@@ -60,6 +60,8 @@ namespace svgio::svgreader
double mfAngle;
MarkerOrient maMarkerOrient;
+ const SvgStyleAttributes* maContextStyleAttibutes;
+
public:
SvgMarkerNode(
SvgDocument& rDocument,
@@ -106,6 +108,8 @@ namespace svgio::svgreader
MarkerOrient getMarkerOrient() const { return maMarkerOrient; }
void setMarkerOrient(const MarkerOrient aMarkerOrient) { maMarkerOrient = aMarkerOrient; }
+ const SvgStyleAttributes* getContextStyleAttributes() const { return maContextStyleAttibutes; }
+ void setContextStyleAttributes(const SvgStyleAttributes* aContextStyleAttibutes) { maContextStyleAttibutes = aContextStyleAttibutes; }
};
} // end of namespace svgio::svgreader
diff --git a/svgio/inc/svgstyleattributes.hxx b/svgio/inc/svgstyleattributes.hxx
index 30cbab965644..46b8baf4d1d3 100644
--- a/svgio/inc/svgstyleattributes.hxx
+++ b/svgio/inc/svgstyleattributes.hxx
@@ -248,18 +248,21 @@ namespace svgio::svgreader
bool mbStrokeDasharraySet : 1;
// tdf#155651 Defines if 'context-fill' is used in fill
- bool mbContextFill : 1;
+ bool mbUseFillFromContextFill : 1;
+
+ // tdf#155651 Defines if 'context-stroke' is used in fill
+ bool mbUseFillFromContextStroke : 1;
+
+ // tdf#155651 Defines if 'context-fill' is used in stroke
+ bool mbUseStrokeFromContextFill : 1;
// tdf#155651 Defines if 'context-stroke' is used in stroke
- bool mbContextStroke : 1;
+ bool mbUseStrokeFromContextStroke : 1;
// tdf#94765 Check id references in gradient/pattern getters
OUString maNodeFillURL;
OUString maNodeStrokeURL;
- const basegfx::BColor* maContextFill;
- const basegfx::BColor* maContextStroke;
-
/// internal helpers
void add_fillGradient(
const basegfx::B2DPolyPolygon& rPath,
@@ -320,6 +323,8 @@ namespace svgio::svgreader
void readCssStyle(std::u16string_view rCandidate);
const SvgStyleAttributes* getParentStyle() const;
+ const SvgMarkerNode* getMarkerParentNode() const;
+
SvgStyleAttributes(SvgNode& rOwner);
~SvgStyleAttributes();
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx b/svgio/qa/cppunit/SvgImportTest.cxx
index 0f2478860d9b..9d03b0bae39d 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -686,6 +686,17 @@ CPPUNIT_TEST_FIXTURE(Test, testContextStroke)
assertXPath(pDocument, "/primitive2D/transform/transform[4]/polypolygonstroke/line"_ostr, "color"_ostr, u"#ff0000"_ustr);
}
+CPPUNIT_TEST_FIXTURE(Test, testContextStrokeGradient)
+{
+ xmlDocUniquePtr pDocument = dumpAndParseSvg(u"/svgio/qa/cppunit/data/contextStrokeGradient.svg");
+
+ assertXPath(pDocument, "/primitive2D/transform/svglineargradient"_ostr);
+ assertXPath(pDocument, "/primitive2D/transform/transform[1]/svglineargradient"_ostr);
+ assertXPath(pDocument, "/primitive2D/transform/transform[2]/svglineargradient"_ostr);
+ assertXPath(pDocument, "/primitive2D/transform/transform[3]/svglineargradient"_ostr);
+ assertXPath(pDocument, "/primitive2D/transform/transform[4]/svglineargradient"_ostr);
+}
+
CPPUNIT_TEST_FIXTURE(Test, testMarkerInPresentation)
{
xmlDocUniquePtr pDocument = dumpAndParseSvg(u"/svgio/qa/cppunit/data/markerInPresentation.svg");
diff --git a/svgio/qa/cppunit/data/contextStrokeGradient.svg b/svgio/qa/cppunit/data/contextStrokeGradient.svg
new file mode 100644
index 000000000000..7de3f70b6a0e
--- /dev/null
+++ b/svgio/qa/cppunit/data/contextStrokeGradient.svg
@@ -0,0 +1,24 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
+ <style>
+ path {
+ fill: none;
+ stroke-width: 4px;
+ marker: url(#diamond);
+ }
+ </style>
+ <defs>
+ <linearGradient
+ id="swatch7">
+ <stop
+ style="stop-color:#23a2b0;stop-opacity:1;"
+ offset="0"
+ id="stop7" />
+ </linearGradient>
+ </defs>
+
+ <path d="M 10,50 v -20 h 40 v -20" stroke="url(#swatch7)"/>
+
+ <marker id="diamond" markerWidth="12" markerHeight="12" refX="6" refY="6" markerUnits="userSpaceOnUse">
+ <circle cx="6" cy="6" r="3" fill="white" stroke="context-stroke" stroke-width="2"/>
+ </marker>
+</svg>
diff --git a/svgio/source/svgreader/svgmarkernode.cxx b/svgio/source/svgreader/svgmarkernode.cxx
index 2279920634a6..c2e1f2716ab9 100644
--- a/svgio/source/svgreader/svgmarkernode.cxx
+++ b/svgio/source/svgreader/svgmarkernode.cxx
@@ -33,7 +33,8 @@ namespace svgio::svgreader
maMarkerWidth(3),
maMarkerHeight(3),
mfAngle(0.0),
- maMarkerOrient(MarkerOrient::notset)
+ maMarkerOrient(MarkerOrient::notset),
+ maContextStyleAttibutes(nullptr)
{
}
diff --git a/svgio/source/svgreader/svgstyleattributes.cxx b/svgio/source/svgreader/svgstyleattributes.cxx
index 5fe78f8b58d0..c3dbdaacea47 100644
--- a/svgio/source/svgreader/svgstyleattributes.cxx
+++ b/svgio/source/svgreader/svgstyleattributes.cxx
@@ -259,6 +259,23 @@ namespace svgio::svgreader
return nullptr;
}
+ const SvgMarkerNode* SvgStyleAttributes::getMarkerParentNode() const
+ {
+ if (SVGToken::Marker == mrOwner.getType())
+ return static_cast<const SvgMarkerNode *>(&mrOwner);
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+ if (pSvgStyleAttributes && maResolvingParent[32] < nStyleDepthLimit)
+ {
+ ++maResolvingParent[32];
+ const SvgMarkerNode* ret = pSvgStyleAttributes->getMarkerParentNode();
+ --maResolvingParent[32];
+ return ret;
+ }
+
+ return nullptr;
+ }
+
void SvgStyleAttributes::add_text(
drawinglayer::primitive2d::Primitive2DContainer& rTarget,
drawinglayer::primitive2d::Primitive2DContainer&& rSource) const
@@ -600,9 +617,36 @@ namespace svgio::svgreader
drawinglayer::primitive2d::Primitive2DContainer& rTarget,
const basegfx::B2DRange& rGeoRange) const
{
- const basegfx::BColor* pFill = getFill();
- const SvgGradientNode* pFillGradient = getSvgGradientNodeFill();
- const SvgPatternNode* pFillPattern = getSvgPatternNodeFill();
+ const basegfx::BColor* pFill = nullptr;
+ const SvgGradientNode* pFillGradient = nullptr;
+ const SvgPatternNode* pFillPattern = nullptr;
+
+ if (mbUseFillFromContextFill)
+ {
+ if (const SvgMarkerNode* pMarker = getMarkerParentNode())
+ {
+ const SvgStyleAttributes* pStyle = pMarker->getContextStyleAttributes();
+ pFill = pStyle->getFill();
+ pFillGradient = pStyle->getSvgGradientNodeFill();
+ pFillPattern = pStyle->getSvgPatternNodeFill();
+ }
+ }
+ else if (mbUseFillFromContextStroke)
+ {
+ if (const SvgMarkerNode* pMarker = getMarkerParentNode())
+ {
+ const SvgStyleAttributes* pStyle = pMarker->getContextStyleAttributes();
+ pFill = pStyle->getStroke();
+ pFillGradient = pStyle->getSvgGradientNodeStroke();
+ pFillPattern = pStyle->getSvgPatternNodeStroke();
+ }
+ }
+ else
+ {
+ pFill = getFill();
+ pFillGradient = getSvgGradientNodeFill();
+ pFillPattern = getSvgPatternNodeFill();
+ }
if(!(pFill || pFillGradient || pFillPattern))
return;
@@ -656,9 +700,36 @@ namespace svgio::svgreader
drawinglayer::primitive2d::Primitive2DContainer& rTarget,
const basegfx::B2DRange& rGeoRange) const
{
- const basegfx::BColor* pStroke = getStroke();
- const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke();
- const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke();
+ const basegfx::BColor* pStroke = nullptr;
+ const SvgGradientNode* pStrokeGradient = nullptr;
+ const SvgPatternNode* pStrokePattern = nullptr;
+
+ if(mbUseStrokeFromContextFill)
+ {
+ if (const SvgMarkerNode* pMarker = getMarkerParentNode())
+ {
+ const SvgStyleAttributes* pStyle = pMarker->getContextStyleAttributes();
+ pStroke = pStyle->getFill();
+ pStrokeGradient = pStyle->getSvgGradientNodeFill();
+ pStrokePattern = pStyle->getSvgPatternNodeFill();
+ }
+ }
+ else if(mbUseStrokeFromContextStroke)
+ {
+ if (const SvgMarkerNode* pMarker = getMarkerParentNode())
+ {
+ const SvgStyleAttributes* pStyle = pMarker->getContextStyleAttributes();
+ pStroke = pStyle->getStroke();
+ pStrokeGradient = pStyle->getSvgGradientNodeStroke();
+ pStrokePattern = pStyle->getSvgPatternNodeStroke();
+ }
+ }
+ else
+ {
+ pStroke = getStroke();
+ pStrokeGradient = getSvgGradientNodeStroke();
+ pStrokePattern = getSvgPatternNodeStroke();
+ }
if(!(pStroke || pStrokeGradient || pStrokePattern))
return;
@@ -823,15 +894,11 @@ namespace svgio::svgreader
rMarkerTransform.identity();
rClipRange.reset();
- // Set the current fill to the marker before calling getMarkerPrimitives,
- // which calls decomposeSvgNode to decompose the children of the marker.
- // If any of the children uses 'fill="context-fill"', then it will use it
- const_cast<SvgStyleAttributes*>(rMarker.getSvgStyleAttributes())->maContextFill = getFill();
-
- // Set the current stroke to the marker before calling getMarkerPrimitives,
+ // Set the current style attibutes to the marker before calling getMarkerPrimitives,
// which calls decomposeSvgNode to decompose the children of the marker.
- // If any of the children uses 'stroke="context-stroke"', then it will use it
- const_cast<SvgStyleAttributes*>(rMarker.getSvgStyleAttributes())->maContextStroke = getStroke();
+ // If any children uses 'context-fill' or 'context-stroke',
+ // then these style attributes will be used in add_fill or add_stroke
+ const_cast<SvgMarkerNode&>(rMarker).setContextStyleAttributes(this);
// get marker primitive representation
rMarkerPrimitives = rMarker.getMarkerPrimitives();
@@ -1320,12 +1387,12 @@ namespace svgio::svgreader
maBaselineShift(BaselineShift::Baseline),
maBaselineShiftNumber(0),
maDominantBaseline(DominantBaseline::Auto),
- maResolvingParent(35, 0),
+ maResolvingParent(34, 0),
mbStrokeDasharraySet(false),
- mbContextFill(false),
- mbContextStroke(false),
- maContextFill(nullptr),
- maContextStroke(nullptr)
+ mbUseFillFromContextFill(false),
+ mbUseFillFromContextStroke(false),
+ mbUseStrokeFromContextFill(false),
+ mbUseStrokeFromContextStroke(false)
{
}
@@ -1347,11 +1414,11 @@ namespace svgio::svgreader
if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"context-fill"))
{
- mbContextFill = true;
+ mbUseFillFromContextFill = true;
}
else if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"context-stroke"))
{
- mbContextStroke = true;
+ mbUseFillFromContextStroke = true;
}
else if(readSvgPaint(aContent, aSvgPaint, aURL, aOpacity))
{
@@ -1400,11 +1467,11 @@ namespace svgio::svgreader
if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"context-stroke"))
{
- mbContextStroke = true;
+ mbUseStrokeFromContextStroke = true;
}
else if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"context-fill"))
{
- mbContextFill = true;
+ mbUseStrokeFromContextFill = true;
}
else if(readSvgPaint(aContent, aSvgPaint, aURL, aOpacity))
{
@@ -2049,40 +2116,6 @@ namespace svgio::svgreader
}
}
- const basegfx::BColor* SvgStyleAttributes::getContextFill() const
- {
- if (SVGToken::Marker == mrOwner.getType())
- return maContextFill;
-
- const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
- if (pSvgStyleAttributes && maResolvingParent[33] < nStyleDepthLimit)
- {
- ++maResolvingParent[33];
- auto ret = pSvgStyleAttributes->getContextFill();
- --maResolvingParent[33];
- return ret;
- }
-
- return nullptr;
- }
-
- const basegfx::BColor* SvgStyleAttributes::getContextStroke() const
- {
- if (SVGToken::Marker == mrOwner.getType())
- return maContextStroke;
-
- const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
- if (pSvgStyleAttributes && maResolvingParent[32] < nStyleDepthLimit)
- {
- ++maResolvingParent[32];
- auto ret = pSvgStyleAttributes->getContextStroke();
- --maResolvingParent[32];
- return ret;
- }
-
- return nullptr;
- }
-
bool SvgStyleAttributes::isClipPathContent() const
{
if (SVGToken::ClipPathNode == mrOwner.getType())
@@ -2151,14 +2184,6 @@ namespace svgio::svgreader
}
}
}
- else if (mbContextFill)
- {
- return getContextFill();
- }
- else if (mbContextStroke)
- {
- return getContextStroke();
- }
else if (maNodeFillURL.isEmpty())
{
const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
@@ -2204,14 +2229,6 @@ namespace svgio::svgreader
return &maStroke.getBColor();
}
}
- else if (mbContextFill)
- {
- return getContextFill();
- }
- else if (mbContextStroke)
- {
- return getContextStroke();
- }
else if (maNodeStrokeURL.isEmpty())
{
const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
@@ -2430,11 +2447,11 @@ namespace svgio::svgreader
const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
- if (pSvgStyleAttributes && maResolvingParent[34] < nStyleDepthLimit)
+ if (pSvgStyleAttributes && maResolvingParent[33] < nStyleDepthLimit)
{
- ++maResolvingParent[34];
+ ++maResolvingParent[33];
auto ret = pSvgStyleAttributes->getOpacity();
- --maResolvingParent[34];
+ --maResolvingParent[33];
return ret;
}