[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));
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,8 @@ protected:
|
||||
|
||||
virtual void onSetAttribute(SkSVGAttribute, const SkSVGValue&);
|
||||
|
||||
virtual bool hasChildren() const { return false; }
|
||||
|
||||
private:
|
||||
SkSVGTag fTag;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user