skia2/experimental/svg/model/SkSVGRenderContext.cpp
fmalita 397a517d1a [SVGDom] Add viewBox support
The main feature is <svg> viewBox and proper viewport support, but the CL
touches a few other things:

* refactor SkSVGRenderContext to auto-restore canvas state, and split the
  presentation bits into a separate CoW SkSVGPresentationContext

* introduce SkSVGNode::onPrepareToRender(), as a way for nodes to push their
  custom state before the actual onRender() call (instead of relying on
  non-virtual SkSVGNode to know about all possible state bits)

* add a "Type" suffix to SVG types, to disambiguate (e.g. SkSVGRectType vs.
  SkSVGRect)

R=robertphillips@google.com,stephana@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2222793002

Review-Url: https://codereview.chromium.org/2222793002
2016-08-08 11:38:55 -07:00

122 lines
3.5 KiB
C++

/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkCanvas.h"
#include "SkSVGRenderContext.h"
#include "SkSVGTypes.h"
namespace {
SkScalar length_size_for_type(const SkSize& viewport, SkSVGLengthContext::LengthType t) {
switch (t) {
case SkSVGLengthContext::LengthType::kHorizontal:
return viewport.width();
case SkSVGLengthContext::LengthType::kVertical:
return viewport.height();
case SkSVGLengthContext::LengthType::kOther:
return SkScalarSqrt(viewport.width() * viewport.height());
}
SkASSERT(false); // Not reached.
return 0;
}
} // anonymous ns
SkScalar SkSVGLengthContext::resolve(const SkSVGLength& l, LengthType t) const {
switch (l.unit()) {
case SkSVGLength::Unit::kNumber:
return l.value();
break;
case SkSVGLength::Unit::kPercentage:
return l.value() * length_size_for_type(fViewport, t) / 100;
break;
default:
SkDebugf("unsupported unit type: <%d>\n", l.unit());
break;
}
return 0;
}
SkRect SkSVGLengthContext::resolveRect(const SkSVGLength& x, const SkSVGLength& y,
const SkSVGLength& w, const SkSVGLength& h) const {
return SkRect::MakeXYWH(
this->resolve(x, SkSVGLengthContext::LengthType::kHorizontal),
this->resolve(y, SkSVGLengthContext::LengthType::kVertical),
this->resolve(w, SkSVGLengthContext::LengthType::kHorizontal),
this->resolve(h, SkSVGLengthContext::LengthType::kVertical));
}
SkSVGPresentationContext::SkSVGPresentationContext() {}
SkSVGPresentationContext::SkSVGPresentationContext(const SkSVGPresentationContext& o) {
this->initFrom(o);
}
SkSVGPresentationContext& SkSVGPresentationContext::operator=(const SkSVGPresentationContext& o) {
this->initFrom(o);
return *this;
}
void SkSVGPresentationContext::initFrom(const SkSVGPresentationContext& other) {
if (other.fFill.isValid()) {
fFill.set(*other.fFill.get());
} else {
fFill.reset();
}
if (other.fStroke.isValid()) {
fStroke.set(*other.fStroke.get());
} else {
fStroke.reset();
}
}
SkPaint& SkSVGPresentationContext::ensureFill() {
if (!fFill.isValid()) {
fFill.init();
fFill.get()->setStyle(SkPaint::kFill_Style);
fFill.get()->setAntiAlias(true);
}
return *fFill.get();
}
SkPaint& SkSVGPresentationContext::ensureStroke() {
if (!fStroke.isValid()) {
fStroke.init();
fStroke.get()->setStyle(SkPaint::kStroke_Style);
fStroke.get()->setAntiAlias(true);
}
return *fStroke.get();
}
void SkSVGPresentationContext::setFillColor(SkColor color) {
this->ensureFill().setColor(color);
}
void SkSVGPresentationContext::setStrokeColor(SkColor color) {
this->ensureStroke().setColor(color);
}
SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas,
const SkSVGLengthContext& lctx,
const SkSVGPresentationContext& pctx)
: fLengthContext(lctx)
, fPresentationContext(pctx)
, fCanvas(canvas)
, fCanvasSaveCount(canvas->getSaveCount()) {}
SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other)
: SkSVGRenderContext(other.canvas(),
other.lengthContext(),
other.presentationContext()) {}
SkSVGRenderContext::~SkSVGRenderContext() {
fCanvas->restoreToCount(fCanvasSaveCount);
}