void updateDom() { const SkPoint corner = pos - SkPoint::Make(size.width() / 2, size.height() / 2); objectNode->setX(SkSVGLength(corner.x())); objectNode->setY(SkSVGLength(corner.y())); // Simulate parallax shadow for a centered light source. SkPoint shadowOffset = pos - SkPoint::Make(kBounds.centerX(), kBounds.centerY()); shadowOffset.scale(kShadowParallax); const SkPoint shadowCorner = corner + shadowOffset; shadowNode->setX(SkSVGLength(shadowCorner.x())); shadowNode->setY(SkSVGLength(shadowCorner.y())); }
// https://www.w3.org/TR/SVG/types.html#DataTypeLength bool SkSVGAttributeParser::parseLength(SkSVGLength* length) { SkScalar s; SkSVGLength::Unit u = SkSVGLength::Unit::kNumber; if (this->parseScalarToken(&s) && (this->parseLengthUnitToken(&u) || this->parseSepToken() || this->parseEOSToken())) { *length = SkSVGLength(s, u); // consume trailing separators this->parseSepToken(); return true; } return false; }
SkSVGPresentationAttributes SkSVGPresentationAttributes::MakeInitial() { SkSVGPresentationAttributes result; result.fFill.set(SkSVGPaint(SkSVGColorType(SK_ColorBLACK))); result.fFillOpacity.set(SkSVGNumberType(1)); result.fStroke.set(SkSVGPaint(SkSVGPaint::Type::kNone)); result.fStrokeLineCap.set(SkSVGLineCap(SkSVGLineCap::Type::kButt)); result.fStrokeLineJoin.set(SkSVGLineJoin(SkSVGLineJoin::Type::kMiter)); result.fStrokeOpacity.set(SkSVGNumberType(1)); result.fStrokeWidth.set(SkSVGLength(1)); return result; }
void onOnceBeforeDraw() override { const SkRect fieldBounds = kBounds.makeOutset(kBallSize / 2, kBallSize / 2); const SkRRect ball = SkRRect::MakeOval(SkRect::MakeWH(kBallSize, kBallSize)); const SkRRect paddle = SkRRect::MakeRectXY(SkRect::MakeWH(kPaddleSize.width(), kPaddleSize.height()), kPaddleSize.width() / 2, kPaddleSize.width() / 2); fBall.initialize(ball, SK_ColorGREEN, SkPoint::Make(kBounds.centerX(), kBounds.centerY()), SkVector::Make(fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax), fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax))); fPaddle0.initialize(paddle, SK_ColorBLUE, SkPoint::Make(fieldBounds.left() - kPaddleSize.width() / 2, fieldBounds.centerY()), SkVector::Make(0, 0)); fPaddle1.initialize(paddle, SK_ColorRED, SkPoint::Make(fieldBounds.right() + kPaddleSize.width() / 2, fieldBounds.centerY()), SkVector::Make(0, 0)); // Background decoration. SkPath bgPath; bgPath.moveTo(kBounds.left() , fieldBounds.top()); bgPath.lineTo(kBounds.right(), fieldBounds.top()); bgPath.moveTo(kBounds.left() , fieldBounds.bottom()); bgPath.lineTo(kBounds.right(), fieldBounds.bottom()); // TODO: stroke-dash support would come in handy right about now. for (uint32_t i = 0; i < kBackgroundDashCount; ++i) { bgPath.moveTo(kBounds.centerX(), kBounds.top() + (i + 0.25f) * kBounds.height() / kBackgroundDashCount); bgPath.lineTo(kBounds.centerX(), kBounds.top() + (i + 0.75f) * kBounds.height() / kBackgroundDashCount); } sk_sp<SkSVGPath> bg = SkSVGPath::Make(); bg->setPath(bgPath); bg->setFill(SkSVGPaint(SkSVGPaint::Type::kNone)); bg->setStroke(SkSVGPaint(SkSVGColorType(SK_ColorBLACK))); bg->setStrokeWidth(SkSVGLength(kBackgroundStroke)); // Build the SVG DOM tree. sk_sp<SkSVGSVG> root = SkSVGSVG::Make(); root->appendChild(std::move(bg)); root->appendChild(fPaddle0.shadowNode); root->appendChild(fPaddle1.shadowNode); root->appendChild(fBall.shadowNode); root->appendChild(fPaddle0.objectNode); root->appendChild(fPaddle1.objectNode); root->appendChild(fBall.objectNode); // Handle everything in a normalized 1x1 space. root->setViewBox(SkSVGViewBoxType(SkRect::MakeWH(1, 1))); fDom = sk_sp<SkSVGDOM>(new SkSVGDOM()); fDom->setContainerSize(SkSize::Make(this->width(), this->height())); fDom->setRoot(std::move(root)); // Off we go. this->updatePaddleStrategy(); }