Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | |
michael@0 | 2 | /* |
michael@0 | 3 | * Copyright 2006 The Android Open Source Project |
michael@0 | 4 | * |
michael@0 | 5 | * Use of this source code is governed by a BSD-style license that can be |
michael@0 | 6 | * found in the LICENSE file. |
michael@0 | 7 | */ |
michael@0 | 8 | |
michael@0 | 9 | |
michael@0 | 10 | #include "SkSVGParser.h" |
michael@0 | 11 | #include "SkSVGCircle.h" |
michael@0 | 12 | #include "SkSVGClipPath.h" |
michael@0 | 13 | #include "SkSVGDefs.h" |
michael@0 | 14 | #include "SkSVGEllipse.h" |
michael@0 | 15 | #include "SkSVGFeColorMatrix.h" |
michael@0 | 16 | #include "SkSVGFilter.h" |
michael@0 | 17 | #include "SkSVGG.h" |
michael@0 | 18 | #include "SkSVGImage.h" |
michael@0 | 19 | #include "SkSVGLine.h" |
michael@0 | 20 | #include "SkSVGLinearGradient.h" |
michael@0 | 21 | #include "SkSVGMask.h" |
michael@0 | 22 | #include "SkSVGMetadata.h" |
michael@0 | 23 | #include "SkSVGPath.h" |
michael@0 | 24 | #include "SkSVGPolygon.h" |
michael@0 | 25 | #include "SkSVGPolyline.h" |
michael@0 | 26 | #include "SkSVGRadialGradient.h" |
michael@0 | 27 | #include "SkSVGRect.h" |
michael@0 | 28 | #include "SkSVGSVG.h" |
michael@0 | 29 | #include "SkSVGStop.h" |
michael@0 | 30 | #include "SkSVGSymbol.h" |
michael@0 | 31 | #include "SkSVGText.h" |
michael@0 | 32 | #include "SkSVGUse.h" |
michael@0 | 33 | #include "SkTSearch.h" |
michael@0 | 34 | #include <stdio.h> |
michael@0 | 35 | |
michael@0 | 36 | static int gGeneratedMatrixID = 0; |
michael@0 | 37 | |
michael@0 | 38 | SkSVGParser::SkSVGParser(SkXMLParserError* errHandler) : |
michael@0 | 39 | SkXMLParser(errHandler), |
michael@0 | 40 | fHead(&fEmptyPaint), fIDs(256), |
michael@0 | 41 | fXMLWriter(&fStream), fCurrElement(NULL), fInSVG(false), fSuppressPaint(false) { |
michael@0 | 42 | fLastTransform.reset(); |
michael@0 | 43 | fEmptyPaint.f_fill.set("black"); |
michael@0 | 44 | fEmptyPaint.f_stroke.set("none"); |
michael@0 | 45 | fEmptyPaint.f_strokeMiterlimit.set("4"); |
michael@0 | 46 | fEmptyPaint.f_fillRule.set("winding"); |
michael@0 | 47 | fEmptyPaint.f_opacity.set("1"); |
michael@0 | 48 | fEmptyPaint.fNext = NULL; |
michael@0 | 49 | for (int index = SkSVGPaint::kInitial + 1; index < SkSVGPaint::kTerminal; index++) { |
michael@0 | 50 | SkString* initial = fEmptyPaint[index]; |
michael@0 | 51 | if (initial->size() == 0) |
michael@0 | 52 | continue; |
michael@0 | 53 | fLastFlush[index]->set(*initial); |
michael@0 | 54 | } |
michael@0 | 55 | } |
michael@0 | 56 | |
michael@0 | 57 | SkSVGParser::~SkSVGParser() { |
michael@0 | 58 | } |
michael@0 | 59 | |
michael@0 | 60 | void SkSVGParser::Delete(SkTDArray<SkSVGElement*>& fChildren) { |
michael@0 | 61 | SkSVGElement** ptr; |
michael@0 | 62 | for (ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { |
michael@0 | 63 | Delete((*ptr)->fChildren); |
michael@0 | 64 | delete *ptr; |
michael@0 | 65 | } |
michael@0 | 66 | } |
michael@0 | 67 | |
michael@0 | 68 | int SkSVGParser::findAttribute(SkSVGBase* element, const char* attrValue, |
michael@0 | 69 | size_t len, bool isPaint) { |
michael@0 | 70 | const SkSVGAttribute* attributes; |
michael@0 | 71 | size_t count = element->getAttributes(&attributes); |
michael@0 | 72 | size_t result = 0; |
michael@0 | 73 | while (result < count) { |
michael@0 | 74 | if (strncmp(attributes->fName, attrValue, len) == 0 && strlen(attributes->fName) == len) { |
michael@0 | 75 | SkASSERT(result == (attributes->fOffset - |
michael@0 | 76 | (isPaint ? sizeof(SkString) : sizeof(SkSVGElement))) / sizeof(SkString)); |
michael@0 | 77 | return result; |
michael@0 | 78 | } |
michael@0 | 79 | attributes++; |
michael@0 | 80 | result++; |
michael@0 | 81 | } |
michael@0 | 82 | return -1; |
michael@0 | 83 | } |
michael@0 | 84 | |
michael@0 | 85 | #if 0 |
michael@0 | 86 | const char* SkSVGParser::getFinal() { |
michael@0 | 87 | _startElement("screenplay"); |
michael@0 | 88 | // generate defs |
michael@0 | 89 | SkSVGElement** ptr; |
michael@0 | 90 | for (ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { |
michael@0 | 91 | SkSVGElement* element = *ptr; |
michael@0 | 92 | translate(element, true); |
michael@0 | 93 | } |
michael@0 | 94 | // generate onLoad |
michael@0 | 95 | _startElement("event"); |
michael@0 | 96 | _addAttribute("kind", "onLoad"); |
michael@0 | 97 | _startElement("paint"); |
michael@0 | 98 | _addAttribute("antiAlias", "true"); |
michael@0 | 99 | _endElement(); |
michael@0 | 100 | for (ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { |
michael@0 | 101 | SkSVGElement* element = *ptr; |
michael@0 | 102 | translate(element, false); |
michael@0 | 103 | } |
michael@0 | 104 | _endElement(); // event |
michael@0 | 105 | _endElement(); // screenplay |
michael@0 | 106 | Delete(fChildren); |
michael@0 | 107 | fStream.write("", 1); |
michael@0 | 108 | return fStream.getStream(); |
michael@0 | 109 | } |
michael@0 | 110 | #endif |
michael@0 | 111 | |
michael@0 | 112 | SkString& SkSVGParser::getPaintLast(SkSVGPaint::Field field) { |
michael@0 | 113 | SkSVGPaint* state = fHead; |
michael@0 | 114 | do { |
michael@0 | 115 | SkString* attr = (*state)[field]; |
michael@0 | 116 | SkASSERT(attr); |
michael@0 | 117 | if (attr->size() > 0) |
michael@0 | 118 | return *attr; |
michael@0 | 119 | state = state->fNext; |
michael@0 | 120 | } while (state); |
michael@0 | 121 | SkASSERT(0); |
michael@0 | 122 | SkASSERT(fEmptyPaint[field]); |
michael@0 | 123 | return *fEmptyPaint[field]; |
michael@0 | 124 | } |
michael@0 | 125 | |
michael@0 | 126 | bool SkSVGParser::isStrokeAndFill( SkSVGPaint** strokeState, SkSVGPaint** fillState) { |
michael@0 | 127 | SkSVGPaint* walking = fHead; |
michael@0 | 128 | bool stroke = false; |
michael@0 | 129 | bool fill = false; |
michael@0 | 130 | bool strokeSet = false; |
michael@0 | 131 | bool fillSet = false; |
michael@0 | 132 | while (walking != NULL) { |
michael@0 | 133 | if (strokeSet == false && walking->f_stroke.size() > 0) { |
michael@0 | 134 | stroke = walking->f_stroke.equals("none") == false; |
michael@0 | 135 | *strokeState = walking; |
michael@0 | 136 | strokeSet = true; |
michael@0 | 137 | } |
michael@0 | 138 | if (fillSet == false && walking->f_fill.size() > 0) { |
michael@0 | 139 | fill = walking->f_fill.equals("none") == false; |
michael@0 | 140 | *fillState = walking; |
michael@0 | 141 | fillSet = true; |
michael@0 | 142 | } |
michael@0 | 143 | walking = walking->fNext; |
michael@0 | 144 | } |
michael@0 | 145 | return stroke && fill; |
michael@0 | 146 | } |
michael@0 | 147 | |
michael@0 | 148 | bool SkSVGParser::onAddAttribute(const char name[], const char value[]) { |
michael@0 | 149 | return onAddAttributeLen(name, value, strlen(value)); |
michael@0 | 150 | } |
michael@0 | 151 | |
michael@0 | 152 | bool SkSVGParser::onAddAttributeLen(const char name[], const char value[], size_t len) { |
michael@0 | 153 | if (fCurrElement == NULL) // this signals we should ignore attributes for this element |
michael@0 | 154 | return true; |
michael@0 | 155 | if (fCurrElement->fIsDef == false && fCurrElement->fIsNotDef == false) |
michael@0 | 156 | return false; // also an ignored element |
michael@0 | 157 | size_t nameLen = strlen(name); |
michael@0 | 158 | int attrIndex = findAttribute(fCurrElement, name, nameLen, false); |
michael@0 | 159 | if (attrIndex == -1) { |
michael@0 | 160 | attrIndex = findAttribute(&fCurrElement->fPaintState, name, nameLen, true); |
michael@0 | 161 | if (attrIndex >= 0) { |
michael@0 | 162 | fCurrElement->fPaintState.addAttribute(*this, attrIndex, value, len); |
michael@0 | 163 | return false; |
michael@0 | 164 | } |
michael@0 | 165 | if (nameLen == 2 && strncmp("id", name, nameLen) == 0) { |
michael@0 | 166 | fCurrElement->f_id.set(value, len); |
michael@0 | 167 | return false; |
michael@0 | 168 | } |
michael@0 | 169 | if (strchr(name, ':') != 0) // part of a different namespace |
michael@0 | 170 | return false; |
michael@0 | 171 | } |
michael@0 | 172 | SkASSERT(attrIndex >= 0); |
michael@0 | 173 | fCurrElement->addAttribute(*this, attrIndex, value, len); |
michael@0 | 174 | return false; |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | bool SkSVGParser::onEndElement(const char elem[]) { |
michael@0 | 178 | int parentIndex = fParents.count() - 1; |
michael@0 | 179 | if (parentIndex >= 0) { |
michael@0 | 180 | SkSVGElement* element = fParents[parentIndex]; |
michael@0 | 181 | element->onEndElement(*this); |
michael@0 | 182 | fParents.remove(parentIndex); |
michael@0 | 183 | } |
michael@0 | 184 | return false; |
michael@0 | 185 | } |
michael@0 | 186 | |
michael@0 | 187 | bool SkSVGParser::onStartElement(const char name[]) { |
michael@0 | 188 | return onStartElementLen(name, strlen(name)); |
michael@0 | 189 | } |
michael@0 | 190 | |
michael@0 | 191 | bool SkSVGParser::onStartElementLen(const char name[], size_t len) { |
michael@0 | 192 | if (strncmp(name, "svg", len) == 0) { |
michael@0 | 193 | fInSVG = true; |
michael@0 | 194 | } else if (fInSVG == false) |
michael@0 | 195 | return false; |
michael@0 | 196 | const char* nextColon = strchr(name, ':'); |
michael@0 | 197 | if (nextColon && (size_t)(nextColon - name) < len) |
michael@0 | 198 | return false; |
michael@0 | 199 | SkSVGTypes type = GetType(name, len); |
michael@0 | 200 | // SkASSERT(type >= 0); |
michael@0 | 201 | if (type < 0) { |
michael@0 | 202 | type = SkSVGType_G; |
michael@0 | 203 | // return true; |
michael@0 | 204 | } |
michael@0 | 205 | SkSVGElement* parent = fParents.count() > 0 ? fParents.top() : NULL; |
michael@0 | 206 | SkSVGElement* element = CreateElement(type, parent); |
michael@0 | 207 | bool result = false; |
michael@0 | 208 | if (parent) { |
michael@0 | 209 | element->fParent = parent; |
michael@0 | 210 | result = fParents.top()->onStartElement(element); |
michael@0 | 211 | } else |
michael@0 | 212 | *fChildren.append() = element; |
michael@0 | 213 | if (strncmp(name, "svg", len) != 0) |
michael@0 | 214 | *fParents.append() = element; |
michael@0 | 215 | fCurrElement = element; |
michael@0 | 216 | return result; |
michael@0 | 217 | } |
michael@0 | 218 | |
michael@0 | 219 | bool SkSVGParser::onText(const char text[], int len) { |
michael@0 | 220 | if (fInSVG == false) |
michael@0 | 221 | return false; |
michael@0 | 222 | SkSVGTypes type = fCurrElement->getType(); |
michael@0 | 223 | if (type != SkSVGType_Text && type != SkSVGType_Tspan) |
michael@0 | 224 | return false; |
michael@0 | 225 | SkSVGText* textElement = (SkSVGText*) fCurrElement; |
michael@0 | 226 | textElement->f_text.set(text, len); |
michael@0 | 227 | return false; |
michael@0 | 228 | } |
michael@0 | 229 | |
michael@0 | 230 | static int32_t strokeFillID = 0; |
michael@0 | 231 | |
michael@0 | 232 | void SkSVGParser::translate(SkSVGElement* element, bool isDef) { |
michael@0 | 233 | SkSVGPaint::Push(&fHead, &element->fPaintState); |
michael@0 | 234 | bool isFlushable = element->isFlushable(); |
michael@0 | 235 | if ((element->fIsDef == false && element->fIsNotDef == false) || |
michael@0 | 236 | (element->fIsDef && isDef == false && element->fIsNotDef == false) || |
michael@0 | 237 | (element->fIsDef == false && isDef && element->fIsNotDef)) { |
michael@0 | 238 | isFlushable = false; |
michael@0 | 239 | } |
michael@0 | 240 | SkSVGPaint* strokeState = NULL, * fillState = NULL; |
michael@0 | 241 | if (isFlushable) |
michael@0 | 242 | element->fPaintState.setSave(*this); |
michael@0 | 243 | if (isFlushable && isStrokeAndFill(&strokeState, &fillState)) { |
michael@0 | 244 | SkString& elementID = element->f_id; |
michael@0 | 245 | if (elementID.size() == 0) { |
michael@0 | 246 | elementID.set("sf"); |
michael@0 | 247 | elementID.appendS32(++strokeFillID); |
michael@0 | 248 | } |
michael@0 | 249 | SkString saveStroke(strokeState->f_stroke); |
michael@0 | 250 | SkString saveFill(fillState->f_fill); |
michael@0 | 251 | strokeState->f_stroke.set("none"); |
michael@0 | 252 | element->fPaintState.flush(*this, isFlushable, isDef); |
michael@0 | 253 | element->translate(*this, isDef); |
michael@0 | 254 | strokeState->f_stroke.set(saveStroke); |
michael@0 | 255 | fillState->f_fill.set("none"); |
michael@0 | 256 | if (element->fPaintState.flush(*this, isFlushable, isDef)) { |
michael@0 | 257 | _startElement("add"); |
michael@0 | 258 | _addAttributeLen("use", elementID.c_str(), elementID.size()); |
michael@0 | 259 | _endElement(); // add |
michael@0 | 260 | } |
michael@0 | 261 | fillState->f_fill.set(saveFill); |
michael@0 | 262 | } else { |
michael@0 | 263 | element->fPaintState.flush(*this, isFlushable, isDef); |
michael@0 | 264 | if (isFlushable || element->isGroup()) |
michael@0 | 265 | element->translate(*this, isDef); |
michael@0 | 266 | } |
michael@0 | 267 | SkSVGPaint::Pop(&fHead); |
michael@0 | 268 | } |
michael@0 | 269 | |
michael@0 | 270 | void SkSVGParser::translateMatrix(SkString& string, SkString* stringID) { |
michael@0 | 271 | if (string.size() == 0) |
michael@0 | 272 | return; |
michael@0 | 273 | if (stringID->size() > 0) { |
michael@0 | 274 | _startElement("add"); |
michael@0 | 275 | _addAttribute("use", stringID->c_str()); |
michael@0 | 276 | _endElement(); // add |
michael@0 | 277 | return; |
michael@0 | 278 | } |
michael@0 | 279 | SkASSERT(strncmp(string.c_str(), "matrix", 6) == 0); |
michael@0 | 280 | ++gGeneratedMatrixID; |
michael@0 | 281 | _startElement("matrix"); |
michael@0 | 282 | char idStr[24]; |
michael@0 | 283 | strcpy(idStr, "sk_matrix"); |
michael@0 | 284 | sprintf(idStr + strlen(idStr), "%d", gGeneratedMatrixID); |
michael@0 | 285 | _addAttribute("id", idStr); |
michael@0 | 286 | stringID->set(idStr); |
michael@0 | 287 | const char* str = string.c_str(); |
michael@0 | 288 | SkASSERT(strncmp(str, "matrix(", 7) == 0); |
michael@0 | 289 | str += 6; |
michael@0 | 290 | const char* strEnd = strrchr(str, ')'); |
michael@0 | 291 | SkASSERT(strEnd != NULL); |
michael@0 | 292 | SkString mat(str, strEnd - str); |
michael@0 | 293 | ConvertToArray(mat); |
michael@0 | 294 | const char* elems[6]; |
michael@0 | 295 | static const int order[] = {0, 3, 1, 4, 2, 5}; |
michael@0 | 296 | const int* orderPtr = order; |
michael@0 | 297 | str = mat.c_str(); |
michael@0 | 298 | strEnd = str + mat.size(); |
michael@0 | 299 | while (str < strEnd) { |
michael@0 | 300 | elems[*orderPtr++] = str; |
michael@0 | 301 | while (str < strEnd && *str != ',' ) |
michael@0 | 302 | str++; |
michael@0 | 303 | str++; |
michael@0 | 304 | } |
michael@0 | 305 | string.reset(); |
michael@0 | 306 | for (int index = 0; index < 6; index++) { |
michael@0 | 307 | const char* end = strchr(elems[index], ','); |
michael@0 | 308 | if (end == NULL) |
michael@0 | 309 | end= strchr(elems[index], ']'); |
michael@0 | 310 | string.append(elems[index], end - elems[index] + 1); |
michael@0 | 311 | } |
michael@0 | 312 | string.remove(string.size() - 1, 1); |
michael@0 | 313 | string.append(",0,0,1]"); |
michael@0 | 314 | _addAttribute("matrix", string); |
michael@0 | 315 | _endElement(); // matrix |
michael@0 | 316 | } |
michael@0 | 317 | |
michael@0 | 318 | static bool is_whitespace(char ch) { |
michael@0 | 319 | return ch > 0 && ch <= ' '; |
michael@0 | 320 | } |
michael@0 | 321 | |
michael@0 | 322 | void SkSVGParser::ConvertToArray(SkString& vals) { |
michael@0 | 323 | vals.appendUnichar(']'); |
michael@0 | 324 | char* valCh = (char*) vals.c_str(); |
michael@0 | 325 | valCh[0] = '['; |
michael@0 | 326 | int index = 1; |
michael@0 | 327 | while (valCh[index] != ']') { |
michael@0 | 328 | while (is_whitespace(valCh[index])) |
michael@0 | 329 | index++; |
michael@0 | 330 | bool foundComma = false; |
michael@0 | 331 | char next; |
michael@0 | 332 | do { |
michael@0 | 333 | next = valCh[index++]; |
michael@0 | 334 | if (next == ',') { |
michael@0 | 335 | foundComma = true; |
michael@0 | 336 | continue; |
michael@0 | 337 | } |
michael@0 | 338 | if (next == ']') { |
michael@0 | 339 | index--; |
michael@0 | 340 | goto undoLastComma; |
michael@0 | 341 | } |
michael@0 | 342 | if (next == ' ') |
michael@0 | 343 | break; |
michael@0 | 344 | foundComma = false; |
michael@0 | 345 | } while (is_whitespace(next) == false); |
michael@0 | 346 | if (foundComma == false) |
michael@0 | 347 | valCh[index - 1] = ','; |
michael@0 | 348 | } |
michael@0 | 349 | undoLastComma: |
michael@0 | 350 | while (is_whitespace(valCh[--index])) |
michael@0 | 351 | ; |
michael@0 | 352 | if (valCh[index] == ',') |
michael@0 | 353 | valCh[index] = ' '; |
michael@0 | 354 | } |
michael@0 | 355 | |
michael@0 | 356 | #define CASE_NEW(type) case SkSVGType_##type : created = new SkSVG##type(); break |
michael@0 | 357 | |
michael@0 | 358 | SkSVGElement* SkSVGParser::CreateElement(SkSVGTypes type, SkSVGElement* parent) { |
michael@0 | 359 | SkSVGElement* created = NULL; |
michael@0 | 360 | switch (type) { |
michael@0 | 361 | CASE_NEW(Circle); |
michael@0 | 362 | CASE_NEW(ClipPath); |
michael@0 | 363 | CASE_NEW(Defs); |
michael@0 | 364 | CASE_NEW(Ellipse); |
michael@0 | 365 | CASE_NEW(FeColorMatrix); |
michael@0 | 366 | CASE_NEW(Filter); |
michael@0 | 367 | CASE_NEW(G); |
michael@0 | 368 | CASE_NEW(Image); |
michael@0 | 369 | CASE_NEW(Line); |
michael@0 | 370 | CASE_NEW(LinearGradient); |
michael@0 | 371 | CASE_NEW(Mask); |
michael@0 | 372 | CASE_NEW(Metadata); |
michael@0 | 373 | CASE_NEW(Path); |
michael@0 | 374 | CASE_NEW(Polygon); |
michael@0 | 375 | CASE_NEW(Polyline); |
michael@0 | 376 | CASE_NEW(RadialGradient); |
michael@0 | 377 | CASE_NEW(Rect); |
michael@0 | 378 | CASE_NEW(Stop); |
michael@0 | 379 | CASE_NEW(SVG); |
michael@0 | 380 | CASE_NEW(Symbol); |
michael@0 | 381 | CASE_NEW(Text); |
michael@0 | 382 | CASE_NEW(Tspan); |
michael@0 | 383 | CASE_NEW(Use); |
michael@0 | 384 | default: |
michael@0 | 385 | SkASSERT(0); |
michael@0 | 386 | return NULL; |
michael@0 | 387 | } |
michael@0 | 388 | created->fParent = parent; |
michael@0 | 389 | bool isDef = created->fIsDef = created->isDef(); |
michael@0 | 390 | bool isNotDef = created->fIsNotDef = created->isNotDef(); |
michael@0 | 391 | if (isDef) { |
michael@0 | 392 | SkSVGElement* up = parent; |
michael@0 | 393 | while (up && up->fIsDef == false) { |
michael@0 | 394 | up->fIsDef = true; |
michael@0 | 395 | up = up->fParent; |
michael@0 | 396 | } |
michael@0 | 397 | } |
michael@0 | 398 | if (isNotDef) { |
michael@0 | 399 | SkSVGElement* up = parent; |
michael@0 | 400 | while (up && up->fIsNotDef == false) { |
michael@0 | 401 | up->fIsNotDef = true; |
michael@0 | 402 | up = up->fParent; |
michael@0 | 403 | } |
michael@0 | 404 | } |
michael@0 | 405 | return created; |
michael@0 | 406 | } |
michael@0 | 407 | |
michael@0 | 408 | const SkSVGTypeName gSVGTypeNames[] = { |
michael@0 | 409 | {"circle", SkSVGType_Circle}, |
michael@0 | 410 | {"clipPath", SkSVGType_ClipPath}, |
michael@0 | 411 | {"defs", SkSVGType_Defs}, |
michael@0 | 412 | {"ellipse", SkSVGType_Ellipse}, |
michael@0 | 413 | {"feColorMatrix", SkSVGType_FeColorMatrix}, |
michael@0 | 414 | {"filter", SkSVGType_Filter}, |
michael@0 | 415 | {"g", SkSVGType_G}, |
michael@0 | 416 | {"image", SkSVGType_Image}, |
michael@0 | 417 | {"line", SkSVGType_Line}, |
michael@0 | 418 | {"linearGradient", SkSVGType_LinearGradient}, |
michael@0 | 419 | {"mask", SkSVGType_Mask}, |
michael@0 | 420 | {"metadata", SkSVGType_Metadata}, |
michael@0 | 421 | {"path", SkSVGType_Path}, |
michael@0 | 422 | {"polygon", SkSVGType_Polygon}, |
michael@0 | 423 | {"polyline", SkSVGType_Polyline}, |
michael@0 | 424 | {"radialGradient", SkSVGType_RadialGradient}, |
michael@0 | 425 | {"rect", SkSVGType_Rect}, |
michael@0 | 426 | {"stop", SkSVGType_Stop}, |
michael@0 | 427 | {"svg", SkSVGType_SVG}, |
michael@0 | 428 | {"symbol", SkSVGType_Symbol}, |
michael@0 | 429 | {"text", SkSVGType_Text}, |
michael@0 | 430 | {"tspan", SkSVGType_Tspan}, |
michael@0 | 431 | {"use", SkSVGType_Use} |
michael@0 | 432 | }; |
michael@0 | 433 | |
michael@0 | 434 | const int kSVGTypeNamesSize = SK_ARRAY_COUNT(gSVGTypeNames); |
michael@0 | 435 | |
michael@0 | 436 | SkSVGTypes SkSVGParser::GetType(const char match[], size_t len ) { |
michael@0 | 437 | int index = SkStrSearch(&gSVGTypeNames[0].fName, kSVGTypeNamesSize, match, |
michael@0 | 438 | len, sizeof(gSVGTypeNames[0])); |
michael@0 | 439 | return index >= 0 && index < kSVGTypeNamesSize ? gSVGTypeNames[index].fType : |
michael@0 | 440 | (SkSVGTypes) -1; |
michael@0 | 441 | } |