| OLD | NEW |
| (Empty) |
| 1 /* libs/graphics/svg/SkSVGPaintState.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 "SkSVGPaintState.h" | |
| 19 #include "SkSVGElements.h" | |
| 20 #include "SkSVGParser.h" | |
| 21 #include "SkParse.h" | |
| 22 | |
| 23 SkSVGAttribute SkSVGPaint::gAttributes[] = { | |
| 24 SVG_LITERAL_ATTRIBUTE(clip-path, f_clipPath), | |
| 25 SVG_LITERAL_ATTRIBUTE(clip-rule, f_clipRule), | |
| 26 SVG_LITERAL_ATTRIBUTE(enable-background, f_enableBackground), | |
| 27 SVG_ATTRIBUTE(fill), | |
| 28 SVG_LITERAL_ATTRIBUTE(fill-rule, f_fillRule), | |
| 29 SVG_ATTRIBUTE(filter), | |
| 30 SVG_LITERAL_ATTRIBUTE(font-family, f_fontFamily), | |
| 31 SVG_LITERAL_ATTRIBUTE(font-size, f_fontSize), | |
| 32 SVG_LITERAL_ATTRIBUTE(letter-spacing, f_letterSpacing), | |
| 33 SVG_ATTRIBUTE(mask), | |
| 34 SVG_ATTRIBUTE(opacity), | |
| 35 SVG_LITERAL_ATTRIBUTE(stop-color, f_stopColor), | |
| 36 SVG_LITERAL_ATTRIBUTE(stop-opacity, f_stopOpacity), | |
| 37 SVG_ATTRIBUTE(stroke), | |
| 38 SVG_LITERAL_ATTRIBUTE(stroke-dasharray, f_strokeDasharray), | |
| 39 SVG_LITERAL_ATTRIBUTE(stroke-linecap, f_strokeLinecap), | |
| 40 SVG_LITERAL_ATTRIBUTE(stroke-linejoin, f_strokeLinejoin), | |
| 41 SVG_LITERAL_ATTRIBUTE(stroke-miterlimit, f_strokeMiterlimit), | |
| 42 SVG_LITERAL_ATTRIBUTE(stroke-width, f_strokeWidth), | |
| 43 SVG_ATTRIBUTE(style), | |
| 44 SVG_ATTRIBUTE(transform) | |
| 45 }; | |
| 46 | |
| 47 const int SkSVGPaint::kAttributesSize = SK_ARRAY_COUNT(SkSVGPaint::gAttributes); | |
| 48 | |
| 49 SkSVGPaint::SkSVGPaint() : fNext(NULL) { | |
| 50 } | |
| 51 | |
| 52 SkString* SkSVGPaint::operator[](int index) { | |
| 53 SkASSERT(index >= 0); | |
| 54 SkASSERT(index < &fTerminal - &fInitial); | |
| 55 SkASSERT(&fTerminal - &fInitial == kTerminal - kInitial); | |
| 56 SkString* result = &fInitial + index + 1; | |
| 57 return result; | |
| 58 } | |
| 59 | |
| 60 void SkSVGPaint::addAttribute(SkSVGParser& parser, int attrIndex, | |
| 61 const char* attrValue, size_t attrLength) { | |
| 62 SkString* attr = (*this)[attrIndex]; | |
| 63 switch(attrIndex) { | |
| 64 case kClipPath: | |
| 65 case kClipRule: | |
| 66 case kEnableBackground: | |
| 67 case kFill: | |
| 68 case kFillRule: | |
| 69 case kFilter: | |
| 70 case kFontFamily: | |
| 71 case kFontSize: | |
| 72 case kLetterSpacing: | |
| 73 case kMask: | |
| 74 case kOpacity: | |
| 75 case kStopColor: | |
| 76 case kStopOpacity: | |
| 77 case kStroke: | |
| 78 case kStroke_Dasharray: | |
| 79 case kStroke_Linecap: | |
| 80 case kStroke_Linejoin: | |
| 81 case kStroke_Miterlimit: | |
| 82 case kStroke_Width: | |
| 83 case kTransform: | |
| 84 attr->set(attrValue, attrLength); | |
| 85 return; | |
| 86 case kStyle: { | |
| 87 // iterate through colon / semi-colon delimited pairs | |
| 88 int pairs = SkParse::Count(attrValue, ';'); | |
| 89 const char* attrEnd = attrValue + attrLength; | |
| 90 do { | |
| 91 const char* end = strchr(attrValue, ';'); | |
| 92 if (end == NULL) | |
| 93 end = attrEnd; | |
| 94 const char* delimiter = strchr(attrValue, ':'); | |
| 95 SkASSERT(delimiter != 0 && delimiter < end); | |
| 96 int index = parser.findAttribute(this, attrValue, (int) (delimit
er - attrValue), true); | |
| 97 SkASSERT(index >= 0); | |
| 98 delimiter++; | |
| 99 addAttribute(parser, index, delimiter, (int) (end - delimiter)); | |
| 100 attrValue = end + 1; | |
| 101 } while (--pairs); | |
| 102 return; | |
| 103 } | |
| 104 default: | |
| 105 SkASSERT(0); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 bool SkSVGPaint::flush(SkSVGParser& parser, bool isFlushable, bool isDef) { | |
| 110 SkSVGPaint current; | |
| 111 SkSVGPaint* walking = parser.fHead; | |
| 112 int index; | |
| 113 while (walking != NULL) { | |
| 114 for (index = kInitial + 1; index < kTerminal; index++) { | |
| 115 SkString* lastAttr = (*walking)[index]; | |
| 116 if (lastAttr->size() == 0) | |
| 117 continue; | |
| 118 if (current[index]->size() > 0) | |
| 119 continue; | |
| 120 current[index]->set(*lastAttr); | |
| 121 } | |
| 122 walking = walking->fNext; | |
| 123 } | |
| 124 bool paintChanged = false; | |
| 125 SkSVGPaint& lastState = parser.fLastFlush; | |
| 126 if (isFlushable == false) { | |
| 127 if (isDef == true) { | |
| 128 if (current.f_mask.size() > 0 && current.f_mask.equals(lastState.f_m
ask) == false) { | |
| 129 SkSVGElement* found; | |
| 130 const char* idStart = strchr(current.f_mask.c_str(), '#'); | |
| 131 SkASSERT(idStart); | |
| 132 SkString id(idStart + 1, strlen(idStart) - 2); | |
| 133 bool itsFound = parser.fIDs.find(id.c_str(), &found); | |
| 134 SkASSERT(itsFound); | |
| 135 SkSVGElement* gradient = found->getGradient(); | |
| 136 if (gradient) { | |
| 137 gradient->write(parser, current.f_fill); | |
| 138 gradient->write(parser, current.f_stroke); | |
| 139 } | |
| 140 } | |
| 141 } | |
| 142 goto setLast; | |
| 143 } | |
| 144 { | |
| 145 bool changed[kTerminal]; | |
| 146 memset(changed, 0, sizeof(changed)); | |
| 147 for (index = kInitial + 1; index < kTerminal; index++) { | |
| 148 if (index == kTransform || index == kClipPath || index == kStopColor
|| index == kStopOpacity || | |
| 149 index == kClipRule || index == kFillRule) | |
| 150 continue; | |
| 151 SkString* lastAttr = lastState[index]; | |
| 152 SkString* currentAttr = current[index]; | |
| 153 paintChanged |= changed[index] = lastAttr->equals(*currentAttr) == f
alse; | |
| 154 } | |
| 155 if (paintChanged) { | |
| 156 if (current.f_mask.size() > 0) { | |
| 157 if (current.f_fill.equals("none") == false && strncmp(current.f_
fill.c_str(), "url(#", 5) != 0) { | |
| 158 SkASSERT(current.f_fill.c_str()[0] == '#'); | |
| 159 SkString replacement("url(#mask"); | |
| 160 replacement.append(current.f_fill.c_str() + 1); | |
| 161 replacement.appendUnichar(')'); | |
| 162 current.f_fill.set(replacement); | |
| 163 } | |
| 164 if (current.f_stroke.equals("none") == false && strncmp(current.
f_stroke.c_str(), "url(#", 5) != 0) { | |
| 165 SkASSERT(current.f_stroke.c_str()[0] == '#'); | |
| 166 SkString replacement("url(#mask"); | |
| 167 replacement.append(current.f_stroke.c_str() + 1); | |
| 168 replacement.appendUnichar(')'); | |
| 169 current.f_stroke.set(replacement); | |
| 170 } | |
| 171 } | |
| 172 if (current.f_fill.equals("none") && current.f_stroke.equals("none")
) | |
| 173 current.f_opacity.set("0"); | |
| 174 if (parser.fSuppressPaint == false) { | |
| 175 parser._startElement("paint"); | |
| 176 bool success = writeChangedAttributes(parser, current, changed); | |
| 177 if (success == false) | |
| 178 return paintChanged; | |
| 179 success = writeChangedElements(parser, current, changed); | |
| 180 if (success == false) | |
| 181 return paintChanged; | |
| 182 parser._endElement(); // paint | |
| 183 } | |
| 184 } | |
| 185 } | |
| 186 setLast: | |
| 187 for (index = kInitial + 1; index < kTerminal; index++) { | |
| 188 SkString* lastAttr = lastState[index]; | |
| 189 SkString* currentAttr = current[index]; | |
| 190 lastAttr->set(*currentAttr); | |
| 191 } | |
| 192 return paintChanged; | |
| 193 } | |
| 194 | |
| 195 int SkSVGPaint::getAttributes(const SkSVGAttribute** attrPtr) { | |
| 196 *attrPtr = gAttributes; | |
| 197 return kAttributesSize; | |
| 198 } | |
| 199 | |
| 200 void SkSVGPaint::setSave(SkSVGParser& parser) { | |
| 201 SkTDArray<SkString*> clips; | |
| 202 SkSVGPaint* walking = parser.fHead; | |
| 203 int index; | |
| 204 SkMatrix sum; | |
| 205 sum.reset(); | |
| 206 while (walking != NULL) { | |
| 207 for (index = kInitial + 1; index < kTerminal; index++) { | |
| 208 SkString* lastAttr = (*walking)[index]; | |
| 209 if (lastAttr->size() == 0) | |
| 210 continue; | |
| 211 if (index == kTransform) { | |
| 212 const char* str = lastAttr->c_str(); | |
| 213 SkASSERT(strncmp(str, "matrix(", 7) == 0); | |
| 214 str += 6; | |
| 215 const char* strEnd = strrchr(str, ')'); | |
| 216 SkASSERT(strEnd != NULL); | |
| 217 SkString mat(str, strEnd - str); | |
| 218 SkSVGParser::ConvertToArray(mat); | |
| 219 SkScalar values[6]; | |
| 220 SkParse::FindScalars(mat.c_str() + 1, values, 6); | |
| 221 SkMatrix matrix; | |
| 222 matrix.reset(); | |
| 223 matrix.setScaleX(values[0]); | |
| 224 matrix.setSkewY(values[1]); | |
| 225 matrix.setSkewX(values[2]); | |
| 226 matrix.setScaleY(values[3]); | |
| 227 matrix.setTranslateX(values[4]); | |
| 228 matrix.setTranslateY(values[5]); | |
| 229 sum.setConcat(matrix, sum); | |
| 230 continue; | |
| 231 } | |
| 232 if ( index == kClipPath) | |
| 233 *clips.insert(0) = lastAttr; | |
| 234 } | |
| 235 walking = walking->fNext; | |
| 236 } | |
| 237 if ((sum == parser.fLastTransform) == false) { | |
| 238 SkMatrix inverse; | |
| 239 bool success = parser.fLastTransform.invert(&inverse); | |
| 240 SkASSERT(success == true); | |
| 241 SkMatrix output; | |
| 242 output.setConcat(inverse, sum); | |
| 243 parser.fLastTransform = sum; | |
| 244 SkString outputStr; | |
| 245 outputStr.appendUnichar('['); | |
| 246 outputStr.appendScalar(output.getScaleX()); | |
| 247 outputStr.appendUnichar(','); | |
| 248 outputStr.appendScalar(output.getSkewX()); | |
| 249 outputStr.appendUnichar(','); | |
| 250 outputStr.appendScalar(output.getTranslateX()); | |
| 251 outputStr.appendUnichar(','); | |
| 252 outputStr.appendScalar(output.getSkewY()); | |
| 253 outputStr.appendUnichar(','); | |
| 254 outputStr.appendScalar(output.getScaleY()); | |
| 255 outputStr.appendUnichar(','); | |
| 256 outputStr.appendScalar(output.getTranslateY()); | |
| 257 outputStr.appendUnichar(','); | |
| 258 outputStr.appendScalar(output.getPerspX()); | |
| 259 outputStr.appendUnichar(','); | |
| 260 outputStr.appendScalar(output.getPerspY()); | |
| 261 outputStr.append(",1]"); | |
| 262 parser._startElement("matrix"); | |
| 263 parser._addAttributeLen("matrix", outputStr.c_str(), outputStr.size()); | |
| 264 parser._endElement(); | |
| 265 } | |
| 266 #if 0 // incomplete | |
| 267 if (parser.fTransformClips.size() > 0) { | |
| 268 // need to reset the clip when the 'g' scope is ended | |
| 269 parser._startElement("add"); | |
| 270 const char* start = strchr(current->f_clipPath.c_str(), '#') + 1; | |
| 271 SkASSERT(start); | |
| 272 parser._addAttributeLen("use", start, strlen(start) - 1); | |
| 273 parser._endElement(); // clip | |
| 274 } | |
| 275 #endif | |
| 276 } | |
| 277 | |
| 278 bool SkSVGPaint::writeChangedAttributes(SkSVGParser& parser, | |
| 279 SkSVGPaint& current, bool* changed) { | |
| 280 SkSVGPaint& lastState = parser.fLastFlush; | |
| 281 for (int index = kInitial + 1; index < kTerminal; index++) { | |
| 282 if (changed[index] == false) | |
| 283 continue; | |
| 284 SkString* topAttr = current[index]; | |
| 285 size_t attrLength = topAttr->size(); | |
| 286 if (attrLength == 0) | |
| 287 continue; | |
| 288 const char* attrValue = topAttr->c_str(); | |
| 289 SkString* lastAttr = lastState[index]; | |
| 290 switch(index) { | |
| 291 case kClipPath: | |
| 292 case kClipRule: | |
| 293 case kEnableBackground: | |
| 294 break; | |
| 295 case kFill: | |
| 296 if (topAttr->equals("none") == false && lastAttr->equals("none")
== true) | |
| 297 parser._addAttribute("stroke", "false"); | |
| 298 goto fillStrokeAttrCommon; | |
| 299 case kFillRule: | |
| 300 case kFilter: | |
| 301 case kFontFamily: | |
| 302 break; | |
| 303 case kFontSize: | |
| 304 parser._addAttributeLen("textSize", attrValue, attrLength); | |
| 305 break; | |
| 306 case kLetterSpacing: | |
| 307 parser._addAttributeLen("textTracking", attrValue, attrLength); | |
| 308 break; | |
| 309 case kMask: | |
| 310 break; | |
| 311 case kOpacity: | |
| 312 break; | |
| 313 case kStopColor: | |
| 314 break; | |
| 315 case kStopOpacity: | |
| 316 break; | |
| 317 case kStroke: | |
| 318 if (topAttr->equals("none") == false && lastAttr->equals("none")
== true) | |
| 319 parser._addAttribute("stroke", "true"); | |
| 320 fillStrokeAttrCommon: | |
| 321 if (strncmp(attrValue, "url(", 4) == 0) { | |
| 322 SkASSERT(attrValue[4] == '#'); | |
| 323 const char* idStart = attrValue + 5; | |
| 324 char* idEnd = strrchr(attrValue, ')'); | |
| 325 SkASSERT(idStart < idEnd); | |
| 326 SkString id(idStart, idEnd - idStart); | |
| 327 SkSVGElement* found; | |
| 328 if (strncmp(id.c_str(), "mask", 4) != 0) { | |
| 329 bool itsFound = parser.fIDs.find(id.c_str(), &found); | |
| 330 SkASSERT(itsFound); | |
| 331 SkASSERT(found->getType() == SkSVGType_LinearGradient || | |
| 332 found->getType() == SkSVGType_RadialGradient); | |
| 333 } | |
| 334 parser._addAttribute("shader", id.c_str()); | |
| 335 } | |
| 336 break; | |
| 337 case kStroke_Dasharray: | |
| 338 break; | |
| 339 case kStroke_Linecap: | |
| 340 parser._addAttributeLen("strokeCap", attrValue, attrLength); | |
| 341 break; | |
| 342 case kStroke_Linejoin: | |
| 343 parser._addAttributeLen("strokeJoin", attrValue, attrLength); | |
| 344 break; | |
| 345 case kStroke_Miterlimit: | |
| 346 parser._addAttributeLen("strokeMiter", attrValue, attrLength); | |
| 347 break; | |
| 348 case kStroke_Width: | |
| 349 parser._addAttributeLen("strokeWidth", attrValue, attrLength); | |
| 350 case kStyle: | |
| 351 case kTransform: | |
| 352 break; | |
| 353 default: | |
| 354 SkASSERT(0); | |
| 355 return false; | |
| 356 } | |
| 357 } | |
| 358 return true; | |
| 359 } | |
| 360 | |
| 361 bool SkSVGPaint::writeChangedElements(SkSVGParser& parser, | |
| 362 SkSVGPaint& current, bool* changed) { | |
| 363 SkSVGPaint& lastState = parser.fLastFlush; | |
| 364 for (int index = kInitial + 1; index < kTerminal; index++) { | |
| 365 SkString* topAttr = current[index]; | |
| 366 size_t attrLength = topAttr->size(); | |
| 367 if (attrLength == 0) | |
| 368 continue; | |
| 369 const char* attrValue = topAttr->c_str(); | |
| 370 SkString* lastAttr = lastState[index]; | |
| 371 switch(index) { | |
| 372 case kClipPath: | |
| 373 case kClipRule: | |
| 374 // !!! need to add this outside of paint | |
| 375 break; | |
| 376 case kEnableBackground: | |
| 377 // !!! don't know what to do with this | |
| 378 break; | |
| 379 case kFill: | |
| 380 goto addColor; | |
| 381 case kFillRule: | |
| 382 case kFilter: | |
| 383 break; | |
| 384 case kFontFamily: | |
| 385 parser._startElement("typeface"); | |
| 386 parser._addAttributeLen("fontName", attrValue, attrLength); | |
| 387 parser._endElement(); // typeface | |
| 388 break; | |
| 389 case kFontSize: | |
| 390 case kLetterSpacing: | |
| 391 break; | |
| 392 case kMask: | |
| 393 case kOpacity: | |
| 394 if (changed[kStroke] == false && changed[kFill] == false) { | |
| 395 parser._startElement("color"); | |
| 396 SkString& opacity = current.f_opacity; | |
| 397 parser._addAttributeLen("color", parser.fLastColor.c_str(),
parser.fLastColor.size()); | |
| 398 parser._addAttributeLen("alpha", opacity.c_str(), opacity.si
ze()); | |
| 399 parser._endElement(); // color | |
| 400 } | |
| 401 break; | |
| 402 case kStopColor: | |
| 403 break; | |
| 404 case kStopOpacity: | |
| 405 break; | |
| 406 case kStroke: | |
| 407 addColor: | |
| 408 if (strncmp(lastAttr->c_str(), "url(", 4) == 0 && strncmp(attrVa
lue, "url(", 4) != 0) { | |
| 409 parser._startElement("shader"); | |
| 410 parser._endElement(); | |
| 411 } | |
| 412 if (topAttr->equals(*lastAttr)) | |
| 413 continue; | |
| 414 { | |
| 415 bool urlRef = strncmp(attrValue, "url(", 4) == 0; | |
| 416 bool colorNone = strcmp(attrValue, "none") == 0; | |
| 417 bool lastEqual = parser.fLastColor.equals(attrValue, attrLen
gth); | |
| 418 bool newColor = urlRef == false && colorNone == false && las
tEqual == false; | |
| 419 if (newColor || changed[kOpacity]) { | |
| 420 parser._startElement("color"); | |
| 421 if (newColor || changed[kOpacity]) { | |
| 422 parser._addAttributeLen("color", attrValue, attrLeng
th); | |
| 423 parser.fLastColor.set(attrValue, attrLength); | |
| 424 } | |
| 425 if (changed[kOpacity]) { | |
| 426 SkString& opacity = current.f_opacity; | |
| 427 parser._addAttributeLen("alpha", opacity.c_str(), op
acity.size()); | |
| 428 } | |
| 429 parser._endElement(); // color | |
| 430 } | |
| 431 } | |
| 432 break; | |
| 433 case kStroke_Dasharray: | |
| 434 parser._startElement("dash"); | |
| 435 SkSVGParser::ConvertToArray(*topAttr); | |
| 436 parser._addAttribute("intervals", topAttr->c_str()); | |
| 437 parser._endElement(); // dash | |
| 438 break; | |
| 439 case kStroke_Linecap: | |
| 440 case kStroke_Linejoin: | |
| 441 case kStroke_Miterlimit: | |
| 442 case kStroke_Width: | |
| 443 case kStyle: | |
| 444 case kTransform: | |
| 445 break; | |
| 446 default: | |
| 447 SkASSERT(0); | |
| 448 return false; | |
| 449 } | |
| 450 } | |
| 451 return true; | |
| 452 } | |
| 453 | |
| 454 void SkSVGPaint::Push(SkSVGPaint** head, SkSVGPaint* newRecord) { | |
| 455 newRecord->fNext = *head; | |
| 456 *head = newRecord; | |
| 457 } | |
| 458 | |
| 459 void SkSVGPaint::Pop(SkSVGPaint** head) { | |
| 460 SkSVGPaint* next = (*head)->fNext; | |
| 461 *head = next; | |
| 462 } | |
| 463 | |
| OLD | NEW |