LibreOffice Module svgio (master) 1
svgstylenode.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <svgstylenode.hxx>
21#include <svgdocument.hxx>
22#include <o3tl/string_view.hxx>
23#include <osl/diagnose.h>
24
25namespace svgio::svgreader
26{
28 SvgDocument& rDocument,
29 SvgNode* pParent)
30 : SvgNode(SVGToken::Style, rDocument, pParent),
31 mbTextCss(true)
32 {
33 }
34
35 // #i125258# no parent when we are a CssStyle holder to break potential loops because
36 // when using CssStyles we jump uncontrolled inside the node tree hierarchy
38 {
39 if(isTextCss())
40 {
41 return false;
42 }
43
44 // call parent
46 }
47
48 void SvgStyleNode::parseAttribute(const OUString& rTokenName, SVGToken aSVGToken, const OUString& aContent)
49 {
50 // call parent
51 SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
52
53 // parse own
54 switch(aSVGToken)
55 {
56 case SVGToken::Type:
57 {
58 if(!aContent.isEmpty())
59 {
60 if(!o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"text/css"))
61 {
62 setTextCss(false);
63 }
64 }
65 break;
66 }
67 default:
68 {
69 break;
70 }
71 }
72 }
73
74 void SvgStyleNode::addCssStyleSheet(std::u16string_view aSelectors, const SvgStyleAttributes& rNewStyle)
75 {
76 // aSelectors: CssStyle selectors, any combination, no comma separations, no spaces at start/end
77 // rNewStyle: the already prepared style to register on that name
78 if(aSelectors.empty())
79 return;
80
81 std::vector< OUString > aSelectorParts;
82 const sal_Int32 nLen(aSelectors.size());
83 sal_Int32 nPos(0);
84 OUStringBuffer aToken;
85
86 // split into single tokens (currently only space separator)
87 while(nPos < nLen)
88 {
89 const sal_Int32 nInitPos(nPos);
90 copyToLimiter(aSelectors, u' ', nPos, aToken, nLen);
91 skip_char(aSelectors, u' ', nPos, nLen);
92 const OUString aSelectorPart(o3tl::trim(aToken));
93 aToken.setLength(0);
94
95 if(!aSelectorPart.isEmpty())
96 {
97 aSelectorParts.push_back(aSelectorPart);
98 }
99
100 if(nInitPos == nPos)
101 {
102 OSL_ENSURE(false, "Could not interpret on current position (!)");
103 nPos++;
104 }
105 }
106
107 if(aSelectorParts.empty())
108 return;
109
110 OUStringBuffer aConcatenatedSelector;
111
112 // re-combine without spaces, create a unique name (for now)
113 for(const auto &a : aSelectorParts)
114 {
115 aConcatenatedSelector.append(a);
116 }
117
118 // CssStyles in SVG are currently not completely supported; the current idea for
119 // supporting the needed minimal set is to register CssStyles associated to a string
120 // which is just the space-char cleaned, concatenated Selectors. The part to 'match'
121 // these is in fillCssStyleVectorUsingHierarchyAndSelectors. There, the same string is
122 // built up using the priorities of local CssStyle, Id, Class and other info combined
123 // with the existing hierarchy. This creates a specificity and priority-sorted local
124 // list for each node which is then chained using get/setCssStyleParent.
125 // The current solution is capable of solving space-separated selectors which can be
126 // mixed between Id, Class and type specifiers.
127 // When CssStyles need more specific solving, the start point is here; remember the
128 // needed infos not in maIdStyleTokenMapperList at the document, but select evtl.
129 // more specific infos there in a class capable of handling more complex matchings.
130 // Additionally fillCssStyleVector (or the mechanism above that when a linked list of
131 // SvgStyleAttributes will not do it) will have to be adapted to make use of it.
132
133 // register new style at document for (evtl. concatenated) stylename
134 const_cast< SvgDocument& >(getDocument()).addSvgStyleAttributesToMapper(aConcatenatedSelector.makeStringAndClear(), rNewStyle);
135 }
136
137 void SvgStyleNode::addCssStyleSheet(std::u16string_view aSelectors, std::u16string_view aContent)
138 {
139 // aSelectors: possible comma-separated list of CssStyle definitions, no spaces at start/end
140 // aContent: the svg style definitions as string
141 if(aSelectors.empty() || aContent.empty())
142 return;
143
144 // comma-separated split (Css abbreviation for same style for multiple selectors)
145 const sal_Int32 nLen(aSelectors.size());
146 sal_Int32 nPos(0);
147 OUStringBuffer aToken;
148
149 while(nPos < nLen)
150 {
151 const sal_Int32 nInitPos(nPos);
152 copyToLimiter(aSelectors, u',', nPos, aToken, nLen);
153 skip_char(aSelectors, u' ', u',', nPos, nLen);
154
155 const OUString aSingleName(o3tl::trim(aToken));
156 aToken.setLength(0);
157
158 // add the current css class only if wasn't previously added
159 auto [aIterator, bIsNew] = maSvgStyleAttributes.try_emplace(aSingleName);
160 if (bIsNew)
161 {
162 // create new style and add to local list (for ownership control) and
163 // in case it's written to again in future classes to prevent overwrites
164 aIterator->second = std::make_unique<SvgStyleAttributes>(*this);
165 }
166 const std::unique_ptr<SvgStyleAttributes>& pCurrentStyle = aIterator->second;
167
168 // fill with content
169 pCurrentStyle->readCssStyle(aContent);
170
171 if(aSingleName.getLength())
172 {
173 addCssStyleSheet(aSingleName, *pCurrentStyle);
174 }
175
176 if(nInitPos == nPos)
177 {
178 OSL_ENSURE(false, "Could not interpret on current position (!)");
179 nPos++;
180 }
181 }
182 }
183
184 void SvgStyleNode::addCssStyleSheet(std::u16string_view aSelectorsAndContent)
185 {
186 const sal_Int32 nLen(aSelectorsAndContent.size());
187
188 if(!nLen)
189 return;
190
191 sal_Int32 nPos(0);
192 OUStringBuffer aToken;
193
194 while(nPos < nLen)
195 {
196 // read the full selectors (may be multiple, comma-separated)
197 const sal_Int32 nInitPos(nPos);
198 skip_char(aSelectorsAndContent, u' ', nPos, nLen);
199 copyToLimiter(aSelectorsAndContent, u'{', nPos, aToken, nLen);
200 skip_char(aSelectorsAndContent, u' ', u'{', nPos, nLen);
201
202 const OUString aSelectors(o3tl::trim(aToken));
203 aToken.setLength(0);
204 OUString aContent;
205
206 if(!aSelectors.isEmpty() && nPos < nLen)
207 {
208 // isolate content as text, embraced by '{' and '}'
209 copyToLimiter(aSelectorsAndContent, u'}', nPos, aToken, nLen);
210 skip_char(aSelectorsAndContent, u' ', u'}', nPos, nLen);
211
212 aContent = o3tl::trim(aToken);
213 aToken.setLength(0);
214 }
215
216 if(!aSelectors.isEmpty() && !aContent.isEmpty())
217 {
218 addCssStyleSheet(aSelectors, aContent);
219 }
220
221 if(nInitPos == nPos)
222 {
223 OSL_ENSURE(false, "Could not interpret on current position (!)");
224 nPos++;
225 }
226 }
227 }
228
229} // end of namespace svgio::svgreader
230
231/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual bool supportsParentStyle() const
#i125258# tell if this node is allowed to have a parent style (e.g. defs do not)
Definition: svgnode.cxx:32
virtual void parseAttribute(const OUString &rTokenName, SVGToken aSVGToken, const OUString &aContent)
Definition: svgnode.cxx:534
const SvgDocument & getDocument() const
Definition: svgnode.hxx:157
SvgStyleNode(SvgDocument &rDocument, SvgNode *pParent)
virtual bool supportsParentStyle() const override
#i125258# tell if this node is allowed to have a parent style (e.g. defs do not)
virtual void parseAttribute(const OUString &rTokenName, SVGToken aSVGToken, const OUString &aContent) override
std::unordered_map< OUString, std::unique_ptr< SvgStyleAttributes > > maSvgStyleAttributes
use styles
void addCssStyleSheet(std::u16string_view aSelectors, const SvgStyleAttributes &rNewStyle)
CssStyleSheet add helpers.
bool isTextCss() const
textCss access
float u
uno_Any a
sal_uInt16 nPos
std::basic_string_view< charT, traits > trim(std::basic_string_view< charT, traits > str)
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
void skip_char(std::u16string_view rCandidate, sal_Unicode nChar, sal_Int32 &nPos, const sal_Int32 nLen)
Definition: svgtools.cxx:292
void copyToLimiter(std::u16string_view rCandidate, sal_Unicode nLimiter, sal_Int32 &nPos, OUStringBuffer &rTarget, const sal_Int32 nLen)
Definition: svgtools.cxx:380