Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/ArrayUtils.h"
8 :
9 : #include "SVGTransformListParser.h"
10 : #include "SVGContentUtils.h"
11 : #include "nsSVGTransform.h"
12 : #include "nsGkAtoms.h"
13 : #include "nsIAtom.h"
14 :
15 : using namespace mozilla;
16 :
17 : //----------------------------------------------------------------------
18 : // private methods
19 :
20 : bool
21 7 : SVGTransformListParser::Parse()
22 : {
23 7 : mTransforms.Clear();
24 7 : return ParseTransforms();
25 : }
26 :
27 : bool
28 7 : SVGTransformListParser::ParseTransforms()
29 : {
30 7 : if (!SkipWsp()) {
31 0 : return true;
32 : }
33 :
34 7 : if (!ParseTransform()) {
35 0 : return false;
36 : }
37 :
38 7 : while (SkipWsp()) {
39 : // The SVG BNF allows multiple comma-wsp between transforms
40 0 : while (*mIter == ',') {
41 0 : ++mIter;
42 0 : if (!SkipWsp()) {
43 0 : return false;
44 : }
45 : }
46 :
47 0 : if (!ParseTransform()) {
48 0 : return false;
49 : }
50 : }
51 7 : return true;
52 : }
53 :
54 : bool
55 7 : SVGTransformListParser::ParseTransform()
56 : {
57 7 : RangedPtr<const char16_t> start(mIter);
58 133 : while (IsAlpha(*mIter)) {
59 63 : ++mIter;
60 63 : if (mIter == mEnd) {
61 0 : return false;
62 : }
63 : }
64 :
65 7 : if (start == mIter) {
66 : // Didn't read anything
67 0 : return false;
68 : }
69 :
70 14 : const nsAString& transform = Substring(start.get(), mIter.get());
71 7 : nsIAtom* keyAtom = NS_GetStaticAtom(transform);
72 :
73 7 : if (!keyAtom || !SkipWsp()) {
74 0 : return false;
75 : }
76 :
77 7 : if (keyAtom == nsGkAtoms::translate) {
78 7 : return ParseTranslate();
79 : }
80 0 : if (keyAtom == nsGkAtoms::scale) {
81 0 : return ParseScale();
82 : }
83 0 : if (keyAtom == nsGkAtoms::rotate) {
84 0 : return ParseRotate();
85 : }
86 0 : if (keyAtom == nsGkAtoms::skewX) {
87 0 : return ParseSkewX();
88 : }
89 0 : if (keyAtom == nsGkAtoms::skewY) {
90 0 : return ParseSkewY();
91 : }
92 0 : if (keyAtom == nsGkAtoms::matrix) {
93 0 : return ParseMatrix();
94 : }
95 0 : return false;
96 : }
97 :
98 : bool
99 7 : SVGTransformListParser::ParseArguments(float* aResult,
100 : uint32_t aMaxCount,
101 : uint32_t* aParsedCount)
102 : {
103 7 : if (*mIter != '(') {
104 0 : return false;
105 : }
106 7 : ++mIter;
107 :
108 7 : if (!SkipWsp()) {
109 0 : return false;
110 : }
111 :
112 7 : if (!SVGContentUtils::ParseNumber(mIter, mEnd, aResult[0])) {
113 0 : return false;
114 : }
115 7 : *aParsedCount = 1;
116 :
117 11 : while (SkipWsp()) {
118 9 : if (*mIter == ')') {
119 7 : ++mIter;
120 7 : return true;
121 : }
122 2 : if (*aParsedCount == aMaxCount) {
123 0 : return false;
124 : }
125 2 : SkipCommaWsp();
126 2 : if (!SVGContentUtils::ParseNumber(mIter, mEnd, aResult[(*aParsedCount)++])) {
127 0 : return false;
128 : }
129 : }
130 0 : return false;
131 : }
132 :
133 : bool
134 7 : SVGTransformListParser::ParseTranslate()
135 : {
136 : float t[2];
137 : uint32_t count;
138 :
139 7 : if (!ParseArguments(t, ArrayLength(t), &count)) {
140 0 : return false;
141 : }
142 :
143 7 : switch (count) {
144 : case 1:
145 5 : t[1] = 0.f;
146 : MOZ_FALLTHROUGH;
147 : case 2:
148 : {
149 7 : nsSVGTransform* transform = mTransforms.AppendElement(fallible);
150 7 : if (!transform) {
151 0 : return false;
152 : }
153 7 : transform->SetTranslate(t[0], t[1]);
154 7 : return true;
155 : }
156 : }
157 :
158 0 : return false;
159 : }
160 :
161 : bool
162 0 : SVGTransformListParser::ParseScale()
163 : {
164 : float s[2];
165 : uint32_t count;
166 :
167 0 : if (!ParseArguments(s, ArrayLength(s), &count)) {
168 0 : return false;
169 : }
170 :
171 0 : switch (count) {
172 : case 1:
173 0 : s[1] = s[0];
174 : MOZ_FALLTHROUGH;
175 : case 2:
176 : {
177 0 : nsSVGTransform* transform = mTransforms.AppendElement(fallible);
178 0 : if (!transform) {
179 0 : return false;
180 : }
181 0 : transform->SetScale(s[0], s[1]);
182 0 : return true;
183 : }
184 : }
185 :
186 0 : return false;
187 : }
188 :
189 :
190 : bool
191 0 : SVGTransformListParser::ParseRotate()
192 : {
193 : float r[3];
194 : uint32_t count;
195 :
196 0 : if (!ParseArguments(r, ArrayLength(r), &count)) {
197 0 : return false;
198 : }
199 :
200 0 : switch (count) {
201 : case 1:
202 0 : r[1] = r[2] = 0.f;
203 : MOZ_FALLTHROUGH;
204 : case 3:
205 : {
206 0 : nsSVGTransform* transform = mTransforms.AppendElement(fallible);
207 0 : if (!transform) {
208 0 : return false;
209 : }
210 0 : transform->SetRotate(r[0], r[1], r[2]);
211 0 : return true;
212 : }
213 : }
214 :
215 0 : return false;
216 : }
217 :
218 : bool
219 0 : SVGTransformListParser::ParseSkewX()
220 : {
221 : float skew;
222 : uint32_t count;
223 :
224 0 : if (!ParseArguments(&skew, 1, &count) || count != 1) {
225 0 : return false;
226 : }
227 :
228 0 : nsSVGTransform* transform = mTransforms.AppendElement(fallible);
229 0 : if (!transform) {
230 0 : return false;
231 : }
232 0 : transform->SetSkewX(skew);
233 :
234 0 : return true;
235 : }
236 :
237 : bool
238 0 : SVGTransformListParser::ParseSkewY()
239 : {
240 : float skew;
241 : uint32_t count;
242 :
243 0 : if (!ParseArguments(&skew, 1, &count) || count != 1) {
244 0 : return false;
245 : }
246 :
247 0 : nsSVGTransform* transform = mTransforms.AppendElement(fallible);
248 0 : if (!transform) {
249 0 : return false;
250 : }
251 0 : transform->SetSkewY(skew);
252 :
253 0 : return true;
254 : }
255 :
256 : bool
257 0 : SVGTransformListParser::ParseMatrix()
258 : {
259 : float m[6];
260 : uint32_t count;
261 :
262 0 : if (!ParseArguments(m, ArrayLength(m), &count) || count != 6) {
263 0 : return false;
264 : }
265 :
266 0 : nsSVGTransform* transform = mTransforms.AppendElement(fallible);
267 0 : if (!transform) {
268 0 : return false;
269 : }
270 0 : transform->SetMatrix(gfxMatrix(m[0], m[1], m[2], m[3], m[4], m[5]));
271 :
272 0 : return true;
273 : }
|