1 | /* |
2 | * Copyright (C) 2007, 2010 Rob Buis <buis@kde.org> |
3 | * Copyright (C) 2018-2019 Apple Inc. All rights reserved. |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Library General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Library General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Library General Public License |
16 | * along with this library; see the file COPYING.LIB. If not, write to |
17 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | * Boston, MA 02110-1301, USA. |
19 | */ |
20 | |
21 | #include "config.h" |
22 | #include "SVGViewSpec.h" |
23 | |
24 | #include "Document.h" |
25 | #include "SVGElement.h" |
26 | #include "SVGFitToViewBox.h" |
27 | #include "SVGNames.h" |
28 | #include "SVGParserUtilities.h" |
29 | #include "SVGTransformList.h" |
30 | #include "SVGTransformable.h" |
31 | |
32 | namespace WebCore { |
33 | |
34 | SVGViewSpec::SVGViewSpec(SVGElement& contextElement) |
35 | : SVGFitToViewBox(&contextElement, SVGPropertyAccess::ReadOnly) |
36 | , m_contextElement(makeWeakPtr(contextElement)) |
37 | , m_transform(SVGTransformList::create(&contextElement, SVGPropertyAccess::ReadOnly)) |
38 | { |
39 | static std::once_flag onceFlag; |
40 | std::call_once(onceFlag, [] { |
41 | PropertyRegistry::registerProperty<SVGNames::transformAttr, &SVGViewSpec::m_transform>(); |
42 | }); |
43 | } |
44 | |
45 | SVGElement* SVGViewSpec::viewTarget() const |
46 | { |
47 | if (!m_contextElement) |
48 | return nullptr; |
49 | auto* element = m_contextElement->treeScope().getElementById(m_viewTargetString); |
50 | if (!is<SVGElement>(element)) |
51 | return nullptr; |
52 | return downcast<SVGElement>(element); |
53 | } |
54 | |
55 | void SVGViewSpec::reset() |
56 | { |
57 | m_viewTargetString = emptyString(); |
58 | m_transform->clearItems(); |
59 | SVGFitToViewBox::reset(); |
60 | SVGZoomAndPan::reset(); |
61 | } |
62 | |
63 | static const UChar svgViewSpec[] = {'s', 'v', 'g', 'V', 'i', 'e', 'w'}; |
64 | static const UChar viewBoxSpec[] = {'v', 'i', 'e', 'w', 'B', 'o', 'x'}; |
65 | static const UChar preserveAspectRatioSpec[] = {'p', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'A', 's', 'p', 'e', 'c', 't', 'R', 'a', 't', 'i', 'o'}; |
66 | static const UChar transformSpec[] = {'t', 'r', 'a', 'n', 's', 'f', 'o', 'r', 'm'}; |
67 | static const UChar zoomAndPanSpec[] = {'z', 'o', 'o', 'm', 'A', 'n', 'd', 'P', 'a', 'n'}; |
68 | static const UChar viewTargetSpec[] = {'v', 'i', 'e', 'w', 'T', 'a', 'r', 'g', 'e', 't'}; |
69 | |
70 | bool SVGViewSpec::parseViewSpec(const String& viewSpec) |
71 | { |
72 | auto upconvertedCharacters = StringView(viewSpec).upconvertedCharacters(); |
73 | const UChar* currViewSpec = upconvertedCharacters; |
74 | const UChar* end = currViewSpec + viewSpec.length(); |
75 | |
76 | if (currViewSpec >= end || !m_contextElement) |
77 | return false; |
78 | |
79 | if (!skipString(currViewSpec, end, svgViewSpec, WTF_ARRAY_LENGTH(svgViewSpec))) |
80 | return false; |
81 | |
82 | if (currViewSpec >= end || *currViewSpec != '(') |
83 | return false; |
84 | currViewSpec++; |
85 | |
86 | while (currViewSpec < end && *currViewSpec != ')') { |
87 | if (*currViewSpec == 'v') { |
88 | if (skipString(currViewSpec, end, viewBoxSpec, WTF_ARRAY_LENGTH(viewBoxSpec))) { |
89 | if (currViewSpec >= end || *currViewSpec != '(') |
90 | return false; |
91 | currViewSpec++; |
92 | FloatRect viewBox; |
93 | if (!SVGFitToViewBox::parseViewBox(currViewSpec, end, viewBox, false)) |
94 | return false; |
95 | setViewBox(viewBox); |
96 | if (currViewSpec >= end || *currViewSpec != ')') |
97 | return false; |
98 | currViewSpec++; |
99 | } else if (skipString(currViewSpec, end, viewTargetSpec, WTF_ARRAY_LENGTH(viewTargetSpec))) { |
100 | if (currViewSpec >= end || *currViewSpec != '(') |
101 | return false; |
102 | const UChar* viewTargetStart = ++currViewSpec; |
103 | while (currViewSpec < end && *currViewSpec != ')') |
104 | currViewSpec++; |
105 | if (currViewSpec >= end) |
106 | return false; |
107 | m_viewTargetString = String(viewTargetStart, currViewSpec - viewTargetStart); |
108 | currViewSpec++; |
109 | } else |
110 | return false; |
111 | } else if (*currViewSpec == 'z') { |
112 | if (!skipString(currViewSpec, end, zoomAndPanSpec, WTF_ARRAY_LENGTH(zoomAndPanSpec))) |
113 | return false; |
114 | if (currViewSpec >= end || *currViewSpec != '(') |
115 | return false; |
116 | currViewSpec++; |
117 | if (!SVGZoomAndPan::parseZoomAndPan(currViewSpec, end)) |
118 | return false; |
119 | if (currViewSpec >= end || *currViewSpec != ')') |
120 | return false; |
121 | currViewSpec++; |
122 | } else if (*currViewSpec == 'p') { |
123 | if (!skipString(currViewSpec, end, preserveAspectRatioSpec, WTF_ARRAY_LENGTH(preserveAspectRatioSpec))) |
124 | return false; |
125 | if (currViewSpec >= end || *currViewSpec != '(') |
126 | return false; |
127 | currViewSpec++; |
128 | SVGPreserveAspectRatioValue preserveAspectRatio; |
129 | if (!preserveAspectRatio.parse(currViewSpec, end, false)) |
130 | return false; |
131 | setPreserveAspectRatio(preserveAspectRatio); |
132 | if (currViewSpec >= end || *currViewSpec != ')') |
133 | return false; |
134 | currViewSpec++; |
135 | } else if (*currViewSpec == 't') { |
136 | if (!skipString(currViewSpec, end, transformSpec, WTF_ARRAY_LENGTH(transformSpec))) |
137 | return false; |
138 | if (currViewSpec >= end || *currViewSpec != '(') |
139 | return false; |
140 | currViewSpec++; |
141 | m_transform->parse(currViewSpec, end); |
142 | if (currViewSpec >= end || *currViewSpec != ')') |
143 | return false; |
144 | currViewSpec++; |
145 | } else |
146 | return false; |
147 | |
148 | if (currViewSpec < end && *currViewSpec == ';') |
149 | currViewSpec++; |
150 | } |
151 | |
152 | if (currViewSpec >= end || *currViewSpec != ')') |
153 | return false; |
154 | |
155 | return true; |
156 | } |
157 | |
158 | } |
159 | |