Kaydet (Commit) 37446076 authored tarafından Armin Le Grand's avatar Armin Le Grand

#120334# Added support for multiple CSS styles per graphic primitive in SVG

üst 5ee3e9d6
......@@ -50,6 +50,7 @@ namespace svgio
namespace svgreader
{
typedef ::std::vector< SvgNode* > SvgNodeVector;
typedef ::std::vector< const SvgStyleAttributes* > SvgStyleAttributeVector;
enum XmlSpace
{
......@@ -79,6 +80,13 @@ namespace svgio
/// XmlSpace value
XmlSpace maXmlSpace;
/// CSS styles
SvgStyleAttributeVector maCssStyleVector;
protected:
/// helper to evtl. link to css style
const SvgStyleAttributes* checkForCssStyle(const rtl::OUString& rClassStr, const SvgStyleAttributes& rOriginal) const;
public:
SvgNode(
SVGToken aType,
......
......@@ -139,12 +139,18 @@ namespace svgio
TextAnchor_end
};
enum FillRule
{
FillRule_notset,
FillRule_nonzero,
FillRule_evenodd
};
class SvgStyleAttributes
{
private:
SvgNode& mrOwner;
const SvgStyleAttributes* mpCssStyleParent;
SvgPaint maFill;
SvgPaint maStroke;
SvgPaint maStopColor;
......@@ -187,18 +193,19 @@ namespace svgio
rtl::OUString maMarkerEndXLink;
const SvgMarkerNode* mpMarkerEndXLink;
/// fill rule
FillRule maFillRule;
// ClipRule setting (only valid wne mbIsClipPathContent == true, default is FillRule_nonzero)
FillRule maClipRule;
/// bitfield
bool maFillRule : 1; // true: NonZero, false: EvenOdd
bool maFillRuleSet : 1;
// defines if this attributes are part of a ClipPath. If yes,
// rough geometry will be created on decomposition by patching
// vaules for fill, stroke, strokeWidth and others
bool mbIsClipPathContent : 1;
// ClipRule setting (only valid wne mbIsClipPathContent == true)
bool mbClipRule : 1; // true == nonzero(default), false == evenodd
/// internal helpers
void add_fillGradient(
const basegfx::B2DPolyPolygon& rPath,
......@@ -256,8 +263,9 @@ namespace svgio
const drawinglayer::primitive2d::Primitive2DSequence& rSource,
const basegfx::B2DHomMatrix* pTransform) const;
/// helper to evtl. link to css style
void checkForCssStyle(const rtl::OUString& rClassStr) const;
/// helper to set mpCssStyleParent temporarily for CSS style hierarchies
void setCssStyleParent(const SvgStyleAttributes* pNew) { mpCssStyleParent = pNew; }
const SvgStyleAttributes* getCssStyleParent() const { return mpCssStyleParent; }
/// scan helpers
void readStyle(const rtl::OUString& rCandidate);
......@@ -307,8 +315,8 @@ namespace svgio
void setFillOpacity(const SvgNumber& rFillOpacity = SvgNumber()) { maFillOpacity = rFillOpacity; }
/// fill rule content
bool getFillRule() const;
void setFillRule(const bool* pFillRule = 0);
const FillRule getFillRule() const;
void setFillRule(const FillRule aFillRule = FillRule_notset) { maFillRule = aFillRule; }
/// fill StrokeDasharray content
const SvgNumberVector& getStrokeDasharray() const;
......
......@@ -52,9 +52,8 @@ namespace svgio
const SvgStyleAttributes* SvgCircleNode::getSvgStyleAttributes() const
{
static rtl::OUString aClassStr(rtl::OUString::createFromAscii("circle"));
maSvgStyleAttributes.checkForCssStyle(aClassStr);
return &maSvgStyleAttributes;
return checkForCssStyle(aClassStr, maSvgStyleAttributes);
}
void SvgCircleNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
......
......@@ -53,9 +53,8 @@ namespace svgio
const SvgStyleAttributes* SvgEllipseNode::getSvgStyleAttributes() const
{
static rtl::OUString aClassStr(rtl::OUString::createFromAscii("ellipse"));
maSvgStyleAttributes.checkForCssStyle(aClassStr);
return &maSvgStyleAttributes;
return checkForCssStyle(aClassStr, maSvgStyleAttributes);
}
void SvgEllipseNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
......
......@@ -51,9 +51,8 @@ namespace svgio
const SvgStyleAttributes* SvgGNode::getSvgStyleAttributes() const
{
static rtl::OUString aClassStr(rtl::OUString::createFromAscii("g"));
maSvgStyleAttributes.checkForCssStyle(aClassStr);
return &maSvgStyleAttributes;
return checkForCssStyle(aClassStr, maSvgStyleAttributes);
}
void SvgGNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
......
......@@ -70,9 +70,8 @@ namespace svgio
const SvgStyleAttributes* SvgImageNode::getSvgStyleAttributes() const
{
static rtl::OUString aClassStr(rtl::OUString::createFromAscii("image"));
maSvgStyleAttributes.checkForCssStyle(aClassStr);
return &maSvgStyleAttributes;
return checkForCssStyle(aClassStr, maSvgStyleAttributes);
}
void SvgImageNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
......
......@@ -53,9 +53,8 @@ namespace svgio
const SvgStyleAttributes* SvgLineNode::getSvgStyleAttributes() const
{
static rtl::OUString aClassStr(rtl::OUString::createFromAscii("line"));
maSvgStyleAttributes.checkForCssStyle(aClassStr);
return &maSvgStyleAttributes;
return checkForCssStyle(aClassStr, maSvgStyleAttributes);
}
void SvgLineNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
......
......@@ -56,9 +56,8 @@ namespace svgio
const SvgStyleAttributes* SvgMarkerNode::getSvgStyleAttributes() const
{
static rtl::OUString aClassStr(rtl::OUString::createFromAscii("marker"));
maSvgStyleAttributes.checkForCssStyle(aClassStr);
return &maSvgStyleAttributes;
return checkForCssStyle(aClassStr, maSvgStyleAttributes);
}
void SvgMarkerNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
......
......@@ -41,6 +41,96 @@ namespace svgio
return 0;
}
const SvgStyleAttributes* SvgNode::checkForCssStyle(const rtl::OUString& rClassStr, const SvgStyleAttributes& rOriginal) const
{
const SvgDocument& rDocument = getDocument();
if(rDocument.hasSvgStyleAttributesById())
{
if(getClass())
{
// find all referenced CSS styles, a list of entries is allowed
const rtl::OUString* pClassList = getClass();
const sal_Int32 nLen(pClassList->getLength());
sal_Int32 nPos(0);
const SvgStyleAttributes* pNew = 0;
skip_char(*pClassList, sal_Unicode(' '), nPos, nLen);
while(nPos < nLen)
{
rtl::OUStringBuffer aTokenValue;
copyToLimiter(*pClassList, sal_Unicode(' '), nPos, aTokenValue, nLen);
skip_char(*pClassList, sal_Unicode(' '), nPos, nLen);
rtl::OUString aId(rtl::OUString::createFromAscii("."));
const rtl::OUString aOUTokenValue(aTokenValue.makeStringAndClear());
// look for CSS style common to token
aId = aId + aOUTokenValue;
pNew = rDocument.findSvgStyleAttributesById(aId);
if(!pNew && rClassStr.getLength())
{
// look for CSS style common to class.token
aId = rClassStr + aId;
pNew = rDocument.findSvgStyleAttributesById(aId);
}
if(pNew)
{
const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew);
}
}
}
if(maCssStyleVector.empty() && getId())
{
// if none found, search for CSS style equal to Id
const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(*getId());
if(pNew)
{
const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew);
}
}
if(maCssStyleVector.empty() && rClassStr.getLength())
{
// if none found, search for CSS style equal to class type
const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(rClassStr);
if(pNew)
{
const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew);
}
}
}
if(maCssStyleVector.empty())
{
return &rOriginal;
}
else
{
// set CssStyleParent at maCssStyleVector members to hang them in front of
// the existing style
SvgStyleAttributes* pCurrent = const_cast< SvgStyleAttributes* >(&rOriginal);
for(sal_uInt32 a(0); a < maCssStyleVector.size(); a++)
{
SvgStyleAttributes* pCandidate = const_cast< SvgStyleAttributes* >(maCssStyleVector[maCssStyleVector.size() - a - 1]);
pCandidate->setCssStyleParent(pCurrent);
pCurrent = pCandidate;
}
return pCurrent;
}
}
SvgNode::SvgNode(
SVGToken aType,
SvgDocument& rDocument,
......@@ -52,7 +142,8 @@ namespace svgio
maChildren(),
mpId(0),
mpClass(0),
maXmlSpace(XmlSpace_notset)
maXmlSpace(XmlSpace_notset),
maCssStyleVector()
{
OSL_ENSURE(SVGTokenUnknown != maType, "SvgNode with unknown type created (!)");
......
......@@ -51,9 +51,8 @@ namespace svgio
const SvgStyleAttributes* SvgPathNode::getSvgStyleAttributes() const
{
static rtl::OUString aClassStr(rtl::OUString::createFromAscii("path"));
maSvgStyleAttributes.checkForCssStyle(aClassStr);
return &maSvgStyleAttributes;
return checkForCssStyle(aClassStr, maSvgStyleAttributes);
}
void SvgPathNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
......
......@@ -70,9 +70,8 @@ namespace svgio
const SvgStyleAttributes* SvgPatternNode::getSvgStyleAttributes() const
{
static rtl::OUString aClassStr(rtl::OUString::createFromAscii("pattern"));
maSvgStyleAttributes.checkForCssStyle(aClassStr);
return &maSvgStyleAttributes;
return checkForCssStyle(aClassStr, maSvgStyleAttributes);
}
void SvgPatternNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
......
......@@ -54,9 +54,8 @@ namespace svgio
{
static rtl::OUString aClassStrA(rtl::OUString::createFromAscii("polygon"));
static rtl::OUString aClassStrB(rtl::OUString::createFromAscii("polyline"));
maSvgStyleAttributes.checkForCssStyle(mbIsPolyline? aClassStrB : aClassStrA);
return &maSvgStyleAttributes;
return checkForCssStyle(mbIsPolyline? aClassStrB : aClassStrA, maSvgStyleAttributes);
}
void SvgPolyNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
......
......@@ -55,9 +55,8 @@ namespace svgio
const SvgStyleAttributes* SvgRectNode::getSvgStyleAttributes() const
{
static rtl::OUString aClassStr(rtl::OUString::createFromAscii("rect"));
maSvgStyleAttributes.checkForCssStyle(aClassStr);
return &maSvgStyleAttributes;
return checkForCssStyle(aClassStr, maSvgStyleAttributes);
}
void SvgRectNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
......
......@@ -212,53 +212,11 @@ namespace svgio
}
}
void SvgStyleAttributes::checkForCssStyle(const rtl::OUString& rClassStr) const
{
if(!mpCssStyleParent)
{
const SvgDocument& rDocument = mrOwner.getDocument();
const SvgStyleAttributes* pNew = 0;
if(rDocument.hasSvgStyleAttributesById())
{
if(mrOwner.getClass())
{
rtl::OUString aId(rtl::OUString::createFromAscii("."));
aId = aId + *mrOwner.getClass();
pNew = rDocument.findSvgStyleAttributesById(aId);
if(!pNew && rClassStr.getLength())
{
aId = rClassStr + aId;
pNew = rDocument.findSvgStyleAttributesById(aId);
}
}
if(!pNew && mrOwner.getId())
{
pNew = rDocument.findSvgStyleAttributesById(*mrOwner.getId());
}
if(!pNew && rClassStr.getLength())
{
pNew = rDocument.findSvgStyleAttributesById(rClassStr);
}
if(pNew)
{
// found css style, set as parent
const_cast< SvgStyleAttributes* >(this)->mpCssStyleParent = pNew;
}
}
}
}
const SvgStyleAttributes* SvgStyleAttributes::getParentStyle() const
{
if(mpCssStyleParent)
if(getCssStyleParent())
{
return mpCssStyleParent;
return getCssStyleParent();
}
if(mrOwner.getParent())
......@@ -1068,8 +1026,8 @@ namespace svgio
{
basegfx::B2DPolyPolygon aPath(rPath);
const bool bNeedToCheckClipRule(SVGTokenPath == mrOwner.getType() || SVGTokenPolygon == mrOwner.getType());
const bool bClipPathIsNonzero(!bIsLine && bNeedToCheckClipRule && mbIsClipPathContent && mbClipRule);
const bool bFillRuleIsNonzero(!bIsLine && bNeedToCheckClipRule && !mbIsClipPathContent && getFillRule());
const bool bClipPathIsNonzero(!bIsLine && bNeedToCheckClipRule && mbIsClipPathContent && FillRule_nonzero == maClipRule);
const bool bFillRuleIsNonzero(!bIsLine && bNeedToCheckClipRule && !mbIsClipPathContent && FillRule_nonzero == getFillRule());
if(bClipPathIsNonzero || bFillRuleIsNonzero)
{
......@@ -1203,10 +1161,9 @@ namespace svgio
mpMarkerMidXLink(0),
maMarkerEndXLink(),
mpMarkerEndXLink(0),
maFillRule(true),
maFillRuleSet(false),
mbIsClipPathContent(SVGTokenClipPathNode == mrOwner.getType()),
mbClipRule(true)
maFillRule(FillRule_notset),
maClipRule(FillRule_nonzero),
mbIsClipPathContent(SVGTokenClipPathNode == mrOwner.getType())
{
if(!mbIsClipPathContent)
{
......@@ -1273,13 +1230,11 @@ namespace svgio
{
if(aContent.match(commonStrings::aStrNonzero))
{
maFillRule = true;
maFillRuleSet = true;
maFillRule = FillRule_nonzero;
}
else if(aContent.match(commonStrings::aStrEvenOdd))
{
maFillRule = false;
maFillRuleSet = true;
maFillRule = FillRule_evenodd;
}
}
break;
......@@ -1790,11 +1745,11 @@ namespace svgio
{
if(aContent.match(commonStrings::aStrNonzero))
{
mbClipRule = true;
maClipRule = FillRule_nonzero;
}
else if(aContent.match(commonStrings::aStrEvenOdd))
{
mbClipRule = false;
maClipRule = FillRule_evenodd;
}
}
break;
......@@ -2048,9 +2003,9 @@ namespace svgio
return SvgNumber(1.0);
}
bool SvgStyleAttributes::getFillRule() const
const FillRule SvgStyleAttributes::getFillRule() const
{
if(maFillRuleSet)
if(FillRule_notset != maFillRule)
{
return maFillRule;
}
......@@ -2063,20 +2018,7 @@ namespace svgio
}
// default is NonZero
return true;
}
void SvgStyleAttributes::setFillRule(const bool* pFillRule)
{
if(pFillRule)
{
maFillRuleSet = true;
maFillRule = *pFillRule;
}
else
{
maFillRuleSet = false;
}
return FillRule_nonzero;
}
const SvgNumberVector& SvgStyleAttributes::getStrokeDasharray() const
......
......@@ -55,9 +55,8 @@ namespace svgio
const SvgStyleAttributes* SvgTextNode::getSvgStyleAttributes() const
{
static rtl::OUString aClassStr(rtl::OUString::createFromAscii("text"));
maSvgStyleAttributes.checkForCssStyle(aClassStr);
return &maSvgStyleAttributes;
return checkForCssStyle(aClassStr, maSvgStyleAttributes);
}
void SvgTextNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
......
......@@ -54,9 +54,8 @@ namespace svgio
const SvgStyleAttributes* SvgUseNode::getSvgStyleAttributes() const
{
static rtl::OUString aClassStr(rtl::OUString::createFromAscii("use"));
maSvgStyleAttributes.checkForCssStyle(aClassStr);
return &maSvgStyleAttributes;
return checkForCssStyle(aClassStr, maSvgStyleAttributes);
}
void SvgUseNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment