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

i125293 More unified (still simple) CssStyles and solvers

üst f00d6d2e
...@@ -71,8 +71,8 @@ namespace svgio ...@@ -71,8 +71,8 @@ namespace svgio
void removeSvgStyleAttributesFromMapper(const rtl::OUString& rStr); void removeSvgStyleAttributesFromMapper(const rtl::OUString& rStr);
/// find a style by it's Id /// find a style by it's Id
bool hasSvgStyleAttributesById() const { return !maIdStyleTokenMapperList.empty(); } bool hasGlobalCssStyleAttributes() const { return !maIdStyleTokenMapperList.empty(); }
const SvgStyleAttributes* findSvgStyleAttributesById(const rtl::OUString& rStr) const; const SvgStyleAttributes* findGlobalCssStyleAttributes(const rtl::OUString& rStr) const;
/// data read access /// data read access
const SvgNodeVector& getSvgNodeVector() const { return maNodes; } const SvgNodeVector& getSvgNodeVector() const { return maNodes; }
......
...@@ -129,6 +129,10 @@ namespace svgio ...@@ -129,6 +129,10 @@ namespace svgio
/// helper for filling the CssStyle vector once dependent on mbCssStyleVectorBuilt /// helper for filling the CssStyle vector once dependent on mbCssStyleVectorBuilt
void fillCssStyleVector(const rtl::OUString& rClassStr); void fillCssStyleVector(const rtl::OUString& rClassStr);
void fillCssStyleVectorUsingHierarchyAndSelectors(
const rtl::OUString& rClassStr,
const SvgNode& rCurrent,
rtl::OUString aConcatenated);
public: public:
SvgNode( SvgNode(
......
...@@ -51,7 +51,11 @@ namespace svgio ...@@ -51,7 +51,11 @@ namespace svgio
virtual bool supportsParentStyle() const; virtual bool supportsParentStyle() const;
virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
void addCssStyleSheet(const rtl::OUString& aContent);
/// CssStyleSheet add helpers
void addCssStyleSheet(const rtl::OUString& aSelectors, const SvgStyleAttributes& rNewStyle);
void addCssStyleSheet(const rtl::OUString& aSelectors, const rtl::OUString& aContent);
void addCssStyleSheet(const rtl::OUString& aSelectorsAndContent);
/// textCss access /// textCss access
bool isTextCss() const { return mbTextCss; } bool isTextCss() const { return mbTextCss; }
......
...@@ -100,7 +100,7 @@ namespace svgio ...@@ -100,7 +100,7 @@ namespace svgio
} }
} }
const SvgStyleAttributes* SvgDocument::findSvgStyleAttributesById(const rtl::OUString& rStr) const const SvgStyleAttributes* SvgDocument::findGlobalCssStyleAttributes(const rtl::OUString& rStr) const
{ {
const IdStyleTokenMapper::const_iterator aResult(maIdStyleTokenMapperList.find(rStr)); const IdStyleTokenMapper::const_iterator aResult(maIdStyleTokenMapperList.find(rStr));
......
...@@ -47,102 +47,96 @@ namespace svgio ...@@ -47,102 +47,96 @@ namespace svgio
return 0; return 0;
} }
void SvgNode::fillCssStyleVector(const rtl::OUString& rClassStr) void SvgNode::fillCssStyleVectorUsingHierarchyAndSelectors(
const rtl::OUString& rClassStr,
const SvgNode& rCurrent,
rtl::OUString aConcatenated)
{ {
OSL_ENSURE(!mbCssStyleVectorBuilt, "OOps, fillCssStyleVector called double ?!?");
mbCssStyleVectorBuilt = true;
// #125293# If we have CssStyles we need to buuild a linked list of SvgStyleAttributes
// which represent this for the current object. There are various methods to
// specify CssStyles which need to be taken into account in a given order:
// - local CssStyle (independent from global CssStyles at SvgDocument)
// - 'id' CssStyle
// - 'class' CssStyle(s)
// - type-dependent elements (e..g. 'rect' for all rect elements)
// - local attributes (rOriginal)
// - inherited attributes (up the hierarchy)
// The first four will be collected in maCssStyleVector for the current element
// (once, this will not change) and be linked in the needed order using the
// get/setCssStyleParent at the SvgStyleAttributes which will be used preferred in
// member evaluation over the existing parent hierarchy
// check for local CssStyle with highest priority
if(mpLocalCssStyle)
{
// if we have one, use as first entry
maCssStyleVector.push_back(mpLocalCssStyle);
}
const SvgDocument& rDocument = getDocument(); const SvgDocument& rDocument = getDocument();
if(rDocument.hasSvgStyleAttributesById()) if(rDocument.hasGlobalCssStyleAttributes())
{ {
// check for 'id' references const SvgNode* pParent = rCurrent.getParent();
if(getId())
// check for ID (highest priority)
if(rCurrent.getId())
{ {
// concatenate combined style name during search for CSS style equal to Id const rtl::OUString& rId = *rCurrent.getId();
// when travelling over node parents
rtl::OUString aConcatenatedStyleName;
const SvgNode* pCurrent = this;
const SvgStyleAttributes* pNew = 0;
while(!pNew && pCurrent) if(rId.getLength())
{ {
if(pCurrent->getId()) const rtl::OUString aNewConcatenated(
{ rtl::OUString::createFromAscii("#") +
aConcatenatedStyleName = *pCurrent->getId() + aConcatenatedStyleName; rId +
} aConcatenated);
if(aConcatenatedStyleName.getLength()) if(pParent)
{ {
pNew = rDocument.findSvgStyleAttributesById(aConcatenatedStyleName); // check for combined selectors at parent firstso that higher specificity will be in front
fillCssStyleVectorUsingHierarchyAndSelectors(rClassStr, *pParent, aNewConcatenated);
} }
pCurrent = pCurrent->getParent(); const SvgStyleAttributes* pNew = rDocument.findGlobalCssStyleAttributes(aNewConcatenated);
}
if(pNew) if(pNew)
{ {
maCssStyleVector.push_back(pNew); // add CssStyle if found
maCssStyleVector.push_back(pNew);
}
} }
} }
// check for 'class' references // check for 'class' references (a list of entries is allowed)
if(getClass()) if(rCurrent.getClass())
{ {
// find all referenced CSS styles (a list of entries is allowed) const rtl::OUString& rClassList = *rCurrent.getClass();
const rtl::OUString* pClassList = getClass(); const sal_Int32 nLen(rClassList.getLength());
const sal_Int32 nLen(pClassList->getLength());
sal_Int32 nPos(0);
const SvgStyleAttributes* pNew = 0;
skip_char(*pClassList, sal_Unicode(' '), nPos, nLen);
while(nPos < nLen) if(nLen)
{ {
rtl::OUStringBuffer aTokenValue; std::vector< rtl::OUString > aParts;
sal_Int32 nPos(0);
rtl::OUStringBuffer aToken;
copyToLimiter(*pClassList, sal_Unicode(' '), nPos, aTokenValue, nLen); while(nPos < nLen)
skip_char(*pClassList, sal_Unicode(' '), nPos, nLen); {
const sal_Int32 nInitPos(nPos);
copyToLimiter(rClassList, sal_Unicode(' '), nPos, aToken, nLen);
skip_char(rClassList, sal_Unicode(' '), nPos, nLen);
const rtl::OUString aPart(aToken.makeStringAndClear().trim());
rtl::OUString aId(rtl::OUString::createFromAscii(".")); if(aPart.getLength())
const rtl::OUString aOUTokenValue(aTokenValue.makeStringAndClear()); {
aParts.push_back(aPart);
}
// look for CSS style common to token if(nInitPos == nPos)
aId = aId + aOUTokenValue; {
pNew = rDocument.findSvgStyleAttributesById(aId); OSL_ENSURE(false, "Could not interpret on current position (!)");
nPos++;
}
}
if(!pNew && rClassStr.getLength()) for(sal_uInt32 a(0); a < aParts.size(); a++)
{ {
// look for CSS style common to class.token const rtl::OUString aNewConcatenated(
aId = rClassStr + aId; rtl::OUString::createFromAscii(".") +
aParts[a] +
aConcatenated);
pNew = rDocument.findSvgStyleAttributesById(aId); if(pParent)
} {
// check for combined selectors at parent firstso that higher specificity will be in front
fillCssStyleVectorUsingHierarchyAndSelectors(rClassStr, *pParent, aNewConcatenated);
}
if(pNew) const SvgStyleAttributes* pNew = rDocument.findGlobalCssStyleAttributes(aNewConcatenated);
{
maCssStyleVector.push_back(pNew); if(pNew)
{
// add CssStyle if found
maCssStyleVector.push_back(pNew);
}
} }
} }
} }
...@@ -150,17 +144,65 @@ namespace svgio ...@@ -150,17 +144,65 @@ namespace svgio
// check for class-dependent references to CssStyles // check for class-dependent references to CssStyles
if(rClassStr.getLength()) if(rClassStr.getLength())
{ {
// search for CSS style equal to class type rtl::OUString aNewConcatenated(aConcatenated);
const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(rClassStr);
if(!rCurrent.getId() && !rCurrent.getClass() && 0 == aConcatenated.indexOf(rClassStr))
{
// no new CssStyle Selector and already starts with rClassStr, do not concatenate;
// we pass an 'empty' node (in the sense of CssStyle Selector)
}
else
{
aNewConcatenated = rClassStr + aConcatenated;
}
if(pParent)
{
// check for combined selectors at parent firstso that higher specificity will be in front
fillCssStyleVectorUsingHierarchyAndSelectors(rClassStr, *pParent, aNewConcatenated);
}
const SvgStyleAttributes* pNew = rDocument.findGlobalCssStyleAttributes(aNewConcatenated);
if(pNew) if(pNew)
{ {
// add CssStyle if found
maCssStyleVector.push_back(pNew); maCssStyleVector.push_back(pNew);
} }
} }
} }
} }
void SvgNode::fillCssStyleVector(const rtl::OUString& rClassStr)
{
OSL_ENSURE(!mbCssStyleVectorBuilt, "OOps, fillCssStyleVector called double ?!?");
mbCssStyleVectorBuilt = true;
// #125293# If we have CssStyles we need to buuild a linked list of SvgStyleAttributes
// which represent this for the current object. There are various methods to
// specify CssStyles which need to be taken into account in a given order:
// - local CssStyle (independent from global CssStyles at SvgDocument)
// - 'id' CssStyle
// - 'class' CssStyle(s)
// - type-dependent elements (e..g. 'rect' for all rect elements)
// - local attributes (rOriginal)
// - inherited attributes (up the hierarchy)
// The first four will be collected in maCssStyleVector for the current element
// (once, this will not change) and be linked in the needed order using the
// get/setCssStyleParent at the SvgStyleAttributes which will be used preferred in
// member evaluation over the existing parent hierarchy
// check for local CssStyle with highest priority
if(mpLocalCssStyle)
{
// if we have one, use as first entry
maCssStyleVector.push_back(mpLocalCssStyle);
}
// check the hierarchy for concatenated patterns of Selectors
fillCssStyleVectorUsingHierarchyAndSelectors(rClassStr, *this, rtl::OUString());
}
const SvgStyleAttributes* SvgNode::checkForCssStyle(const rtl::OUString& rClassStr, const SvgStyleAttributes& rOriginal) const const SvgStyleAttributes* SvgNode::checkForCssStyle(const rtl::OUString& rClassStr, const SvgStyleAttributes& rOriginal) const
{ {
if(!mbCssStyleVectorBuilt) if(!mbCssStyleVectorBuilt)
......
...@@ -90,74 +90,140 @@ namespace svgio ...@@ -90,74 +90,140 @@ namespace svgio
} }
} }
void SvgStyleNode::addCssStyleSheet(const rtl::OUString& aContent) void SvgStyleNode::addCssStyleSheet(const rtl::OUString& aSelectors, const SvgStyleAttributes& rNewStyle)
{ {
const sal_Int32 nLen(aContent.getLength()); // aSelectors: CssStyle selectors, any combination, no comma separations, no spaces at start/end
// rNewStyle: the already preapared style to register on that name
if(nLen) if(aSelectors.getLength())
{ {
std::vector< rtl::OUString > aSelectorParts;
const sal_Int32 nLen(aSelectors.getLength());
sal_Int32 nPos(0); sal_Int32 nPos(0);
rtl::OUStringBuffer aTokenValue; rtl::OUStringBuffer aToken;
// split into single tokens (currently only space separator)
while(nPos < nLen) while(nPos < nLen)
{ {
// read the full style node names (may be multiple) and put to aStyleName
const sal_Int32 nInitPos(nPos); const sal_Int32 nInitPos(nPos);
skip_char(aContent, sal_Unicode(' '), nPos, nLen); copyToLimiter(aSelectors, sal_Unicode(' '), nPos, aToken, nLen);
copyToLimiter(aContent, sal_Unicode('{'), nPos, aTokenValue, nLen); skip_char(aSelectors, sal_Unicode(' '), nPos, nLen);
skip_char(aContent, sal_Unicode(' '), sal_Unicode('{'), nPos, nLen); const rtl::OUString aSelectorPart(aToken.makeStringAndClear().trim());
const rtl::OUString aStyleName(aTokenValue.makeStringAndClear().trim()); if(aSelectorPart.getLength())
const sal_Int32 nLen2(aStyleName.getLength()); {
std::vector< rtl::OUString > aStyleNames; aSelectorParts.push_back(aSelectorPart);
}
if(nLen2) if(nInitPos == nPos)
{ {
// extract names OSL_ENSURE(false, "Could not interpret on current position (!)");
sal_Int32 nPos2(0); nPos++;
rtl::OUStringBuffer aSingleName; }
}
while(nPos2 < nLen2) if(aSelectorParts.size())
{ {
skip_char(aStyleName, sal_Unicode('#'), nPos2, nLen2); rtl::OUString aConcatenatedSelector;
copyToLimiter(aStyleName, sal_Unicode(' '), nPos2, aSingleName, nLen2);
skip_char(aStyleName, sal_Unicode(' '), nPos2, nLen2); // re-combine without spaces, create a unique name (for now)
for(sal_uInt32 a(0); a < aSelectorParts.size(); a++)
{
aConcatenatedSelector += aSelectorParts[a];
}
const rtl::OUString aOUSingleName(aSingleName.makeStringAndClear().trim()); // CssStyles in SVG are currently not completely supported; the current idea for
// supporting the needed minimal set is to register CssStyles associated to a string
// which is just the space-char cleaned, concatenated Selectors. The part to 'match'
// these is in fillCssStyleVectorUsingHierarchyAndSelectors. There, the same string is
// built up using the priorities of local CssStyle, Id, Class and other info combined
// with the existing hierarchy. This creates a specificity- and priority-sorted local
// list for each node which is then chained using get/setCssStyleParent.
// The current solution is capable of solving space-separated selectors which can be
// mixed between Id, Class and type specifiers.
// When CssStyles need more specific solving, the start point is here; remember the
// needed infos not in maIdStyleTokenMapperList at the document, but select evtl.
// more specific infos there in a class capable of handling more complex matchings.
// Additionally fillCssStyleVector (or the mechanism above that when a linked list of
// SvgStyleAttributes will not do it) will have to be adapted to make use of it.
// register new style at document for (evtl. concatenated) stylename
const_cast< SvgDocument& >(getDocument()).addSvgStyleAttributesToMapper(aConcatenatedSelector, rNewStyle);
}
}
}
if(aOUSingleName.getLength()) void SvgStyleNode::addCssStyleSheet(const rtl::OUString& aSelectors, const rtl::OUString& aContent)
{ {
aStyleNames.push_back(aOUSingleName); // aSelectors: possible comma-separated list of CssStyle definitions, no spaces at start/end
} // aContent: the svg style definitions as string
} if(aSelectors.getLength() && aContent.getLength())
{
// create new style and add to local list (for ownership control)
SvgStyleAttributes* pNewStyle = new SvgStyleAttributes(*this);
maSvgStyleAttributes.push_back(pNewStyle);
// fill with content
pNewStyle->readStyle(aContent);
// comma-separated split (Css abbreviation for same style for multiple selectors)
const sal_Int32 nLen(aSelectors.getLength());
sal_Int32 nPos(0);
rtl::OUStringBuffer aToken;
while(nPos < nLen)
{
const sal_Int32 nInitPos(nPos);
copyToLimiter(aSelectors, sal_Unicode(','), nPos, aToken, nLen);
skip_char(aSelectors, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
const rtl::OUString aSingleName(aToken.makeStringAndClear().trim());
if(aSingleName.getLength())
{
addCssStyleSheet(aSingleName, *pNewStyle);
} }
if(aStyleNames.size() && nPos < nLen) if(nInitPos == nPos)
{ {
copyToLimiter(aContent, sal_Unicode('}'), nPos, aTokenValue, nLen); OSL_ENSURE(false, "Could not interpret on current position (!)");
skip_char(aContent, sal_Unicode(' '), sal_Unicode('}'), nPos, nLen); nPos++;
const rtl::OUString aStyleContent(aTokenValue.makeStringAndClear().trim()); }
}
}
}
if(aStyleContent.getLength()) void SvgStyleNode::addCssStyleSheet(const rtl::OUString& aSelectorsAndContent)
{ {
// create new style const sal_Int32 nLen(aSelectorsAndContent.getLength());
SvgStyleAttributes* pNewStyle = new SvgStyleAttributes(*this);
maSvgStyleAttributes.push_back(pNewStyle);
// fill with content if(nLen)
pNewStyle->readStyle(aStyleContent); {
sal_Int32 nPos(0);
rtl::OUStringBuffer aToken;
while(nPos < nLen)
{
// read the full selectors (may be multiple, comma-separated)
const sal_Int32 nInitPos(nPos);
skip_char(aSelectorsAndContent, sal_Unicode(' '), nPos, nLen);
copyToLimiter(aSelectorsAndContent, sal_Unicode('{'), nPos, aToken, nLen);
skip_char(aSelectorsAndContent, sal_Unicode(' '), sal_Unicode('{'), nPos, nLen);
// concatenate combined style name const rtl::OUString aSelectors(aToken.makeStringAndClear().trim());
rtl::OUString aConcatenatedStyleName; rtl::OUString aContent;
for(sal_uInt32 a(0); a < aStyleNames.size(); a++) if(aSelectors.getLength() && nPos < nLen)
{ {
aConcatenatedStyleName += aStyleNames[a]; // isolate content as text, embraced by '{' and '}'
} copyToLimiter(aSelectorsAndContent, sal_Unicode('}'), nPos, aToken, nLen);
skip_char(aSelectorsAndContent, sal_Unicode(' '), sal_Unicode('}'), nPos, nLen);
// register new style at document for (evtl. concatenated) stylename aContent = aToken.makeStringAndClear().trim();
const_cast< SvgDocument& >(getDocument()).addSvgStyleAttributesToMapper(aConcatenatedStyleName, *pNewStyle); }
}
if(aSelectors.getLength() && aContent.getLength())
{
addCssStyleSheet(aSelectors, aContent);
} }
if(nInitPos == nPos) if(nInitPos == nPos)
......
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