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