[SVGDom] Opacity optimization

Apply opacity as fill/stroke paint alpha instead of saveLayer, when
possible.

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

Committed: https://skia.googlesource.com/skia/+/3dbb7b9f196d793fbd16243157ee67638891f5dc
Review-Url: https://codereview.chromium.org/2353503005
This commit is contained in:
fmalita 2016-09-20 15:45:57 -07:00 committed by Commit bot
parent 768dc8f496
commit bef51c23c3
6 changed files with 47 additions and 6 deletions

View File

@ -14,6 +14,10 @@ void SkSVGContainer::appendChild(sk_sp<SkSVGNode> node) {
fChildren.push_back(std::move(node));
}
bool SkSVGContainer::hasChildren() const {
return !fChildren.empty();
}
void SkSVGContainer::onRender(const SkSVGRenderContext& ctx) const {
for (int i = 0; i < fChildren.count(); ++i) {
fChildren[i]->render(ctx);

View File

@ -22,6 +22,8 @@ protected:
void onRender(const SkSVGRenderContext&) const override;
bool hasChildren() const final;
// TODO: add some sort of child iterator, and hide the container.
SkSTArray<1, sk_sp<SkSVGNode>, true> fChildren;

View File

@ -31,7 +31,8 @@ bool SkSVGNode::asPaint(const SkSVGRenderContext& ctx, SkPaint* paint) const {
}
bool SkSVGNode::onPrepareToRender(SkSVGRenderContext* ctx) const {
ctx->applyPresentationAttributes(fPresentationAttributes);
ctx->applyPresentationAttributes(fPresentationAttributes,
this->hasChildren() ? 0 : SkSVGRenderContext::kLeaf);
return true;
}

View File

@ -69,6 +69,8 @@ protected:
virtual void onSetAttribute(SkSVGAttribute, const SkSVGValue&);
virtual bool hasChildren() const { return false; }
private:
SkSVGTag fTag;

View File

@ -239,7 +239,8 @@ const SkSVGNode* SkSVGRenderContext::findNodeById(const SkString& id) const {
return v ? v->get() : nullptr;
}
void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttributes& attrs) {
void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttributes& attrs,
uint32_t flags) {
#define ApplyLazyInheritedAttribute(ATTR) \
do { \
@ -267,10 +268,36 @@ void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttr
// Uninherited attributes. Only apply to the current context.
auto* opacity = attrs.fOpacity.getMaybeNull();
if (opacity && opacity->value() < 1) {
if (auto* opacity = attrs.fOpacity.getMaybeNull()) {
this->applyOpacity(opacity->value(), flags);
}
}
void SkSVGRenderContext::applyOpacity(SkScalar opacity, uint32_t flags) {
if (opacity >= 1) {
return;
}
const bool hasFill = SkToBool(this->fillPaint());
const bool hasStroke = SkToBool(this->strokePaint());
// We can apply the opacity as paint alpha iif it only affects one atomic draw.
// For now, this means a) the target node doesn't have any descendants, and
// b) it only has a stroke or a fill (but not both). Going forward, we may need
// to refine this heuristic (e.g. to accommodate markers).
if ((flags & kLeaf) && (hasFill ^ hasStroke)) {
auto* pctx = fPresentationContext.writable();
if (hasFill) {
pctx->fFillPaint.setAlpha(
SkScalarRoundToInt(opacity * pctx->fFillPaint.getAlpha()));
} else {
pctx->fStrokePaint.setAlpha(
SkScalarRoundToInt(opacity * pctx->fStrokePaint.getAlpha()));
}
} else {
// Expensive, layer-based fall back.
SkPaint opacityPaint;
opacityPaint.setAlpha(opacity_to_alpha(opacity->value()));
opacityPaint.setAlpha(opacity_to_alpha(opacity));
// Balanced in the destructor, via restoreToCount().
fCanvas->saveLayer(nullptr, &opacityPaint);
}

View File

@ -67,7 +67,10 @@ public:
SkCanvas* canvas() const { return fCanvas; }
void applyPresentationAttributes(const SkSVGPresentationAttributes&);
enum ApplyFlags {
kLeaf = 1 << 0, // the target node doesn't have descendants
};
void applyPresentationAttributes(const SkSVGPresentationAttributes&, uint32_t flags);
const SkSVGNode* findNodeById(const SkString&) const;
@ -80,6 +83,8 @@ private:
void* operator new(size_t, void*) = delete;
SkSVGRenderContext& operator=(const SkSVGRenderContext&) = delete;
void applyOpacity(SkScalar opacity, uint32_t flags);
const SkSVGIDMapper& fIDMapper;
SkTCopyOnFirstWrite<SkSVGLengthContext> fLengthContext;
SkTCopyOnFirstWrite<SkSVGPresentationContext> fPresentationContext;