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