Ejemplo n.º 1
0
// https://www.w3.org/TR/SVG/pservers.html#LinearGradientElementHrefAttribute
void SkSVGLinearGradient::collectColorStops(const SkSVGRenderContext& ctx,
                                            SkSTArray<2, SkScalar, true>* pos,
                                            SkSTArray<2, SkColor, true>* colors) const {
    // Used to resolve percentage offsets.
    const SkSVGLengthContext ltx(SkSize::Make(1, 1));

    for (const auto& child : fChildren) {
        if (child->tag() != SkSVGTag::kStop) {
            continue;
        }

        const auto& stop = static_cast<const SkSVGStop&>(*child);
        colors->push_back(SkColorSetA(stop.stopColor(),
                                      SkScalarRoundToInt(stop.stopOpacity() * 255)));
        pos->push_back(SkTPin(ltx.resolve(stop.offset(), SkSVGLengthContext::LengthType::kOther),
                              0.f, 1.f));
    }

    SkASSERT(colors->count() == pos->count());

    if (pos->empty() && !fHref.value().isEmpty()) {
        const auto* ref = ctx.findNodeById(fHref);
        if (ref && ref->tag() == SkSVGTag::kLinearGradient) {
            static_cast<const SkSVGLinearGradient*>(ref)->collectColorStops(ctx, pos, colors);
        }
    }
}
Ejemplo n.º 2
0
bool SkSVGLinearGradient::onAsPaint(const SkSVGRenderContext& ctx, SkPaint* paint) const {
    const auto& lctx = ctx.lengthContext();
    const auto x1 = lctx.resolve(fX1, SkSVGLengthContext::LengthType::kHorizontal);
    const auto y1 = lctx.resolve(fY1, SkSVGLengthContext::LengthType::kVertical);
    const auto x2 = lctx.resolve(fX2, SkSVGLengthContext::LengthType::kHorizontal);
    const auto y2 = lctx.resolve(fY2, SkSVGLengthContext::LengthType::kVertical);

    const SkPoint pts[2] = { {x1, y1}, {x2, y2}};
    SkSTArray<2, SkColor , true> colors;
    SkSTArray<2, SkScalar, true> pos;

    this->collectColorStops(ctx, &pos, &colors);
    // TODO:
    //       * stop (lazy?) sorting
    //       * href loop detection
    //       * href attribute inheritance (not just color stops)
    //       * objectBoundingBox units support

    static_assert(static_cast<SkShader::TileMode>(SkSVGSpreadMethod::Type::kPad) ==
                  SkShader::kClamp_TileMode, "SkSVGSpreadMethod::Type is out of sync");
    static_assert(static_cast<SkShader::TileMode>(SkSVGSpreadMethod::Type::kRepeat) ==
                  SkShader::kRepeat_TileMode, "SkSVGSpreadMethod::Type is out of sync");
    static_assert(static_cast<SkShader::TileMode>(SkSVGSpreadMethod::Type::kReflect) ==
                  SkShader::kMirror_TileMode, "SkSVGSpreadMethod::Type is out of sync");
    const auto tileMode = static_cast<SkShader::TileMode>(fSpreadMethod.type());

    paint->setShader(SkGradientShader::MakeLinear(pts, colors.begin(), pos.begin(), colors.count(),
                                                  tileMode, 0, &fGradientTransform.value()));
    return true;
}
Ejemplo n.º 3
0
SkPath SkSVGPath::onAsPath(const SkSVGRenderContext& ctx) const {
    // the computed fillType follows inheritance rules and needs to be applied at draw time.
    fPath.setFillType(FillRuleToFillType(*ctx.presentationContext().fInherited.fFillRule.get()));

    SkPath path = fPath;
    this->mapToParent(&path);
    return path;
}
Ejemplo n.º 4
0
SkPath SkSVGPoly::onAsPath(const SkSVGRenderContext& ctx) const {
    SkPath path = fPath;

    // clip-rule can be inherited and needs to be applied at clip time.
    path.setFillType(ctx.presentationContext().fInherited.fClipRule.get()->asFillType());

    this->mapToParent(&path);
    return path;
}
Ejemplo n.º 5
0
void SkSVGShape::onRender(const SkSVGRenderContext& ctx) const {
    const auto fillType = ctx.presentationContext().fInherited.fFillRule.get()->asFillType();

    // TODO: this approach forces duplicate geometry resolution in onDraw(); refactor to avoid.
    if (const SkPaint* fillPaint = ctx.fillPaint()) {
        this->onDraw(ctx.canvas(), ctx.lengthContext(), *fillPaint, fillType);
    }

    if (const SkPaint* strokePaint = ctx.strokePaint()) {
        this->onDraw(ctx.canvas(), ctx.lengthContext(), *strokePaint, fillType);
    }
}
Ejemplo n.º 6
0
void SkSVGPath::onRender(SkCanvas* canvas, const SkSVGRenderContext& ctx) const {
    this->doRender(canvas, ctx.fillPaint());
    this->doRender(canvas, ctx.strokePaint());
}