Chromium Code Reviews| Index: experimental/svg/model/SkSVGRenderContext.cpp |
| diff --git a/experimental/svg/model/SkSVGRenderContext.cpp b/experimental/svg/model/SkSVGRenderContext.cpp |
| index e902d4ecf3d389018535e941299ef989c1e7bd42..dde7ad144d581b5a2ac6cb095f5b0bc5ec8a3702 100644 |
| --- a/experimental/svg/model/SkSVGRenderContext.cpp |
| +++ b/experimental/svg/model/SkSVGRenderContext.cpp |
| @@ -6,6 +6,7 @@ |
| */ |
| #include "SkCanvas.h" |
| +#include "SkSVGAttribute.h" |
| #include "SkSVGRenderContext.h" |
| #include "SkSVGTypes.h" |
| @@ -30,6 +31,7 @@ SkScalar length_size_for_type(const SkSize& viewport, SkSVGLengthContext::Length |
| SkScalar SkSVGLengthContext::resolve(const SkSVGLength& l, LengthType t) const { |
| switch (l.unit()) { |
|
robertphillips
2016/08/11 13:38:54
// fall through ?
f(malita)
2016/08/11 14:03:16
Done.
|
| case SkSVGLength::Unit::kNumber: |
| + case SkSVGLength::Unit::kPX: |
| return l.value(); |
| break; |
| case SkSVGLength::Unit::kPercentage: |
| @@ -52,55 +54,135 @@ SkRect SkSVGLengthContext::resolveRect(const SkSVGLength& x, const SkSVGLength& |
| this->resolve(h, SkSVGLengthContext::LengthType::kVertical)); |
| } |
| -SkSVGPresentationContext::SkSVGPresentationContext() {} |
| +namespace { |
| -SkSVGPresentationContext::SkSVGPresentationContext(const SkSVGPresentationContext& o) { |
| - this->initFrom(o); |
| +SkPaint::Cap toSkCap(const SkSVGLineCap& cap) { |
| + switch (cap.type()) { |
| + case SkSVGLineCap::Type::kButt: |
| + return SkPaint::kButt_Cap; |
| + case SkSVGLineCap::Type::kRound: |
| + return SkPaint::kRound_Cap; |
| + case SkSVGLineCap::Type::kSquare: |
| + return SkPaint::kSquare_Cap; |
| + default: |
| + SkASSERT(false); |
| + return SkPaint::kButt_Cap; |
| + } |
| } |
| -SkSVGPresentationContext& SkSVGPresentationContext::operator=(const SkSVGPresentationContext& o) { |
| - this->initFrom(o); |
| - return *this; |
| +SkPaint::Join toSkJoin(const SkSVGLineJoin& join) { |
| + switch (join.type()) { |
| + case SkSVGLineJoin::Type::kMiter: |
| + return SkPaint::kMiter_Join; |
| + case SkSVGLineJoin::Type::kRound: |
| + return SkPaint::kRound_Join; |
| + case SkSVGLineJoin::Type::kBevel: |
| + return SkPaint::kBevel_Join; |
| + default: |
| + SkASSERT(false); |
| + return SkPaint::kMiter_Join; |
| + } |
| } |
| -void SkSVGPresentationContext::initFrom(const SkSVGPresentationContext& other) { |
| - if (other.fFill.isValid()) { |
| - fFill.set(*other.fFill.get()); |
| - } else { |
| - fFill.reset(); |
| +void applySvgPaint(const SkSVGPaint& svgPaint, SkPaint* p) { |
| + switch (svgPaint.type()) { |
| + case SkSVGPaint::Type::kColor: |
| + p->setColor(SkColorSetA(svgPaint.color(), p->getAlpha())); |
| + break; |
| + case SkSVGPaint::Type::kCurrentColor: |
| + SkDebugf("unimplemented 'currentColor' paint type"); |
| + // Fall through. |
| + case SkSVGPaint::Type::kNone: |
| + // Fall through. |
| + case SkSVGPaint::Type::kInherit: |
| + break; |
| } |
| +} |
| - if (other.fStroke.isValid()) { |
| - fStroke.set(*other.fStroke.get()); |
| - } else { |
| - fStroke.reset(); |
| - } |
| +// Commit the selected attribute to the paint cache. |
| +template <SkSVGAttribute> |
| +void commitToPaint(const SkSVGPresentationAttributes&, |
| + const SkSVGLengthContext&, |
| + SkSVGPresentationContext*); |
| + |
| +template <> |
| +void commitToPaint<SkSVGAttribute::kFill>(const SkSVGPresentationAttributes& attrs, |
| + const SkSVGLengthContext&, |
| + SkSVGPresentationContext* pctx) { |
| + applySvgPaint(*attrs.fFill.get(), &pctx->fFillPaint); |
| } |
| -SkPaint& SkSVGPresentationContext::ensureFill() { |
| - if (!fFill.isValid()) { |
| - fFill.init(); |
| - fFill.get()->setStyle(SkPaint::kFill_Style); |
| - fFill.get()->setAntiAlias(true); |
| +template <> |
| +void commitToPaint<SkSVGAttribute::kStroke>(const SkSVGPresentationAttributes& attrs, |
| + const SkSVGLengthContext&, |
| + SkSVGPresentationContext* pctx) { |
| + applySvgPaint(*attrs.fStroke.get(), &pctx->fStrokePaint); |
| +} |
| + |
| +template <> |
| +void commitToPaint<SkSVGAttribute::kFillOpacity>(const SkSVGPresentationAttributes& attrs, |
| + const SkSVGLengthContext&, |
| + SkSVGPresentationContext* pctx) { |
| + pctx->fFillPaint.setAlpha(static_cast<uint8_t>(*attrs.fFillOpacity.get() * 255)); |
| +} |
| + |
| +template <> |
| +void commitToPaint<SkSVGAttribute::kStrokeLineCap>(const SkSVGPresentationAttributes& attrs, |
| + const SkSVGLengthContext&, |
| + SkSVGPresentationContext* pctx) { |
| + const auto& cap = *attrs.fStrokeLineCap.get(); |
| + if (cap.type() != SkSVGLineCap::Type::kInherit) { |
| + pctx->fStrokePaint.setStrokeCap(toSkCap(cap)); |
| } |
| - return *fFill.get(); |
| } |
| -SkPaint& SkSVGPresentationContext::ensureStroke() { |
| - if (!fStroke.isValid()) { |
| - fStroke.init(); |
| - fStroke.get()->setStyle(SkPaint::kStroke_Style); |
| - fStroke.get()->setAntiAlias(true); |
| +template <> |
| +void commitToPaint<SkSVGAttribute::kStrokeLineJoin>(const SkSVGPresentationAttributes& attrs, |
| + const SkSVGLengthContext&, |
| + SkSVGPresentationContext* pctx) { |
| + const auto& join = *attrs.fStrokeLineJoin.get(); |
| + if (join.type() != SkSVGLineJoin::Type::kInherit) { |
| + pctx->fStrokePaint.setStrokeJoin(toSkJoin(join)); |
| } |
| - return *fStroke.get(); |
| } |
| -void SkSVGPresentationContext::setFillColor(SkColor color) { |
| - this->ensureFill().setColor(color); |
| +template <> |
| +void commitToPaint<SkSVGAttribute::kStrokeOpacity>(const SkSVGPresentationAttributes& attrs, |
| + const SkSVGLengthContext&, |
| + SkSVGPresentationContext* pctx) { |
| + pctx->fStrokePaint.setAlpha(static_cast<uint8_t>(*attrs.fStrokeOpacity.get() * 255)); |
| +} |
| + |
| +template <> |
| +void commitToPaint<SkSVGAttribute::kStrokeWidth>(const SkSVGPresentationAttributes& attrs, |
| + const SkSVGLengthContext& lctx, |
| + SkSVGPresentationContext* pctx) { |
| + auto strokeWidth = lctx.resolve(*attrs.fStrokeWidth.get(), |
| + SkSVGLengthContext::LengthType::kOther); |
| + pctx->fStrokePaint.setStrokeWidth(strokeWidth); |
| } |
| -void SkSVGPresentationContext::setStrokeColor(SkColor color) { |
| - this->ensureStroke().setColor(color); |
| +} // anonymous ns |
| + |
| +SkSVGPresentationContext::SkSVGPresentationContext() |
| + : fInherited(SkSVGPresentationAttributes::MakeInitial()) { |
| + |
| + fFillPaint.setStyle(SkPaint::kFill_Style); |
| + fStrokePaint.setStyle(SkPaint::kStroke_Style); |
| + |
| + // TODO: drive AA off presentation attrs also (shape-rendering?) |
| + fFillPaint.setAntiAlias(true); |
| + fStrokePaint.setAntiAlias(true); |
| + |
| + // Commit initial values to the paint cache. |
| + SkSVGLengthContext dummy(SkSize::Make(0, 0)); |
| + commitToPaint<SkSVGAttribute::kFill>(fInherited, dummy, this); |
| + commitToPaint<SkSVGAttribute::kFillOpacity>(fInherited, dummy, this); |
| + commitToPaint<SkSVGAttribute::kStroke>(fInherited, dummy, this); |
| + commitToPaint<SkSVGAttribute::kStrokeLineCap>(fInherited, dummy, this); |
| + commitToPaint<SkSVGAttribute::kStrokeLineJoin>(fInherited, dummy, this); |
| + commitToPaint<SkSVGAttribute::kStrokeOpacity>(fInherited, dummy, this); |
| + commitToPaint<SkSVGAttribute::kStrokeWidth>(fInherited, dummy, this); |
| } |
| SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas, |
| @@ -112,10 +194,47 @@ SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas, |
| , fCanvasSaveCount(canvas->getSaveCount()) {} |
| SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other) |
| - : SkSVGRenderContext(other.canvas(), |
| - other.lengthContext(), |
| - other.presentationContext()) {} |
| + : SkSVGRenderContext(other.fCanvas, |
| + *other.fLengthContext, |
| + *other.fPresentationContext) {} |
| SkSVGRenderContext::~SkSVGRenderContext() { |
| fCanvas->restoreToCount(fCanvasSaveCount); |
| } |
| + |
| +void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttributes& attrs) { |
| + |
| +#define ApplyLazyInheritedAttribute(ATTR) \ |
| + do { \ |
| + /* All attributes should be defined on the inherited context. */ \ |
| + SkASSERT(fPresentationContext->fInherited.f ## ATTR.isValid()); \ |
| + const auto* value = attrs.f ## ATTR.getMaybeNull(); \ |
| + if (value && *value != *fPresentationContext->fInherited.f ## ATTR.get()) { \ |
| + /* Update the local attribute value */ \ |
| + fPresentationContext.writable()->fInherited.f ## ATTR.set(*value); \ |
| + /* Update the cached paints */ \ |
| + commitToPaint<SkSVGAttribute::k ## ATTR>(attrs, *fLengthContext, \ |
| + fPresentationContext.writable()); \ |
| + } \ |
| + } while (false) |
| + |
| + ApplyLazyInheritedAttribute(Fill); |
| + ApplyLazyInheritedAttribute(FillOpacity); |
| + ApplyLazyInheritedAttribute(Stroke); |
| + ApplyLazyInheritedAttribute(StrokeLineCap); |
| + ApplyLazyInheritedAttribute(StrokeLineJoin); |
| + ApplyLazyInheritedAttribute(StrokeOpacity); |
| + ApplyLazyInheritedAttribute(StrokeWidth); |
| + |
| +#undef ApplyLazyInheritedAttribute |
| +} |
| + |
| +const SkPaint* SkSVGRenderContext::fillPaint() const { |
| + const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fFill.get()->type(); |
| + return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fFillPaint : nullptr; |
| +} |
| + |
| +const SkPaint* SkSVGRenderContext::strokePaint() const { |
| + const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fStroke.get()->type(); |
| + return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fStrokePaint : nullptr; |
| +} |