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