[svg] Property inheritance workaround

Property inheritance is supposed to follow the tree hierarchy, but we
implement it based on the render path.

One nasty side effect is when resolving IRI paint servers
(gradients, patterns), the referencing node properties get inherited
(leak) into the paint server fragment.  E.g.

  <pattern id="pat">
    <rect fill="green"/>
  </pattern>

  <rect stroke="blue" fill="url(#pat)" stroke="blue"/>

The pattern subtree incorrectly inherits a blue stroke property from
the referencing node when we resolve the fill.

As a temporary (and imperfect) workaround, we can reset the presentation
context when resolving IRI paint servers.

Change-Id: Ia4a8a6199222820661f805c43340b5e16902feff
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/354668
Reviewed-by: Tyler Denniston <tdenniston@google.com>
Commit-Queue: Florin Malita <fmalita@google.com>
This commit is contained in:
Florin Malita 2021-01-15 15:47:19 -05:00 committed by Skia Commit-Bot
parent 4f2bcff08e
commit d414e600b2
2 changed files with 13 additions and 1 deletions

View File

@ -135,6 +135,8 @@ public:
const SkSVGLength& w, const SkSVGLength& h,
SkSVGObjectBoundingBoxUnits) const;
const SkSVGIDMapper& idMapper() const { return fIDMapper; }
private:
// Stack-only
void* operator new(size_t) = delete;

View File

@ -111,8 +111,18 @@ void applySvgPaint(const SkSVGRenderContext& ctx, const SkSVGPaint& svgPaint, Sk
p->setColor(SkColorSetA(ctx.resolveSvgColor(svgPaint.color()), p->getAlpha()));
break;
case SkSVGPaint::Type::kIRI: {
// Out property inheritance is borked as it follows the render path and not the tree
// hierarchy. To avoid gross transgressions like leaf node presentation attributes leaking
// into the paint server context, use a pristine presentation context when following hrefs.
SkSVGPresentationContext pctx;
SkSVGRenderContext local_context(ctx.canvas(),
ctx.fontMgr(),
ctx.idMapper(),
ctx.lengthContext(),
pctx, ctx.node());
const auto node = ctx.findNodeById(svgPaint.iri());
if (!node || !node->asPaint(ctx, p)) {
if (!node || !node->asPaint(local_context, p)) {
p->setColor(SK_ColorTRANSPARENT);
}
break;