1ddde725dSArmin Le Grand /**************************************************************
2ddde725dSArmin Le Grand  *
3ddde725dSArmin Le Grand  * Licensed to the Apache Software Foundation (ASF) under one
4ddde725dSArmin Le Grand  * or more contributor license agreements.  See the NOTICE file
5ddde725dSArmin Le Grand  * distributed with this work for additional information
6ddde725dSArmin Le Grand  * regarding copyright ownership.  The ASF licenses this file
7ddde725dSArmin Le Grand  * to you under the Apache License, Version 2.0 (the
8ddde725dSArmin Le Grand  * "License"); you may not use this file except in compliance
9ddde725dSArmin Le Grand  * with the License.  You may obtain a copy of the License at
10ddde725dSArmin Le Grand  *
11ddde725dSArmin Le Grand  *   http://www.apache.org/licenses/LICENSE-2.0
12ddde725dSArmin Le Grand  *
13ddde725dSArmin Le Grand  * Unless required by applicable law or agreed to in writing,
14ddde725dSArmin Le Grand  * software distributed under the License is distributed on an
15ddde725dSArmin Le Grand  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16ddde725dSArmin Le Grand  * KIND, either express or implied.  See the License for the
17ddde725dSArmin Le Grand  * specific language governing permissions and limitations
18ddde725dSArmin Le Grand  * under the License.
19ddde725dSArmin Le Grand  *
20ddde725dSArmin Le Grand  *************************************************************/
21ddde725dSArmin Le Grand 
22ddde725dSArmin Le Grand // MARKER(update_precomp.py): autogen include statement, do not remove
23ddde725dSArmin Le Grand #include "precompiled_svgio.hxx"
24ddde725dSArmin Le Grand 
25ddde725dSArmin Le Grand #include <svgio/svgreader/svgstylenode.hxx>
26ddde725dSArmin Le Grand #include <svgio/svgreader/svgdocument.hxx>
27ddde725dSArmin Le Grand 
28ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
29ddde725dSArmin Le Grand 
30ddde725dSArmin Le Grand namespace svgio
31ddde725dSArmin Le Grand {
32ddde725dSArmin Le Grand     namespace svgreader
33ddde725dSArmin Le Grand     {
34ddde725dSArmin Le Grand         SvgStyleNode::SvgStyleNode(
35ddde725dSArmin Le Grand             SvgDocument& rDocument,
36ddde725dSArmin Le Grand             SvgNode* pParent)
37ddde725dSArmin Le Grand         :   SvgNode(SVGTokenStyle, rDocument, pParent),
38ddde725dSArmin Le Grand             maSvgStyleAttributes(),
39ddde725dSArmin Le Grand             mbTextCss(false)
40ddde725dSArmin Le Grand         {
41ddde725dSArmin Le Grand         }
42ddde725dSArmin Le Grand 
43ddde725dSArmin Le Grand         SvgStyleNode::~SvgStyleNode()
44ddde725dSArmin Le Grand         {
45ddde725dSArmin Le Grand             while(!maSvgStyleAttributes.empty())
46ddde725dSArmin Le Grand             {
47ddde725dSArmin Le Grand                 delete *(maSvgStyleAttributes.end() - 1);
48ddde725dSArmin Le Grand                 maSvgStyleAttributes.pop_back();
49ddde725dSArmin Le Grand             }
50ddde725dSArmin Le Grand         }
51ddde725dSArmin Le Grand 
524374d266SArmin Le Grand         // #125258# no parent when we are a CssStyle holder to break potential loops because
534374d266SArmin Le Grand         // when using CssStyles we jump uncontrolled inside the node tree hierarchy
544374d266SArmin Le Grand         bool SvgStyleNode::supportsParentStyle() const
554374d266SArmin Le Grand         {
564374d266SArmin Le Grand             if(isTextCss())
574374d266SArmin Le Grand             {
584374d266SArmin Le Grand                 return false;
594374d266SArmin Le Grand             }
604374d266SArmin Le Grand 
614374d266SArmin Le Grand             // call parent
624374d266SArmin Le Grand             return SvgNode::supportsParentStyle();
634374d266SArmin Le Grand         }
644374d266SArmin Le Grand 
65ddde725dSArmin Le Grand         void SvgStyleNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
66ddde725dSArmin Le Grand         {
67ddde725dSArmin Le Grand             // call parent
68ddde725dSArmin Le Grand             SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
69ddde725dSArmin Le Grand 
70ddde725dSArmin Le Grand             // parse own
71ddde725dSArmin Le Grand             switch(aSVGToken)
72ddde725dSArmin Le Grand             {
73ddde725dSArmin Le Grand                 case SVGTokenType:
74ddde725dSArmin Le Grand                 {
75ddde725dSArmin Le Grand                     if(aContent.getLength())
76ddde725dSArmin Le Grand                     {
77ddde725dSArmin Le Grand                         static rtl::OUString aStrTextCss(rtl::OUString::createFromAscii("text/css"));
78ddde725dSArmin Le Grand 
79ddde725dSArmin Le Grand                         if(aContent.match(aStrTextCss))
80ddde725dSArmin Le Grand                         {
81ddde725dSArmin Le Grand                             setTextCss(true);
82ddde725dSArmin Le Grand                         }
83ddde725dSArmin Le Grand                     }
84ddde725dSArmin Le Grand                     break;
85ddde725dSArmin Le Grand                 }
86e2bf1e9dSArmin Le Grand                 default:
87e2bf1e9dSArmin Le Grand                 {
88e2bf1e9dSArmin Le Grand                     break;
89e2bf1e9dSArmin Le Grand                 }
90ddde725dSArmin Le Grand             }
91ddde725dSArmin Le Grand         }
92ddde725dSArmin Le Grand 
93*eb82bfcdSArmin Le Grand         void SvgStyleNode::addCssStyleSheet(const rtl::OUString& aSelectors, const SvgStyleAttributes& rNewStyle)
94ddde725dSArmin Le Grand         {
95*eb82bfcdSArmin Le Grand             // aSelectors: CssStyle selectors, any combination, no comma separations, no spaces at start/end
96*eb82bfcdSArmin Le Grand             // rNewStyle: the already preapared style to register on that name
97*eb82bfcdSArmin Le Grand             if(aSelectors.getLength())
98ddde725dSArmin Le Grand             {
99*eb82bfcdSArmin Le Grand                 std::vector< rtl::OUString > aSelectorParts;
100*eb82bfcdSArmin Le Grand                 const sal_Int32 nLen(aSelectors.getLength());
101ddde725dSArmin Le Grand                 sal_Int32 nPos(0);
102*eb82bfcdSArmin Le Grand                 rtl::OUStringBuffer aToken;
103ddde725dSArmin Le Grand 
104*eb82bfcdSArmin Le Grand                 // split into single tokens (currently only space separator)
105311ea6abSArmin Le Grand                 while(nPos < nLen)
106ddde725dSArmin Le Grand                 {
107311ea6abSArmin Le Grand                     const sal_Int32 nInitPos(nPos);
108*eb82bfcdSArmin Le Grand                     copyToLimiter(aSelectors, sal_Unicode(' '), nPos, aToken, nLen);
109*eb82bfcdSArmin Le Grand                     skip_char(aSelectors, sal_Unicode(' '), nPos, nLen);
110*eb82bfcdSArmin Le Grand                     const rtl::OUString aSelectorPart(aToken.makeStringAndClear().trim());
111ddde725dSArmin Le Grand 
112*eb82bfcdSArmin Le Grand                     if(aSelectorPart.getLength())
113*eb82bfcdSArmin Le Grand                     {
114*eb82bfcdSArmin Le Grand                         aSelectorParts.push_back(aSelectorPart);
115*eb82bfcdSArmin Le Grand                     }
1169d01bcdeSArmin Le Grand 
117*eb82bfcdSArmin Le Grand                     if(nInitPos == nPos)
1189d01bcdeSArmin Le Grand                     {
119*eb82bfcdSArmin Le Grand                         OSL_ENSURE(false, "Could not interpret on current position (!)");
120*eb82bfcdSArmin Le Grand                         nPos++;
121*eb82bfcdSArmin Le Grand                     }
122*eb82bfcdSArmin Le Grand                 }
1239d01bcdeSArmin Le Grand 
124*eb82bfcdSArmin Le Grand                 if(aSelectorParts.size())
125*eb82bfcdSArmin Le Grand                 {
126*eb82bfcdSArmin Le Grand                     rtl::OUString aConcatenatedSelector;
127*eb82bfcdSArmin Le Grand 
128*eb82bfcdSArmin Le Grand                     // re-combine without spaces, create a unique name (for now)
129*eb82bfcdSArmin Le Grand                     for(sal_uInt32 a(0); a < aSelectorParts.size(); a++)
130*eb82bfcdSArmin Le Grand                     {
131*eb82bfcdSArmin Le Grand                         aConcatenatedSelector += aSelectorParts[a];
132*eb82bfcdSArmin Le Grand                     }
1339d01bcdeSArmin Le Grand 
134*eb82bfcdSArmin Le Grand                     // CssStyles in SVG are currently not completely supported; the current idea for
135*eb82bfcdSArmin Le Grand                     // supporting the needed minimal set is to register CssStyles associated to a string
136*eb82bfcdSArmin Le Grand                     // which is just the space-char cleaned, concatenated Selectors. The part to 'match'
137*eb82bfcdSArmin Le Grand                     // these is in fillCssStyleVectorUsingHierarchyAndSelectors. There, the same string is
138*eb82bfcdSArmin Le Grand                     // built up using the priorities of local CssStyle, Id, Class and other info combined
139*eb82bfcdSArmin Le Grand                     // with the existing hierarchy. This creates a specificity- and priority-sorted local
140*eb82bfcdSArmin Le Grand                     // list for each node which is then chained using get/setCssStyleParent.
141*eb82bfcdSArmin Le Grand                     // The current solution is capable of solving space-separated selectors which can be
142*eb82bfcdSArmin Le Grand                     // mixed between Id, Class and type specifiers.
143*eb82bfcdSArmin Le Grand                     // When CssStyles need more specific solving, the start point is here; remember the
144*eb82bfcdSArmin Le Grand                     // needed infos not in maIdStyleTokenMapperList at the document, but select evtl.
145*eb82bfcdSArmin Le Grand                     // more specific infos there in a class capable of handling more complex matchings.
146*eb82bfcdSArmin Le Grand                     // Additionally fillCssStyleVector (or the mechanism above that when a linked list of
147*eb82bfcdSArmin Le Grand                     // SvgStyleAttributes will not do it) will have to be adapted to make use of it.
148*eb82bfcdSArmin Le Grand 
149*eb82bfcdSArmin Le Grand                     // register new style at document for (evtl. concatenated) stylename
150*eb82bfcdSArmin Le Grand                     const_cast< SvgDocument& >(getDocument()).addSvgStyleAttributesToMapper(aConcatenatedSelector, rNewStyle);
151*eb82bfcdSArmin Le Grand                 }
152*eb82bfcdSArmin Le Grand             }
153*eb82bfcdSArmin Le Grand         }
1549d01bcdeSArmin Le Grand 
155*eb82bfcdSArmin Le Grand         void SvgStyleNode::addCssStyleSheet(const rtl::OUString& aSelectors, const rtl::OUString& aContent)
156*eb82bfcdSArmin Le Grand         {
157*eb82bfcdSArmin Le Grand             // aSelectors: possible comma-separated list of CssStyle definitions, no spaces at start/end
158*eb82bfcdSArmin Le Grand             // aContent: the svg style definitions as string
159*eb82bfcdSArmin Le Grand             if(aSelectors.getLength() && aContent.getLength())
160*eb82bfcdSArmin Le Grand             {
161*eb82bfcdSArmin Le Grand                 // create new style and add to local list (for ownership control)
162*eb82bfcdSArmin Le Grand                 SvgStyleAttributes* pNewStyle = new SvgStyleAttributes(*this);
163*eb82bfcdSArmin Le Grand                 maSvgStyleAttributes.push_back(pNewStyle);
164*eb82bfcdSArmin Le Grand 
165*eb82bfcdSArmin Le Grand                 // fill with content
166*eb82bfcdSArmin Le Grand                 pNewStyle->readStyle(aContent);
167*eb82bfcdSArmin Le Grand 
168*eb82bfcdSArmin Le Grand                 // comma-separated split (Css abbreviation for same style for multiple selectors)
169*eb82bfcdSArmin Le Grand                 const sal_Int32 nLen(aSelectors.getLength());
170*eb82bfcdSArmin Le Grand                 sal_Int32 nPos(0);
171*eb82bfcdSArmin Le Grand                 rtl::OUStringBuffer aToken;
172*eb82bfcdSArmin Le Grand 
173*eb82bfcdSArmin Le Grand                 while(nPos < nLen)
174*eb82bfcdSArmin Le Grand                 {
175*eb82bfcdSArmin Le Grand                     const sal_Int32 nInitPos(nPos);
176*eb82bfcdSArmin Le Grand                     copyToLimiter(aSelectors, sal_Unicode(','), nPos, aToken, nLen);
177*eb82bfcdSArmin Le Grand                     skip_char(aSelectors, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
178*eb82bfcdSArmin Le Grand 
179*eb82bfcdSArmin Le Grand                     const rtl::OUString aSingleName(aToken.makeStringAndClear().trim());
180*eb82bfcdSArmin Le Grand 
181*eb82bfcdSArmin Le Grand                     if(aSingleName.getLength())
182*eb82bfcdSArmin Le Grand                     {
183*eb82bfcdSArmin Le Grand                         addCssStyleSheet(aSingleName, *pNewStyle);
1849d01bcdeSArmin Le Grand                     }
1859d01bcdeSArmin Le Grand 
186*eb82bfcdSArmin Le Grand                     if(nInitPos == nPos)
187ddde725dSArmin Le Grand                     {
188*eb82bfcdSArmin Le Grand                         OSL_ENSURE(false, "Could not interpret on current position (!)");
189*eb82bfcdSArmin Le Grand                         nPos++;
190*eb82bfcdSArmin Le Grand                     }
191*eb82bfcdSArmin Le Grand                 }
192*eb82bfcdSArmin Le Grand             }
193*eb82bfcdSArmin Le Grand         }
194311ea6abSArmin Le Grand 
195*eb82bfcdSArmin Le Grand         void SvgStyleNode::addCssStyleSheet(const rtl::OUString& aSelectorsAndContent)
196*eb82bfcdSArmin Le Grand         {
197*eb82bfcdSArmin Le Grand             const sal_Int32 nLen(aSelectorsAndContent.getLength());
198ddde725dSArmin Le Grand 
199*eb82bfcdSArmin Le Grand             if(nLen)
200*eb82bfcdSArmin Le Grand             {
201*eb82bfcdSArmin Le Grand                 sal_Int32 nPos(0);
202*eb82bfcdSArmin Le Grand                 rtl::OUStringBuffer aToken;
203*eb82bfcdSArmin Le Grand 
204*eb82bfcdSArmin Le Grand                 while(nPos < nLen)
205*eb82bfcdSArmin Le Grand                 {
206*eb82bfcdSArmin Le Grand                     // read the full selectors (may be multiple, comma-separated)
207*eb82bfcdSArmin Le Grand                     const sal_Int32 nInitPos(nPos);
208*eb82bfcdSArmin Le Grand                     skip_char(aSelectorsAndContent, sal_Unicode(' '), nPos, nLen);
209*eb82bfcdSArmin Le Grand                     copyToLimiter(aSelectorsAndContent, sal_Unicode('{'), nPos, aToken, nLen);
210*eb82bfcdSArmin Le Grand                     skip_char(aSelectorsAndContent, sal_Unicode(' '), sal_Unicode('{'), nPos, nLen);
211ddde725dSArmin Le Grand 
212*eb82bfcdSArmin Le Grand                     const rtl::OUString aSelectors(aToken.makeStringAndClear().trim());
213*eb82bfcdSArmin Le Grand                     rtl::OUString aContent;
2149d01bcdeSArmin Le Grand 
215*eb82bfcdSArmin Le Grand                     if(aSelectors.getLength() && nPos < nLen)
216*eb82bfcdSArmin Le Grand                     {
217*eb82bfcdSArmin Le Grand                         // isolate content as text, embraced by '{' and '}'
218*eb82bfcdSArmin Le Grand                         copyToLimiter(aSelectorsAndContent, sal_Unicode('}'), nPos, aToken, nLen);
219*eb82bfcdSArmin Le Grand                         skip_char(aSelectorsAndContent, sal_Unicode(' '), sal_Unicode('}'), nPos, nLen);
2209d01bcdeSArmin Le Grand 
221*eb82bfcdSArmin Le Grand                         aContent = aToken.makeStringAndClear().trim();
222*eb82bfcdSArmin Le Grand                     }
223*eb82bfcdSArmin Le Grand 
224*eb82bfcdSArmin Le Grand                     if(aSelectors.getLength() && aContent.getLength())
225*eb82bfcdSArmin Le Grand                     {
226*eb82bfcdSArmin Le Grand                         addCssStyleSheet(aSelectors, aContent);
227311ea6abSArmin Le Grand                     }
228311ea6abSArmin Le Grand 
229311ea6abSArmin Le Grand                     if(nInitPos == nPos)
230311ea6abSArmin Le Grand                     {
231311ea6abSArmin Le Grand                         OSL_ENSURE(false, "Could not interpret on current position (!)");
232311ea6abSArmin Le Grand                         nPos++;
233ddde725dSArmin Le Grand                     }
234ddde725dSArmin Le Grand                 }
235ddde725dSArmin Le Grand             }
236ddde725dSArmin Le Grand         }
237ddde725dSArmin Le Grand 
238ddde725dSArmin Le Grand     } // end of namespace svgreader
239ddde725dSArmin Le Grand } // end of namespace svgio
240ddde725dSArmin Le Grand 
241ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
242ddde725dSArmin Le Grand // eof
243