diff options
author | Armin Le Grand <alg@apache.org> | 2014-07-29 14:36:29 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2014-08-07 18:50:44 +0100 |
commit | 2c7d4665a08591aea2cf30d09485ae166d997138 (patch) | |
tree | 527935a8c77b91fdb9d59c3931a9b99840d9e72a /svgio/source | |
parent | 04b02f2f5a4f71198e0cb616404c4721c918afe6 (diff) |
Related: #i125293# More unified (still simple) CssStyles and solvers
(cherry picked from commit b760428400bbc7ab3db4d5de6239589e79981a06)
Conflicts:
svgio/inc/svgio/svgreader/svgdocument.hxx
svgio/inc/svgio/svgreader/svgnode.hxx
svgio/inc/svgio/svgreader/svgstylenode.hxx
svgio/source/svgreader/svgdocument.cxx
svgio/source/svgreader/svgnode.cxx
svgio/source/svgreader/svgstylenode.cxx
Change-Id: Ifcfc665df18f56e2cbc359411b633271c3b8d4bb
Diffstat (limited to 'svgio/source')
-rw-r--r-- | svgio/source/svgreader/svgdocument.cxx | 10 | ||||
-rw-r--r-- | svgio/source/svgreader/svgnode.cxx | 188 | ||||
-rw-r--r-- | svgio/source/svgreader/svgstylenode.cxx | 160 |
3 files changed, 237 insertions, 121 deletions
diff --git a/svgio/source/svgreader/svgdocument.cxx b/svgio/source/svgreader/svgdocument.cxx index ff95628cda79..6f4e0a56746d 100644 --- a/svgio/source/svgreader/svgdocument.cxx +++ b/svgio/source/svgreader/svgdocument.cxx @@ -85,7 +85,15 @@ namespace svgio } } - const SvgStyleAttributes* SvgDocument::findSvgStyleAttributesById(const OUString& rStr) const + void SvgDocument::removeSvgStyleAttributesFromMapper(const OUString& rStr) + { + if(!rStr.isEmpty()) + { + maIdStyleTokenMapperList.erase(rStr); + } + } + + const SvgStyleAttributes* SvgDocument::findGlobalCssStyleAttributes(const OUString& rStr) const { const IdStyleTokenMapper::const_iterator aResult(maIdStyleTokenMapperList.find(rStr)); diff --git a/svgio/source/svgreader/svgnode.cxx b/svgio/source/svgreader/svgnode.cxx index 1652a25ff6f3..d771c5178a86 100644 --- a/svgio/source/svgreader/svgnode.cxx +++ b/svgio/source/svgreader/svgnode.cxx @@ -40,102 +40,96 @@ namespace svgio return 0; } - void SvgNode::fillCssStyleVector(const OUString& rClassStr) + void SvgNode::fillCssStyleVectorUsingHierarchyAndSelectors( + const OUString& rClassStr, + const SvgNode& rCurrent, + 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(); - if(rDocument.hasSvgStyleAttributesById()) + if(rDocument.hasGlobalCssStyleAttributes()) { - // check for 'id' references - if(getId()) + const SvgNode* pParent = rCurrent.getParent(); + + // check for ID (highest priority) + if(rCurrent.getId()) { - // concatenate combined style name during search for CSS style equal to Id - // when travelling over node parents - OUString aConcatenatedStyleName; - const SvgNode* pCurrent = this; - const SvgStyleAttributes* pNew = 0; + const OUString& rId = *rCurrent.getId(); - while(!pNew && pCurrent) + if(rId.getLength()) { - if(pCurrent->getId()) - { - aConcatenatedStyleName = *pCurrent->getId() + aConcatenatedStyleName; - } + const OUString aNewConcatenated( + OUString::createFromAscii("#") + + 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) - { - maCssStyleVector.push_back(pNew); + if(pNew) + { + // add CssStyle if found + maCssStyleVector.push_back(pNew); + } } } - // check for 'class' references - if(getClass()) + // check for 'class' references (a list of entries is allowed) + if(rCurrent.getClass()) { - // find all referenced CSS styles (a list of entries is allowed) - const OUString* pClassList = getClass(); - const sal_Int32 nLen(pClassList->getLength()); - sal_Int32 nPos(0); - const SvgStyleAttributes* pNew = 0; - - skip_char(*pClassList, sal_Unicode(' '), nPos, nLen); + const OUString& rClassList = *rCurrent.getClass(); + const sal_Int32 nLen(rClassList.getLength()); - while(nPos < nLen) + if(nLen) { - OUStringBuffer aTokenValue; + std::vector< OUString > aParts; + sal_Int32 nPos(0); + OUStringBuffer aToken; - copyToLimiter(*pClassList, sal_Unicode(' '), nPos, aTokenValue, nLen); - skip_char(*pClassList, sal_Unicode(' '), nPos, nLen); + while(nPos < nLen) + { + const sal_Int32 nInitPos(nPos); + copyToLimiter(rClassList, sal_Unicode(' '), nPos, aToken, nLen); + skip_char(rClassList, sal_Unicode(' '), nPos, nLen); + const OUString aPart(aToken.makeStringAndClear().trim()); - OUString aId(OUString::createFromAscii(".")); - const OUString aOUTokenValue(aTokenValue.makeStringAndClear()); + if(aPart.getLength()) + { + aParts.push_back(aPart); + } - // look for CSS style common to token - aId = aId + aOUTokenValue; - pNew = rDocument.findSvgStyleAttributesById(aId); + if(nInitPos == nPos) + { + 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 - aId = rClassStr + aId; + const OUString aNewConcatenated( + 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) - { - maCssStyleVector.push_back(pNew); + const SvgStyleAttributes* pNew = rDocument.findGlobalCssStyleAttributes(aNewConcatenated); + + if(pNew) + { + // add CssStyle if found + maCssStyleVector.push_back(pNew); + } } } } @@ -143,17 +137,65 @@ namespace svgio // check for class-dependent references to CssStyles if(rClassStr.getLength()) { - // search for CSS style equal to class type - const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(rClassStr); + OUString aNewConcatenated(aConcatenated); + + 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) { + // add CssStyle if found maCssStyleVector.push_back(pNew); } } } } + void SvgNode::fillCssStyleVector(const OUString& rClassStr) + { + OSL_ENSURE(!mbCssStyleVectorBuilt, "OOps, fillCssStyleVector called double ?!?"); + mbCssStyleVectorBuilt = true; + + // #i125293# 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, OUString()); + } + const SvgStyleAttributes* SvgNode::checkForCssStyle(const OUString& rClassStr, const SvgStyleAttributes& rOriginal) const { if(!mbCssStyleVectorBuilt) diff --git a/svgio/source/svgreader/svgstylenode.cxx b/svgio/source/svgreader/svgstylenode.cxx index e5b965fab705..c9c455e67c1c 100644 --- a/svgio/source/svgreader/svgstylenode.cxx +++ b/svgio/source/svgreader/svgstylenode.cxx @@ -81,74 +81,140 @@ namespace svgio } } - void SvgStyleNode::addCssStyleSheet(const OUString& aContent) + void SvgStyleNode::addCssStyleSheet(const OUString& aSelectors, const SvgStyleAttributes& rNewStyle) { - const sal_Int32 nLen(aContent.getLength()); - - if(nLen) + // aSelectors: CssStyle selectors, any combination, no comma separations, no spaces at start/end + // rNewStyle: the already preapared style to register on that name + if(aSelectors.getLength()) { + std::vector< OUString > aSelectorParts; + const sal_Int32 nLen(aSelectors.getLength()); sal_Int32 nPos(0); - OUStringBuffer aTokenValue; + OUStringBuffer aToken; + // split into single tokens (currently only space separator) while(nPos < nLen) { - // read the full style node names (may be multiple) and put to aStyleName const sal_Int32 nInitPos(nPos); - skip_char(aContent, sal_Unicode(' '), nPos, nLen); - copyToLimiter(aContent, sal_Unicode('{'), nPos, aTokenValue, nLen); - skip_char(aContent, sal_Unicode(' '), sal_Unicode('{'), nPos, nLen); + copyToLimiter(aSelectors, sal_Unicode(' '), nPos, aToken, nLen); + skip_char(aSelectors, sal_Unicode(' '), nPos, nLen); + const OUString aSelectorPart(aToken.makeStringAndClear().trim()); - const OUString aStyleName(aTokenValue.makeStringAndClear().trim()); - const sal_Int32 nLen2(aStyleName.getLength()); - std::vector< OUString > aStyleNames; + if(aSelectorPart.getLength()) + { + aSelectorParts.push_back(aSelectorPart); + } - if(nLen2) + if(nInitPos == nPos) { - // extract names - sal_Int32 nPos2(0); - OUStringBuffer aSingleName; + OSL_ENSURE(false, "Could not interpret on current position (!)"); + nPos++; + } + } - while(nPos2 < nLen2) - { - skip_char(aStyleName, sal_Unicode('#'), nPos2, nLen2); - copyToLimiter(aStyleName, sal_Unicode(' '), nPos2, aSingleName, nLen2); - skip_char(aStyleName, sal_Unicode(' '), nPos2, nLen2); + if(aSelectorParts.size()) + { + OUString aConcatenatedSelector; + + // re-combine without spaces, create a unique name (for now) + for(sal_uInt32 a(0); a < aSelectorParts.size(); a++) + { + aConcatenatedSelector += aSelectorParts[a]; + } - const 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()) - { - aStyleNames.push_back(aOUSingleName); - } - } + void SvgStyleNode::addCssStyleSheet(const OUString& aSelectors, const OUString& aContent) + { + // 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); + 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 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); - skip_char(aContent, sal_Unicode(' '), sal_Unicode('}'), nPos, nLen); - const OUString aStyleContent(aTokenValue.makeStringAndClear().trim()); + OSL_ENSURE(false, "Could not interpret on current position (!)"); + nPos++; + } + } + } + } - if(!aStyleContent.isEmpty()) - { - // create new style - SvgStyleAttributes* pNewStyle = new SvgStyleAttributes(*this); - maSvgStyleAttributes.push_back(pNewStyle); + void SvgStyleNode::addCssStyleSheet(const OUString& aSelectorsAndContent) + { + const sal_Int32 nLen(aSelectorsAndContent.getLength()); - // fill with content - pNewStyle->readStyle(aStyleContent); + if(nLen) + { + sal_Int32 nPos(0); + 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 - OUString aConcatenatedStyleName; + const OUString aSelectors(aToken.makeStringAndClear().trim()); + OUString aContent; - for(sal_uInt32 a(0); a < aStyleNames.size(); a++) - { - aConcatenatedStyleName += aStyleNames[a]; - } + if(aSelectors.getLength() && nPos < nLen) + { + // 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 - const_cast< SvgDocument& >(getDocument()).addSvgStyleAttributesToMapper(aConcatenatedStyleName, *pNewStyle); - } + aContent = aToken.makeStringAndClear().trim(); + } + + if(aSelectors.getLength() && aContent.getLength()) + { + addCssStyleSheet(aSelectors, aContent); } if(nInitPos == nPos) |