[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:
parent
768dc8f496
commit
bef51c23c3
@ -14,6 +14,10 @@ void SkSVGContainer::appendChild(sk_sp<SkSVGNode> node) {
|
|||||||
fChildren.push_back(std::move(node));
|
fChildren.push_back(std::move(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SkSVGContainer::hasChildren() const {
|
||||||
|
return !fChildren.empty();
|
||||||
|
}
|
||||||
|
|
||||||
void SkSVGContainer::onRender(const SkSVGRenderContext& ctx) const {
|
void SkSVGContainer::onRender(const SkSVGRenderContext& ctx) const {
|
||||||
for (int i = 0; i < fChildren.count(); ++i) {
|
for (int i = 0; i < fChildren.count(); ++i) {
|
||||||
fChildren[i]->render(ctx);
|
fChildren[i]->render(ctx);
|
||||||
|
@ -22,6 +22,8 @@ protected:
|
|||||||
|
|
||||||
void onRender(const SkSVGRenderContext&) const override;
|
void onRender(const SkSVGRenderContext&) const override;
|
||||||
|
|
||||||
|
bool hasChildren() const final;
|
||||||
|
|
||||||
// TODO: add some sort of child iterator, and hide the container.
|
// TODO: add some sort of child iterator, and hide the container.
|
||||||
SkSTArray<1, sk_sp<SkSVGNode>, true> fChildren;
|
SkSTArray<1, sk_sp<SkSVGNode>, true> fChildren;
|
||||||
|
|
||||||
|
@ -31,7 +31,8 @@ bool SkSVGNode::asPaint(const SkSVGRenderContext& ctx, SkPaint* paint) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool SkSVGNode::onPrepareToRender(SkSVGRenderContext* ctx) const {
|
bool SkSVGNode::onPrepareToRender(SkSVGRenderContext* ctx) const {
|
||||||
ctx->applyPresentationAttributes(fPresentationAttributes);
|
ctx->applyPresentationAttributes(fPresentationAttributes,
|
||||||
|
this->hasChildren() ? 0 : SkSVGRenderContext::kLeaf);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,8 @@ protected:
|
|||||||
|
|
||||||
virtual void onSetAttribute(SkSVGAttribute, const SkSVGValue&);
|
virtual void onSetAttribute(SkSVGAttribute, const SkSVGValue&);
|
||||||
|
|
||||||
|
virtual bool hasChildren() const { return false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SkSVGTag fTag;
|
SkSVGTag fTag;
|
||||||
|
|
||||||
|
@ -239,7 +239,8 @@ const SkSVGNode* SkSVGRenderContext::findNodeById(const SkString& id) const {
|
|||||||
return v ? v->get() : nullptr;
|
return v ? v->get() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttributes& attrs) {
|
void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttributes& attrs,
|
||||||
|
uint32_t flags) {
|
||||||
|
|
||||||
#define ApplyLazyInheritedAttribute(ATTR) \
|
#define ApplyLazyInheritedAttribute(ATTR) \
|
||||||
do { \
|
do { \
|
||||||
@ -267,10 +268,36 @@ void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttr
|
|||||||
|
|
||||||
// Uninherited attributes. Only apply to the current context.
|
// Uninherited attributes. Only apply to the current context.
|
||||||
|
|
||||||
auto* opacity = attrs.fOpacity.getMaybeNull();
|
if (auto* opacity = attrs.fOpacity.getMaybeNull()) {
|
||||||
if (opacity && opacity->value() < 1) {
|
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;
|
SkPaint opacityPaint;
|
||||||
opacityPaint.setAlpha(opacity_to_alpha(opacity->value()));
|
opacityPaint.setAlpha(opacity_to_alpha(opacity));
|
||||||
// Balanced in the destructor, via restoreToCount().
|
// Balanced in the destructor, via restoreToCount().
|
||||||
fCanvas->saveLayer(nullptr, &opacityPaint);
|
fCanvas->saveLayer(nullptr, &opacityPaint);
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,10 @@ public:
|
|||||||
|
|
||||||
SkCanvas* canvas() const { return fCanvas; }
|
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;
|
const SkSVGNode* findNodeById(const SkString&) const;
|
||||||
|
|
||||||
@ -80,6 +83,8 @@ private:
|
|||||||
void* operator new(size_t, void*) = delete;
|
void* operator new(size_t, void*) = delete;
|
||||||
SkSVGRenderContext& operator=(const SkSVGRenderContext&) = delete;
|
SkSVGRenderContext& operator=(const SkSVGRenderContext&) = delete;
|
||||||
|
|
||||||
|
void applyOpacity(SkScalar opacity, uint32_t flags);
|
||||||
|
|
||||||
const SkSVGIDMapper& fIDMapper;
|
const SkSVGIDMapper& fIDMapper;
|
||||||
SkTCopyOnFirstWrite<SkSVGLengthContext> fLengthContext;
|
SkTCopyOnFirstWrite<SkSVGLengthContext> fLengthContext;
|
||||||
SkTCopyOnFirstWrite<SkSVGPresentationContext> fPresentationContext;
|
SkTCopyOnFirstWrite<SkSVGPresentationContext> fPresentationContext;
|
||||||
|
Loading…
Reference in New Issue
Block a user