SVGTransformListParser.cpp (5012B)
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 "SVGTransformListParser.h" 8 9 #include "SVGContentUtils.h" 10 #include "SVGTransform.h" 11 #include "nsAtom.h" 12 #include "nsGkAtoms.h" 13 14 namespace mozilla { 15 16 //---------------------------------------------------------------------- 17 // private methods 18 19 bool SVGTransformListParser::Parse() { 20 mTransforms.Clear(); 21 return ParseTransforms(); 22 } 23 24 bool SVGTransformListParser::ParseTransforms() { 25 if (!SkipWsp()) { 26 return true; 27 } 28 29 if (!ParseTransform()) { 30 return false; 31 } 32 33 while (SkipWsp()) { 34 // The SVG BNF allows multiple comma-wsp between transforms 35 while (*mIter == ',') { 36 ++mIter; 37 if (!SkipWsp()) { 38 return false; 39 } 40 } 41 42 if (!ParseTransform()) { 43 return false; 44 } 45 } 46 return true; 47 } 48 49 bool SVGTransformListParser::ParseTransform() { 50 nsAString::const_iterator start(mIter); 51 while (IsAsciiAlpha(*mIter)) { 52 ++mIter; 53 if (mIter == mEnd) { 54 return false; 55 } 56 } 57 58 if (start == mIter) { 59 // Didn't read anything 60 return false; 61 } 62 63 const nsAString& transform = Substring(start, mIter); 64 nsStaticAtom* keyAtom = NS_GetStaticAtom(transform); 65 66 if (!keyAtom || !SkipWsp()) { 67 return false; 68 } 69 70 if (keyAtom == nsGkAtoms::translate) { 71 return ParseTranslate(); 72 } 73 if (keyAtom == nsGkAtoms::scale) { 74 return ParseScale(); 75 } 76 if (keyAtom == nsGkAtoms::rotate) { 77 return ParseRotate(); 78 } 79 if (keyAtom == nsGkAtoms::skewX) { 80 return ParseSkewX(); 81 } 82 if (keyAtom == nsGkAtoms::skewY) { 83 return ParseSkewY(); 84 } 85 if (keyAtom == nsGkAtoms::matrix) { 86 return ParseMatrix(); 87 } 88 return false; 89 } 90 91 bool SVGTransformListParser::ParseArguments(float* aResult, uint32_t aMaxCount, 92 uint32_t* aParsedCount) { 93 if (*mIter != '(') { 94 return false; 95 } 96 ++mIter; 97 98 if (!SkipWsp()) { 99 return false; 100 } 101 102 if (!SVGContentUtils::ParseNumber(mIter, mEnd, aResult[0])) { 103 return false; 104 } 105 *aParsedCount = 1; 106 107 while (SkipWsp()) { 108 if (*mIter == ')') { 109 ++mIter; 110 return true; 111 } 112 if (*aParsedCount == aMaxCount) { 113 return false; 114 } 115 SkipCommaWsp(); 116 if (!SVGContentUtils::ParseNumber(mIter, mEnd, 117 aResult[(*aParsedCount)++])) { 118 return false; 119 } 120 } 121 return false; 122 } 123 124 bool SVGTransformListParser::ParseTranslate() { 125 float t[2]; 126 uint32_t count; 127 128 if (!ParseArguments(t, std::size(t), &count)) { 129 return false; 130 } 131 132 switch (count) { 133 case 1: 134 t[1] = 0.f; 135 [[fallthrough]]; 136 case 2: { 137 SVGTransform* transform = mTransforms.AppendElement(fallible); 138 if (!transform) { 139 return false; 140 } 141 transform->SetTranslate(t[0], t[1]); 142 return true; 143 } 144 } 145 146 return false; 147 } 148 149 bool SVGTransformListParser::ParseScale() { 150 float s[2]; 151 uint32_t count; 152 153 if (!ParseArguments(s, std::size(s), &count)) { 154 return false; 155 } 156 157 switch (count) { 158 case 1: 159 s[1] = s[0]; 160 [[fallthrough]]; 161 case 2: { 162 SVGTransform* transform = mTransforms.AppendElement(fallible); 163 if (!transform) { 164 return false; 165 } 166 transform->SetScale(s[0], s[1]); 167 return true; 168 } 169 } 170 171 return false; 172 } 173 174 bool SVGTransformListParser::ParseRotate() { 175 float r[3]; 176 uint32_t count; 177 178 if (!ParseArguments(r, std::size(r), &count)) { 179 return false; 180 } 181 182 switch (count) { 183 case 1: 184 r[1] = r[2] = 0.f; 185 [[fallthrough]]; 186 case 3: { 187 SVGTransform* transform = mTransforms.AppendElement(fallible); 188 if (!transform) { 189 return false; 190 } 191 transform->SetRotate(r[0], r[1], r[2]); 192 return true; 193 } 194 } 195 196 return false; 197 } 198 199 bool SVGTransformListParser::ParseSkewX() { 200 float skew; 201 uint32_t count; 202 203 if (!ParseArguments(&skew, 1, &count) || count != 1) { 204 return false; 205 } 206 207 SVGTransform* transform = mTransforms.AppendElement(fallible); 208 if (!transform) { 209 return false; 210 } 211 transform->SetSkewX(skew); 212 213 return true; 214 } 215 216 bool SVGTransformListParser::ParseSkewY() { 217 float skew; 218 uint32_t count; 219 220 if (!ParseArguments(&skew, 1, &count) || count != 1) { 221 return false; 222 } 223 224 SVGTransform* transform = mTransforms.AppendElement(fallible); 225 if (!transform) { 226 return false; 227 } 228 transform->SetSkewY(skew); 229 230 return true; 231 } 232 233 bool SVGTransformListParser::ParseMatrix() { 234 float m[6]; 235 uint32_t count; 236 237 if (!ParseArguments(m, std::size(m), &count) || count != 6) { 238 return false; 239 } 240 241 SVGTransform* transform = mTransforms.AppendElement(fallible); 242 if (!transform) { 243 return false; 244 } 245 transform->SetMatrix(gfxMatrix(m[0], m[1], m[2], m[3], m[4], m[5])); 246 247 return true; 248 } 249 250 } // namespace mozilla