1 | /* |
2 | * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org> |
3 | * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> |
4 | * Copyright (C) 2015-2018 Apple Inc. All right reserved. |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Library General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Library General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Library General Public License |
17 | * along with this library; see the file COPYING.LIB. If not, write to |
18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | * Boston, MA 02110-1301, USA. |
20 | */ |
21 | |
22 | #include "config.h" |
23 | #include "SVGTests.h" |
24 | |
25 | #include "DOMImplementation.h" |
26 | #include "HTMLNames.h" |
27 | #include "SVGElement.h" |
28 | #include "SVGNames.h" |
29 | #include "SVGStringList.h" |
30 | #include <wtf/Language.h> |
31 | #include <wtf/NeverDestroyed.h> |
32 | |
33 | #if ENABLE(MATHML) |
34 | #include "MathMLNames.h" |
35 | #endif |
36 | |
37 | namespace WebCore { |
38 | |
39 | using namespace SVGNames; |
40 | |
41 | static const HashSet<String, ASCIICaseInsensitiveHash>& supportedSVGFeatures() |
42 | { |
43 | static NeverDestroyed<HashSet<String, ASCIICaseInsensitiveHash>> features = [] { |
44 | static const char* const features10[] = { |
45 | #if ENABLE(SVG_FONTS) |
46 | "dom" , |
47 | "dom.svg" , |
48 | "dom.svg.static" , |
49 | "svg" , |
50 | "svg.static" , |
51 | #endif |
52 | }; |
53 | static const char* const features11[] = { |
54 | "animation" , |
55 | "basegraphicsattribute" , |
56 | "basicclip" , |
57 | "basicfilter" , |
58 | "basicpaintattribute" , |
59 | "basicstructure" , |
60 | "basictext" , |
61 | "clip" , |
62 | "conditionalprocessing" , |
63 | "containerattribute" , |
64 | "coreattribute" , |
65 | "cursor" , |
66 | "documenteventsattribute" , |
67 | "extensibility" , |
68 | "externalresourcesrequired" , |
69 | "filter" , |
70 | "gradient" , |
71 | "graphicaleventsattribute" , |
72 | "graphicsattribute" , |
73 | "hyperlinking" , |
74 | "image" , |
75 | "marker" , |
76 | "mask" , |
77 | "opacityattribute" , |
78 | "paintattribute" , |
79 | "pattern" , |
80 | "script" , |
81 | "shape" , |
82 | "structure" , |
83 | "style" , |
84 | "svg-animation" , |
85 | "svgdom-animation" , |
86 | "text" , |
87 | "view" , |
88 | "viewportattribute" , |
89 | "xlinkattribute" , |
90 | #if ENABLE(SVG_FONTS) |
91 | "basicfont" , |
92 | "font" , |
93 | "svg" , |
94 | "svg-static" , |
95 | "svgdom" , |
96 | "svgdom-static" , |
97 | #endif |
98 | }; |
99 | HashSet<String, ASCIICaseInsensitiveHash> set; |
100 | for (auto& feature : features10) |
101 | set.add(makeString("org.w3c." , feature)); |
102 | for (auto& feature : features11) |
103 | set.add(makeString("http://www.w3.org/tr/svg11/feature#" , feature)); |
104 | return set; |
105 | }(); |
106 | return features; |
107 | } |
108 | |
109 | SVGTests::SVGTests(SVGElement* contextElement) |
110 | : m_contextElement(*contextElement) |
111 | , m_requiredFeatures(SVGStringList::create(contextElement)) |
112 | , m_requiredExtensions(SVGStringList::create(contextElement)) |
113 | , m_systemLanguage(SVGStringList::create(contextElement)) |
114 | { |
115 | static std::once_flag onceFlag; |
116 | std::call_once(onceFlag, [] { |
117 | PropertyRegistry::registerProperty<SVGNames::requiredFeaturesAttr, &SVGTests::m_requiredFeatures>(); |
118 | PropertyRegistry::registerProperty<SVGNames::requiredExtensionsAttr, &SVGTests::m_requiredExtensions>(); |
119 | PropertyRegistry::registerProperty<SVGNames::systemLanguageAttr, &SVGTests::m_systemLanguage>(); |
120 | }); |
121 | } |
122 | |
123 | bool SVGTests::hasExtension(const String& extension) |
124 | { |
125 | // We recognize XHTML and MathML, as implemented in Gecko and suggested in the SVG Tiny recommendation (http://www.w3.org/TR/SVG11/struct.html#RequiredExtensionsAttribute). |
126 | #if ENABLE(MATHML) |
127 | if (extension == MathMLNames::mathmlNamespaceURI) |
128 | return true; |
129 | #endif |
130 | return extension == HTMLNames::xhtmlNamespaceURI; |
131 | } |
132 | |
133 | bool SVGTests::isValid() const |
134 | { |
135 | for (auto& feature : m_requiredFeatures->items()) { |
136 | if (feature.isEmpty() || !supportedSVGFeatures().contains(feature)) |
137 | return false; |
138 | } |
139 | for (auto& language : m_systemLanguage->items()) { |
140 | if (language != defaultLanguage().substring(0, 2)) |
141 | return false; |
142 | } |
143 | for (auto& extension : m_requiredExtensions->items()) { |
144 | if (!hasExtension(extension)) |
145 | return false; |
146 | } |
147 | return true; |
148 | } |
149 | |
150 | void SVGTests::parseAttribute(const QualifiedName& attributeName, const AtomicString& value) |
151 | { |
152 | if (attributeName == requiredFeaturesAttr) |
153 | m_requiredFeatures->reset(value); |
154 | if (attributeName == requiredExtensionsAttr) |
155 | m_requiredExtensions->reset(value); |
156 | if (attributeName == systemLanguageAttr) |
157 | m_systemLanguage->reset(value); |
158 | } |
159 | |
160 | void SVGTests::svgAttributeChanged(const QualifiedName& attrName) |
161 | { |
162 | if (!PropertyRegistry::isKnownAttribute(attrName)) |
163 | return; |
164 | |
165 | if (!m_contextElement.isConnected()) |
166 | return; |
167 | m_contextElement.invalidateStyleAndRenderersForSubtree(); |
168 | } |
169 | |
170 | void SVGTests::addSupportedAttributes(HashSet<QualifiedName>& supportedAttributes) |
171 | { |
172 | supportedAttributes.add(requiredFeaturesAttr); |
173 | supportedAttributes.add(requiredExtensionsAttr); |
174 | supportedAttributes.add(systemLanguageAttr); |
175 | } |
176 | |
177 | bool SVGTests::hasFeatureForLegacyBindings(const String& feature, const String& version) |
178 | { |
179 | // FIXME: This function is here only to be exposed in the Objective-C and GObject bindings for both Node and DOMImplementation. |
180 | // It's likely that we can just remove this and instead have the bindings return true unconditionally. |
181 | // This is what the DOMImplementation function now does in JavaScript as is now suggested in the DOM specification. |
182 | // The behavior implemented below is quirky, but preserves what WebKit has done for at least the last few years. |
183 | |
184 | bool hasSVG10FeaturePrefix = startsWithLettersIgnoringASCIICase(feature, "org.w3c.dom.svg" ) || startsWithLettersIgnoringASCIICase(feature, "org.w3c.svg" ); |
185 | bool hasSVG11FeaturePrefix = startsWithLettersIgnoringASCIICase(feature, "http://www.w3.org/tr/svg" ); |
186 | |
187 | // We don't even try to handle feature names that don't look like the SVG ones, so just return true for all of those. |
188 | if (!(hasSVG10FeaturePrefix || hasSVG11FeaturePrefix)) |
189 | return true; |
190 | |
191 | // If the version number matches the style of the feature name, then use the set to see if the feature is supported. |
192 | if (version.isEmpty() || (hasSVG10FeaturePrefix && version == "1.0" ) || (hasSVG11FeaturePrefix && version == "1.1" )) |
193 | return supportedSVGFeatures().contains(feature); |
194 | |
195 | return false; |
196 | } |
197 | |
198 | } |
199 | |