[Libreoffice-commits] core.git: svgio/inc svgio/source

Armin Le Grand alg at apache.org
Thu Aug 7 10:51:15 PDT 2014


 svgio/inc/svgio/svgreader/svgdocument.hxx  |    5 
 svgio/inc/svgio/svgreader/svgnode.hxx      |    4 
 svgio/inc/svgio/svgreader/svgstylenode.hxx |    8 -
 svgio/source/svgreader/svgdocument.cxx     |   10 +
 svgio/source/svgreader/svgnode.cxx         |  188 +++++++++++++++++------------
 svgio/source/svgreader/svgstylenode.cxx    |  160 +++++++++++++++++-------
 6 files changed, 250 insertions(+), 125 deletions(-)

New commits:
commit 2c7d4665a08591aea2cf30d09485ae166d997138
Author: Armin Le Grand <alg at apache.org>
Date:   Tue Jul 29 14:36:29 2014 +0000

    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

diff --git a/svgio/inc/svgio/svgreader/svgdocument.hxx b/svgio/inc/svgio/svgreader/svgdocument.hxx
index e61b291..cbc651b 100644
--- a/svgio/inc/svgio/svgreader/svgdocument.hxx
+++ b/svgio/inc/svgio/svgreader/svgdocument.hxx
@@ -65,10 +65,11 @@ namespace svgio
 
             /// add/remove styles to mapper
             void addSvgStyleAttributesToMapper(const OUString& rStr, const SvgStyleAttributes& rSvgStyleAttributes);
+            void removeSvgStyleAttributesFromMapper(const OUString& rStr);
 
             /// find a style by it's Id
-            bool hasSvgStyleAttributesById() const { return !maIdStyleTokenMapperList.empty(); }
-            const SvgStyleAttributes* findSvgStyleAttributesById(const OUString& rStr) const;
+            bool hasGlobalCssStyleAttributes() const { return !maIdStyleTokenMapperList.empty(); }
+            const SvgStyleAttributes* findGlobalCssStyleAttributes(const 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 4793ddf..9fa9e72 100644
--- a/svgio/inc/svgio/svgreader/svgnode.hxx
+++ b/svgio/inc/svgio/svgreader/svgnode.hxx
@@ -126,6 +126,10 @@ namespace svgio
 
             /// helper for filling the CssStyle vector once dependent on mbCssStyleVectorBuilt
             void fillCssStyleVector(const OUString& rClassStr);
+            void fillCssStyleVectorUsingHierarchyAndSelectors(
+                const OUString& rClassStr,
+                const SvgNode& rCurrent,
+                OUString aConcatenated);
 
         public:
             SvgNode(
diff --git a/svgio/inc/svgio/svgreader/svgstylenode.hxx b/svgio/inc/svgio/svgreader/svgstylenode.hxx
index fc851df..e113ea9 100644
--- a/svgio/inc/svgio/svgreader/svgstylenode.hxx
+++ b/svgio/inc/svgio/svgreader/svgstylenode.hxx
@@ -45,8 +45,12 @@ namespace svgio
             /// #i125258# tell if this node is allowed to have a parent style (e.g. defs do not)
             virtual bool supportsParentStyle() const SAL_OVERRIDE;
 
-            virtual void parseAttribute(const OUString& rTokenName, SVGToken aSVGToken, const OUString& aContent) SAL_OVERRIDE;
-            void addCssStyleSheet(const OUString& aContent);
+            virtual void parseAttribute(const OUString& rTokenName, SVGToken aSVGToken, const OUString& aContent);
+
+            /// CssStyleSheet add helpers
+            void addCssStyleSheet(const OUString& aSelectors, const SvgStyleAttributes& rNewStyle);
+            void addCssStyleSheet(const OUString& aSelectors, const OUString& aContent);
+            void addCssStyleSheet(const OUString& aSelectorsAndContent);
 
             /// textCss access
             bool isTextCss() const { return mbTextCss; }
diff --git a/svgio/source/svgreader/svgdocument.cxx b/svgio/source/svgreader/svgdocument.cxx
index ff95628..6f4e0a5 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 1652a25..d771c51 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 e5b965f..c9c455e 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)


More information about the Libreoffice-commits mailing list