svgio/inc/svgio/svgreader/svgdocument.hxx | 4 svgio/inc/svgio/svgreader/svgnode.hxx | 4 svgio/inc/svgio/svgreader/svgstylenode.hxx | 6 svgio/source/svgreader/svgdocument.cxx | 2 svgio/source/svgreader/svgnode.cxx | 188 +++++++++++++++++------------ svgio/source/svgreader/svgstylenode.cxx | 160 +++++++++++++++++------- 6 files changed, 240 insertions(+), 124 deletions(-)
New commits: commit b760428400bbc7ab3db4d5de6239589e79981a06 Author: Armin Le Grand <a...@apache.org> Date: Tue Jul 29 14:36:29 2014 +0000 i125293 More unified (still simple) CssStyles and solvers diff --git a/svgio/inc/svgio/svgreader/svgdocument.hxx b/svgio/inc/svgio/svgreader/svgdocument.hxx index ac23378..9eabedd 100644 --- a/svgio/inc/svgio/svgreader/svgdocument.hxx +++ b/svgio/inc/svgio/svgreader/svgdocument.hxx @@ -71,8 +71,8 @@ namespace svgio void removeSvgStyleAttributesFromMapper(const rtl::OUString& rStr); /// find a style by it's Id - bool hasSvgStyleAttributesById() const { return !maIdStyleTokenMapperList.empty(); } - const SvgStyleAttributes* findSvgStyleAttributesById(const rtl::OUString& rStr) const; + bool hasGlobalCssStyleAttributes() const { return !maIdStyleTokenMapperList.empty(); } + const SvgStyleAttributes* findGlobalCssStyleAttributes(const rtl::OUString& rStr) const; /// data read access const SvgNodeVector& getSvgNodeVector() const { return maNodes; } diff --git a/svgio/inc/svgio/svgreader/svgnode.hxx b/svgio/inc/svgio/svgreader/svgnode.hxx index b3aaf4e..fece050 100644 --- a/svgio/inc/svgio/svgreader/svgnode.hxx +++ b/svgio/inc/svgio/svgreader/svgnode.hxx @@ -129,6 +129,10 @@ namespace svgio /// helper for filling the CssStyle vector once dependent on mbCssStyleVectorBuilt void fillCssStyleVector(const rtl::OUString& rClassStr); + void fillCssStyleVectorUsingHierarchyAndSelectors( + const rtl::OUString& rClassStr, + const SvgNode& rCurrent, + rtl::OUString aConcatenated); public: SvgNode( diff --git a/svgio/inc/svgio/svgreader/svgstylenode.hxx b/svgio/inc/svgio/svgreader/svgstylenode.hxx index 924ef88..e4e7fe7 100644 --- a/svgio/inc/svgio/svgreader/svgstylenode.hxx +++ b/svgio/inc/svgio/svgreader/svgstylenode.hxx @@ -51,7 +51,11 @@ namespace svgio virtual bool supportsParentStyle() const; 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 bool isTextCss() const { return mbTextCss; } diff --git a/svgio/source/svgreader/svgdocument.cxx b/svgio/source/svgreader/svgdocument.cxx index c719dbd..ef4ea12 100644 --- a/svgio/source/svgreader/svgdocument.cxx +++ b/svgio/source/svgreader/svgdocument.cxx @@ -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)); diff --git a/svgio/source/svgreader/svgnode.cxx b/svgio/source/svgreader/svgnode.cxx index cf3f8e0..a631312 100644 --- a/svgio/source/svgreader/svgnode.cxx +++ b/svgio/source/svgreader/svgnode.cxx @@ -47,102 +47,96 @@ namespace svgio 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(); - 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 - rtl::OUString aConcatenatedStyleName; - const SvgNode* pCurrent = this; - const SvgStyleAttributes* pNew = 0; + const rtl::OUString& rId = *rCurrent.getId(); - while(!pNew && pCurrent) + if(rId.getLength()) { - if(pCurrent->getId()) - { - aConcatenatedStyleName = *pCurrent->getId() + aConcatenatedStyleName; - } + const rtl::OUString aNewConcatenated( + rtl::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 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); + const rtl::OUString& rClassList = *rCurrent.getClass(); + const sal_Int32 nLen(rClassList.getLength()); - 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); - 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 rtl::OUString aPart(aToken.makeStringAndClear().trim()); - rtl::OUString aId(rtl::OUString::createFromAscii(".")); - const rtl::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 rtl::OUString aNewConcatenated( + 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) - { - maCssStyleVector.push_back(pNew); + const SvgStyleAttributes* pNew = rDocument.findGlobalCssStyleAttributes(aNewConcatenated); + + if(pNew) + { + // add CssStyle if found + maCssStyleVector.push_back(pNew); + } } } } @@ -150,17 +144,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); + rtl::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 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 { if(!mbCssStyleVectorBuilt) diff --git a/svgio/source/svgreader/svgstylenode.cxx b/svgio/source/svgreader/svgstylenode.cxx index de41886..48482d1 100644 --- a/svgio/source/svgreader/svgstylenode.cxx +++ b/svgio/source/svgreader/svgstylenode.cxx @@ -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()); - - 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< rtl::OUString > aSelectorParts; + const sal_Int32 nLen(aSelectors.getLength()); sal_Int32 nPos(0); - rtl::OUStringBuffer aTokenValue; + rtl::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 rtl::OUString aSelectorPart(aToken.makeStringAndClear().trim()); - const rtl::OUString aStyleName(aTokenValue.makeStringAndClear().trim()); - const sal_Int32 nLen2(aStyleName.getLength()); - std::vector< rtl::OUString > aStyleNames; + if(aSelectorPart.getLength()) + { + aSelectorParts.push_back(aSelectorPart); + } - if(nLen2) + if(nInitPos == nPos) { - // extract names - sal_Int32 nPos2(0); - rtl::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()) + { + rtl::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 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()) - { - aStyleNames.push_back(aOUSingleName); - } - } + void SvgStyleNode::addCssStyleSheet(const rtl::OUString& aSelectors, const rtl::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); + 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); - skip_char(aContent, sal_Unicode(' '), sal_Unicode('}'), nPos, nLen); - const rtl::OUString aStyleContent(aTokenValue.makeStringAndClear().trim()); + OSL_ENSURE(false, "Could not interpret on current position (!)"); + nPos++; + } + } + } + } - if(aStyleContent.getLength()) - { - // create new style - SvgStyleAttributes* pNewStyle = new SvgStyleAttributes(*this); - maSvgStyleAttributes.push_back(pNewStyle); + void SvgStyleNode::addCssStyleSheet(const rtl::OUString& aSelectorsAndContent) + { + const sal_Int32 nLen(aSelectorsAndContent.getLength()); - // fill with content - pNewStyle->readStyle(aStyleContent); + if(nLen) + { + 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 - rtl::OUString aConcatenatedStyleName; + const rtl::OUString aSelectors(aToken.makeStringAndClear().trim()); + rtl::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) _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits