gfx/skia/trunk/src/svg/SkSVGParser.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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 }

mercurial