tdf#129356: handle css combinator when the element name is combined...

... with the ID or the class

While at it, simplify the code a bit

Change-Id: I9e36f334b884d31229568835a346d4427a47c760
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155945
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Xisco Fauli 2023-08-22 12:46:02 +02:00
parent 3cf3e0e21d
commit b224733640
4 changed files with 81 additions and 48 deletions

View file

@ -125,7 +125,7 @@ namespace svgio::svgreader
const OUString& aConcatenated);
void fillCssStyleVectorUsingHierarchyAndSelectors(
const SvgNode& rCurrent,
const OUString& aConcatenated);
std::u16string_view aConcatenated);
void fillCssStyleVectorUsingParent(
const SvgNode& rCurrent);

View file

@ -441,6 +441,29 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf156168)
assertXPath(pDocument, "/primitive2D/transform/polypolygonstroke[4]/line", "color", "#00ff00");
}
CPPUNIT_TEST_FIXTURE(Test, testTdf129356)
{
Primitive2DSequence aSequence = parseSvg(u"/svgio/qa/cppunit/data/tdf129356.svg");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
drawinglayer::Primitive2dXmlDump dumper;
xmlDocUniquePtr pDocument = dumper.dumpAndParse(aSequence);
CPPUNIT_ASSERT (pDocument);
// Without the fix in place, this test would have failed with
// - Expected: #008000
// - Actual : #0000ff
assertXPath(pDocument, "/primitive2D/transform/polypolygoncolor[1]", "color", "#008000");
assertXPath(pDocument, "/primitive2D/transform/polypolygoncolor[2]", "color", "#008000");
assertXPath(pDocument, "/primitive2D/transform/polypolygoncolor[3]", "color", "#008000");
assertXPath(pDocument, "/primitive2D/transform/polypolygoncolor[4]", "color", "#008000");
assertXPath(pDocument, "/primitive2D/transform/polypolygoncolor[5]", "color", "#008000");
assertXPath(pDocument, "/primitive2D/transform/polypolygoncolor[6]", "color", "#008000");
assertXPath(pDocument, "/primitive2D/transform/polypolygoncolor[7]", "color", "#008000");
assertXPath(pDocument, "/primitive2D/transform/polypolygoncolor[8]", "color", "#008000");
}
CPPUNIT_TEST_FIXTURE(Test, testTdf156034)
{
Primitive2DSequence aSequence = parseSvg(u"/svgio/qa/cppunit/data/tdf156034.svg");

View file

@ -0,0 +1,34 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-0 0 800 800">
<style>
g.g1 rect {fill:green;}
g#g3 rect {fill:green;}
g.g4 #r1 {fill:green;}
g#g3 .r5 {fill:green;}
</style>
<g class="g4 g1">
<g class="g2">
<rect x="0" y="0" height="50" width="50" fill="blue"></rect>
</g>
<rect x="60" y="0" height="50" width="50" fill="blue"></rect>
</g>
<g id="g3">
<g id="g4">
<rect x="120" y="0" height="50" width="50" fill="blue"></rect>
</g>
<rect x="180" y="0" height="50" width="50" fill="blue"></rect>
</g>
<g class="g4 g1">
<g>
<rect id="r1" x="240" y="0" height="50" width="50" fill="blue"></rect>
</g>
<rect id="r1" x="300" y="0" height="50" width="50" fill="blue"></rect>
</g>
<g id="g3">
<g id="g4">
<rect class="r5" x="360" y="0" height="50" width="50" fill="blue"></rect>
</g>
<rect class="r5" x="420" y="0" height="50" width="50" fill="blue"></rect>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -94,7 +94,7 @@ namespace {
void SvgNode::fillCssStyleVectorUsingHierarchyAndSelectors(
const SvgNode& rCurrent,
const OUString& aConcatenated)
std::u16string_view aConcatenated)
{
const SvgDocument& rDocument = getDocument();
@ -102,6 +102,7 @@ namespace {
return;
const SvgNode* pParent = rCurrent.getParent();
OUString sCurrentType(SVGTokenToStr(rCurrent.getType()));
// check for ID (highest priority)
if(rCurrent.getId())
@ -110,21 +111,17 @@ namespace {
if(rId.getLength())
{
const OUString aNewConcatenated(
"#" + rId + aConcatenated);
const OUString aNewConcatenated("#" + rId + aConcatenated);
addCssStyle(rDocument, aNewConcatenated);
if(!sCurrentType.isEmpty())
addCssStyle(rDocument, sCurrentType + aNewConcatenated);
if(pParent)
{
// check for combined selectors at parent first so that higher specificity will be in front
fillCssStyleVectorUsingHierarchyAndSelectors(*pParent, aNewConcatenated);
}
addCssStyle(rDocument, aNewConcatenated);
// look further up in the hierarchy
if(!aConcatenated.isEmpty() && pParent && pParent->getId())
{
const OUString& rParentId = pParent->getId().value();
addCssStyle(rDocument, "#" + rParentId + aConcatenated);
}
}
}
@ -132,55 +129,34 @@ namespace {
for(const auto &aClass : aClasses)
{
const OUString aNewConcatenated("." + aClass + aConcatenated);
addCssStyle(rDocument, aNewConcatenated);
if(!sCurrentType.isEmpty())
addCssStyle(rDocument, sCurrentType + aNewConcatenated);
if(pParent)
{
// check for combined selectors at parent first so that higher specificity will be in front
fillCssStyleVectorUsingHierarchyAndSelectors(*pParent, aNewConcatenated);
}
addCssStyle(rDocument, aNewConcatenated);
// look further up in the hierarchy
if(!aConcatenated.isEmpty() && pParent)
{
std::vector <OUString> aParentClasses = parseClass(*pParent);
for(const auto &aParentClass : aParentClasses)
{
addCssStyle(rDocument, "." + aParentClass + aConcatenated);
}
}
}
OUString sCurrentType(SVGTokenToStr(getType()));
if(!sCurrentType.isEmpty())
{
const OUString aNewConcatenated(sCurrentType + aConcatenated);
addCssStyle(rDocument, aNewConcatenated);
}
OUString sType(SVGTokenToStr(getType()));
// check for class-dependent references to CssStyles
if(sCurrentType.isEmpty())
if(sType.isEmpty())
return;
OUString aNewConcatenated(aConcatenated);
if(!rCurrent.getId() && !rCurrent.getClass() && 0 == aConcatenated.indexOf(sCurrentType))
{
// no new CssStyle Selector and already starts with sCurrentType, do not concatenate;
// we pass an 'empty' node (in the sense of CssStyle Selector)
}
else
{
aNewConcatenated = sCurrentType + aConcatenated;
}
if(pParent)
{
// check for combined selectors at parent first so that higher specificity will be in front
fillCssStyleVectorUsingHierarchyAndSelectors(*pParent, aNewConcatenated);
}
addCssStyle(rDocument, aNewConcatenated);
// check if there is a css style with element inside element
if(pParent)
{
OUString sParentType(SVGTokenToStr(pParent->getType()));
addCssStyle(rDocument, sParentType + sCurrentType);
fillCssStyleVectorUsingHierarchyAndSelectors(*pParent, sType);
}
}
@ -309,7 +285,7 @@ namespace {
fillCssStyleVectorUsingParent(*this);
// check the hierarchy for concatenated patterns of Selectors
fillCssStyleVectorUsingHierarchyAndSelectors(*this, OUString());
fillCssStyleVectorUsingHierarchyAndSelectors(*this, std::u16string_view());
// tdf#99115, Add css selector '*' style only if the element is on top of the hierarchy