void SkSVGUse::translate(SkSVGParser& parser, bool defState) { INHERITED::translate(parser, defState); parser._startElement("add"); const char* start = strchr(f_xlink_href.c_str(), '#') + 1; SkASSERT(start); parser._addAttributeLen("use", start, strlen(start) - 1); parser._endElement(); // clip }
void SkSVGPolygon::translate(SkSVGParser& parser, bool defState) { parser._startElement("polygon"); SkSVGElement::translate(parser, defState); SVG_ADD_ATTRIBUTE(points); if (f_fillRule.size() > 0) parser._addAttribute("fillType", f_fillRule.equals("evenodd") ? "evenOdd" : "winding"); parser._endElement(); }
void SkSVGImage::translate(SkSVGParser& parser, bool defState) { parser._startElement("image"); INHERITED::translate(parser, defState); SVG_ADD_ATTRIBUTE(x); SVG_ADD_ATTRIBUTE(y); // SVG_ADD_ATTRIBUTE(width); // SVG_ADD_ATTRIBUTE(height); translateImage(parser); parser._endElement(); }
void SkSVGClipPath::translate(SkSVGParser& parser, bool defState) { parser._startElement("clip"); INHERITED::translate(parser, defState); SkASSERT(fChildren.count() == 1); SkSVGElement* child = *fChildren.begin(); SkASSERT(child->getType() == SkSVGType_Use); SkSVGUse* use = (SkSVGUse*) child; SkSVGElement* ref = NULL; const char* refStr = &use->f_xlink_href.c_str()[1]; SkASSERT(parser.getIDs().find(refStr, &ref)); SkASSERT(ref); if (ref->getType() == SkSVGType_Rect) parser._addAttribute("rectangle", refStr); else parser._addAttribute("path", refStr); parser._endElement(); }
void SkSVGPath::translate(SkSVGParser& parser, bool defState) { parser._startElement("path"); INHERITED::translate(parser, defState); bool hasMultiplePaths = false; const char* firstZ = strchr(f_d.c_str(), 'z'); if (firstZ != nullptr) { firstZ++; // skip over 'z' while (*firstZ == ' ') firstZ++; hasMultiplePaths = *firstZ != '\0'; } if (hasMultiplePaths) { SkString& fillRule = parser.getPaintLast(SkSVGPaint::kFillRule); if (fillRule.size() > 0) parser._addAttribute("fillType", fillRule.equals("evenodd") ? "evenOdd" : "winding"); } SVG_ADD_ATTRIBUTE(d); parser._endElement(); }
void SkSVGImage::translateImage(SkSVGParser& parser) { SkASSERT(f_xlink_href.size() > 0); const char* data = f_xlink_href.c_str(); SkASSERT(strncmp(data, "data:image/", 11) == 0); data += 11; SkASSERT(strncmp(data, "png;", 4) == 0 || strncmp(data, "jpeg;", 5) == 0); data = strchr(data, ';'); SkASSERT(strncmp(data, ";base64,", 8) == 0); data += 8; parser._addAttribute("base64", data); }
void SkSVGLinearGradient::translate(SkSVGParser& parser, bool defState) { if (fMatrixID.size() == 0) parser.translateMatrix(f_gradientTransform, &fMatrixID); parser._startElement("linearGradient"); if (fMatrixID.size() > 0) parser._addAttribute("matrix", fMatrixID); INHERITED::translateGradientUnits(f_gradientUnits); SkString points; points.appendUnichar('['); points.append(f_x1); points.appendUnichar(','); points.append(f_y1); points.appendUnichar(','); points.append(f_x2); points.appendUnichar(','); points.append(f_y2); points.appendUnichar(']'); parser._addAttribute("points", points.c_str()); INHERITED::translate(parser, defState); parser._endElement(); }
void SkSVGPaint::addAttribute(SkSVGParser& parser, int attrIndex, const char* attrValue, size_t attrLength) { SkString* attr = (*this)[attrIndex]; switch(attrIndex) { case kClipPath: case kClipRule: case kEnableBackground: case kFill: case kFillRule: case kFilter: case kFontFamily: case kFontSize: case kLetterSpacing: case kMask: case kOpacity: case kStopColor: case kStopOpacity: case kStroke: case kStroke_Dasharray: case kStroke_Linecap: case kStroke_Linejoin: case kStroke_Miterlimit: case kStroke_Width: case kTransform: attr->set(attrValue, attrLength); return; case kStyle: { // iterate through colon / semi-colon delimited pairs int pairs = SkParse::Count(attrValue, ';'); const char* attrEnd = attrValue + attrLength; do { const char* end = strchr(attrValue, ';'); if (end == NULL) end = attrEnd; const char* delimiter = strchr(attrValue, ':'); SkASSERT(delimiter != 0 && delimiter < end); int index = parser.findAttribute(this, attrValue, (int) (delimiter - attrValue), true); SkASSERT(index >= 0); delimiter++; addAttribute(parser, index, delimiter, (int) (end - delimiter)); attrValue = end + 1; } while (--pairs); return; } default: SkASSERT(0); } }
void SkSVGRadialGradient::translate(SkSVGParser& parser, bool defState) { if (fMatrixID.size() == 0) parser.translateMatrix(f_gradientTransform, &fMatrixID); parser._startElement("radialGradient"); if (fMatrixID.size() > 0) parser._addAttribute("matrix", fMatrixID); INHERITED::translateGradientUnits(f_gradientUnits); SkString center; center.appendUnichar('['); center.append(f_cx); center.appendUnichar(','); center.append(f_cy); center.appendUnichar(']'); parser._addAttribute("center", center); parser._addAttribute("radius", f_r); INHERITED::translate(parser, defState); parser._endElement(); }
void SkSVGSVG::translate(SkSVGParser& parser, bool defState) { SkScalar height, width; SkScalar viewBox[4]; const char* hSuffix = SkParse::FindScalar(f_height.c_str(), &height); if (strcmp(hSuffix, "pt") == 0) height = SkScalarMulDiv(height, SK_Scalar1 * 72, SK_Scalar1 * 96); const char* wSuffix = SkParse::FindScalar(f_width.c_str(), &width); if (strcmp(wSuffix, "pt") == 0) width = SkScalarMulDiv(width, SK_Scalar1 * 72, SK_Scalar1 * 96); SkParse::FindScalars(f_viewBox.c_str(), viewBox, 4); SkRect box; box.fLeft = SkScalarDiv(viewBox[0], width); box.fTop = SkScalarDiv(viewBox[1], height); box.fRight = SkScalarDiv(viewBox[2], width); box.fBottom = SkScalarDiv(viewBox[3], height); if (box.fLeft == 0 && box.fTop == 0 && box.fRight == SK_Scalar1 && box.fBottom == SK_Scalar1) return; parser._startElement("matrix"); if (box.fLeft != 0) { SkString x; x.appendScalar(box.fLeft); parser._addAttributeLen("translateX", x.c_str(), x.size()); } if (box.fTop != 0) { SkString y; y.appendScalar(box.fTop); parser._addAttributeLen("translateY", y.c_str(), y.size()); } if (box.fRight != SK_Scalar1) { SkString x; x.appendScalar(box.fRight); parser._addAttributeLen("scaleX", x.c_str(), x.size()); } if (box.fBottom != SK_Scalar1) { SkString y; y.appendScalar(box.fBottom); parser._addAttributeLen("scaleY", y.c_str(), y.size()); } parser._endElement(); }
void SkSVGEllipse::translate(SkSVGParser& parser, bool defState) { parser._startElement("oval"); INHERITED::translate(parser, defState); SkScalar cx, cy, rx, ry; SkParse::FindScalar(f_cx.c_str(), &cx); SkParse::FindScalar(f_cy.c_str(), &cy); SkParse::FindScalar(f_rx.c_str(), &rx); SkParse::FindScalar(f_ry.c_str(), &ry); SkScalar left, top, right, bottom; left = cx - rx; top = cy - ry; right = cx + rx; bottom = cy + ry; char scratch[16]; sprintf(scratch, "%g", left); parser._addAttribute("left", scratch); sprintf(scratch, "%g", top); parser._addAttribute("top", scratch); sprintf(scratch, "%g", right); parser._addAttribute("right", scratch); sprintf(scratch, "%g", bottom); parser._addAttribute("bottom", scratch); parser._endElement(); }
bool SkSVGPaint::flush(SkSVGParser& parser, bool isFlushable, bool isDef) { SkSVGPaint current; SkSVGPaint* walking = parser.fHead; int index; while (walking != NULL) { for (index = kInitial + 1; index < kTerminal; index++) { SkString* lastAttr = (*walking)[index]; if (lastAttr->size() == 0) continue; if (current[index]->size() > 0) continue; current[index]->set(*lastAttr); } walking = walking->fNext; } bool paintChanged = false; SkSVGPaint& lastState = parser.fLastFlush; if (isFlushable == false) { if (isDef == true) { if (current.f_mask.size() > 0 && current.f_mask.equals(lastState.f_mask) == false) { SkSVGElement* found; const char* idStart = strchr(current.f_mask.c_str(), '#'); SkASSERT(idStart); SkString id(idStart + 1, strlen(idStart) - 2); bool itsFound = parser.fIDs.find(id.c_str(), &found); SkASSERT(itsFound); SkSVGElement* gradient = found->getGradient(); if (gradient) { gradient->write(parser, current.f_fill); gradient->write(parser, current.f_stroke); } } } goto setLast; } { bool changed[kTerminal]; memset(changed, 0, sizeof(changed)); for (index = kInitial + 1; index < kTerminal; index++) { if (index == kTransform || index == kClipPath || index == kStopColor || index == kStopOpacity || index == kClipRule || index == kFillRule) continue; SkString* lastAttr = lastState[index]; SkString* currentAttr = current[index]; paintChanged |= changed[index] = lastAttr->equals(*currentAttr) == false; } if (paintChanged) { if (current.f_mask.size() > 0) { if (current.f_fill.equals("none") == false && strncmp(current.f_fill.c_str(), "url(#", 5) != 0) { SkASSERT(current.f_fill.c_str()[0] == '#'); SkString replacement("url(#mask"); replacement.append(current.f_fill.c_str() + 1); replacement.appendUnichar(')'); current.f_fill.set(replacement); } if (current.f_stroke.equals("none") == false && strncmp(current.f_stroke.c_str(), "url(#", 5) != 0) { SkASSERT(current.f_stroke.c_str()[0] == '#'); SkString replacement("url(#mask"); replacement.append(current.f_stroke.c_str() + 1); replacement.appendUnichar(')'); current.f_stroke.set(replacement); } } if (current.f_fill.equals("none") && current.f_stroke.equals("none")) current.f_opacity.set("0"); if (parser.fSuppressPaint == false) { parser._startElement("paint"); bool success = writeChangedAttributes(parser, current, changed); if (success == false) return paintChanged; success = writeChangedElements(parser, current, changed); if (success == false) return paintChanged; parser._endElement(); // paint } } } setLast: for (index = kInitial + 1; index < kTerminal; index++) { SkString* lastAttr = lastState[index]; SkString* currentAttr = current[index]; lastAttr->set(*currentAttr); } return paintChanged; }
void SkSVGGroup::translate(SkSVGParser& parser, bool defState) { for (SkSVGElement** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) parser.translate(*ptr, defState); }
void SkSVGStop::translate(SkSVGParser& parser, bool defState) { parser._startElement("color"); INHERITED::translate(parser, defState); parser._addAttribute("color", parser.getPaintLast(SkSVGPaint::kStopColor)); parser._endElement(); }
void SkSVGPaint::setSave(SkSVGParser& parser) { SkTDArray<SkString*> clips; SkSVGPaint* walking = parser.fHead; int index; SkMatrix sum; sum.reset(); while (walking != NULL) { for (index = kInitial + 1; index < kTerminal; index++) { SkString* lastAttr = (*walking)[index]; if (lastAttr->size() == 0) continue; if (index == kTransform) { const char* str = lastAttr->c_str(); SkASSERT(strncmp(str, "matrix(", 7) == 0); str += 6; const char* strEnd = strrchr(str, ')'); SkASSERT(strEnd != NULL); SkString mat(str, strEnd - str); SkSVGParser::ConvertToArray(mat); SkScalar values[6]; SkParse::FindScalars(mat.c_str() + 1, values, 6); SkMatrix matrix; matrix.reset(); matrix.setScaleX(values[0]); matrix.setSkewY(values[1]); matrix.setSkewX(values[2]); matrix.setScaleY(values[3]); matrix.setTranslateX(values[4]); matrix.setTranslateY(values[5]); sum.setConcat(matrix, sum); continue; } if ( index == kClipPath) *clips.insert(0) = lastAttr; } walking = walking->fNext; } if ((sum == parser.fLastTransform) == false) { SkMatrix inverse; bool success = parser.fLastTransform.invert(&inverse); SkASSERT(success == true); SkMatrix output; output.setConcat(inverse, sum); parser.fLastTransform = sum; SkString outputStr; outputStr.appendUnichar('['); outputStr.appendScalar(output.getScaleX()); outputStr.appendUnichar(','); outputStr.appendScalar(output.getSkewX()); outputStr.appendUnichar(','); outputStr.appendScalar(output.getTranslateX()); outputStr.appendUnichar(','); outputStr.appendScalar(output.getSkewY()); outputStr.appendUnichar(','); outputStr.appendScalar(output.getScaleY()); outputStr.appendUnichar(','); outputStr.appendScalar(output.getTranslateY()); outputStr.appendUnichar(','); outputStr.appendScalar(output.getPerspX()); outputStr.appendUnichar(','); outputStr.appendScalar(output.getPerspY()); outputStr.append(",1]"); parser._startElement("matrix"); parser._addAttributeLen("matrix", outputStr.c_str(), outputStr.size()); parser._endElement(); } #if 0 // incomplete if (parser.fTransformClips.size() > 0) { // need to reset the clip when the 'g' scope is ended parser._startElement("add"); const char* start = strchr(current->f_clipPath.c_str(), '#') + 1; SkASSERT(start); parser._addAttributeLen("use", start, strlen(start) - 1); parser._endElement(); // clip } #endif }
bool SkSVGPaint::writeChangedAttributes(SkSVGParser& parser, SkSVGPaint& current, bool* changed) { SkSVGPaint& lastState = parser.fLastFlush; for (int index = kInitial + 1; index < kTerminal; index++) { if (changed[index] == false) continue; SkString* topAttr = current[index]; size_t attrLength = topAttr->size(); if (attrLength == 0) continue; const char* attrValue = topAttr->c_str(); SkString* lastAttr = lastState[index]; switch(index) { case kClipPath: case kClipRule: case kEnableBackground: break; case kFill: if (topAttr->equals("none") == false && lastAttr->equals("none") == true) parser._addAttribute("stroke", "false"); goto fillStrokeAttrCommon; case kFillRule: case kFilter: case kFontFamily: break; case kFontSize: parser._addAttributeLen("textSize", attrValue, attrLength); break; case kLetterSpacing: parser._addAttributeLen("textTracking", attrValue, attrLength); break; case kMask: break; case kOpacity: break; case kStopColor: break; case kStopOpacity: break; case kStroke: if (topAttr->equals("none") == false && lastAttr->equals("none") == true) parser._addAttribute("stroke", "true"); fillStrokeAttrCommon: if (strncmp(attrValue, "url(", 4) == 0) { SkASSERT(attrValue[4] == '#'); const char* idStart = attrValue + 5; const char* idEnd = strrchr(attrValue, ')'); SkASSERT(idStart < idEnd); SkString id(idStart, idEnd - idStart); SkSVGElement* found; if (strncmp(id.c_str(), "mask", 4) != 0) { bool itsFound = parser.fIDs.find(id.c_str(), &found); SkASSERT(itsFound); SkASSERT(found->getType() == SkSVGType_LinearGradient || found->getType() == SkSVGType_RadialGradient); } parser._addAttribute("shader", id.c_str()); } break; case kStroke_Dasharray: break; case kStroke_Linecap: parser._addAttributeLen("strokeCap", attrValue, attrLength); break; case kStroke_Linejoin: parser._addAttributeLen("strokeJoin", attrValue, attrLength); break; case kStroke_Miterlimit: parser._addAttributeLen("strokeMiter", attrValue, attrLength); break; case kStroke_Width: parser._addAttributeLen("strokeWidth", attrValue, attrLength); case kStyle: case kTransform: break; default: SkASSERT(0); return false; } } return true; }
bool SkSVGElement::onEndElement(SkSVGParser& parser) { if (f_id.size() > 0) parser.getIDs().set(f_id.c_str(), f_id.size(), this); return false; }
bool SkSVGPaint::writeChangedElements(SkSVGParser& parser, SkSVGPaint& current, bool* changed) { SkSVGPaint& lastState = parser.fLastFlush; for (int index = kInitial + 1; index < kTerminal; index++) { SkString* topAttr = current[index]; size_t attrLength = topAttr->size(); if (attrLength == 0) continue; const char* attrValue = topAttr->c_str(); SkString* lastAttr = lastState[index]; switch(index) { case kClipPath: case kClipRule: // !!! need to add this outside of paint break; case kEnableBackground: // !!! don't know what to do with this break; case kFill: goto addColor; case kFillRule: case kFilter: break; case kFontFamily: parser._startElement("typeface"); parser._addAttributeLen("fontName", attrValue, attrLength); parser._endElement(); // typeface break; case kFontSize: case kLetterSpacing: break; case kMask: case kOpacity: if (changed[kStroke] == false && changed[kFill] == false) { parser._startElement("color"); SkString& opacity = current.f_opacity; parser._addAttributeLen("color", parser.fLastColor.c_str(), parser.fLastColor.size()); parser._addAttributeLen("alpha", opacity.c_str(), opacity.size()); parser._endElement(); // color } break; case kStopColor: break; case kStopOpacity: break; case kStroke: addColor: if (strncmp(lastAttr->c_str(), "url(", 4) == 0 && strncmp(attrValue, "url(", 4) != 0) { parser._startElement("shader"); parser._endElement(); } if (topAttr->equals(*lastAttr)) continue; { bool urlRef = strncmp(attrValue, "url(", 4) == 0; bool colorNone = strcmp(attrValue, "none") == 0; bool lastEqual = parser.fLastColor.equals(attrValue, attrLength); bool newColor = urlRef == false && colorNone == false && lastEqual == false; if (newColor || changed[kOpacity]) { parser._startElement("color"); if (newColor || changed[kOpacity]) { parser._addAttributeLen("color", attrValue, attrLength); parser.fLastColor.set(attrValue, attrLength); } if (changed[kOpacity]) { SkString& opacity = current.f_opacity; parser._addAttributeLen("alpha", opacity.c_str(), opacity.size()); } parser._endElement(); // color } } break; case kStroke_Dasharray: parser._startElement("dash"); SkSVGParser::ConvertToArray(*topAttr); parser._addAttribute("intervals", topAttr->c_str()); parser._endElement(); // dash break; case kStroke_Linecap: case kStroke_Linejoin: case kStroke_Miterlimit: case kStroke_Width: case kStyle: case kTransform: break; default: SkASSERT(0); return false; } } return true; }