[svg] Cleanup text content model rules

Per spec (and empirically) <text> elements are not nestable (neither
directly or indirectly):
https://www.w3.org/TR/SVG11/intro.html#TermTextContentChildElement

Update the implementation to

 - only bridge onRender -> onRenderText in the root SkSVGText
   implementation
 - disallow <text> elements as text container descendants

Change-Id: I07b3abaf943b820e01c88f78bddf7ce5970ee508
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/358220
Commit-Queue: Florin Malita <fmalita@google.com>
Reviewed-by: Tyler Denniston <tdenniston@google.com>
This commit is contained in:
Florin Malita 2021-01-24 12:04:17 -05:00 committed by Skia Commit-Bot
parent fe8a4faa4b
commit 302ea2e03c
2 changed files with 10 additions and 19 deletions

View File

@ -26,6 +26,9 @@ protected:
virtual void onRenderText(const SkSVGRenderContext&, SkSVGTextContext*, virtual void onRenderText(const SkSVGRenderContext&, SkSVGTextContext*,
SkSVGXmlSpace) const = 0; SkSVGXmlSpace) const = 0;
// Text nodes other than the root <text> element are not rendered directly.
void onRender(const SkSVGRenderContext&) const override {}
private: private:
SkPath onAsPath(const SkSVGRenderContext&) const final; SkPath onAsPath(const SkSVGRenderContext&) const final;
@ -53,8 +56,6 @@ protected:
bool parseAndSetAttribute(const char*, const char*) override; bool parseAndSetAttribute(const char*, const char*) override;
private: private:
void onRender(const SkSVGRenderContext&) const final;
std::vector<sk_sp<SkSVGTextFragment>> fChildren; std::vector<sk_sp<SkSVGTextFragment>> fChildren;
using INHERITED = SkSVGTextFragment; using INHERITED = SkSVGTextFragment;
@ -67,7 +68,7 @@ public:
private: private:
SkSVGText() : INHERITED(SkSVGTag::kText) {} SkSVGText() : INHERITED(SkSVGTag::kText) {}
void onRenderText(const SkSVGRenderContext&, SkSVGTextContext*, SkSVGXmlSpace) const override; void onRender(const SkSVGRenderContext&) const override;
using INHERITED = SkSVGTextContainer; using INHERITED = SkSVGTextContainer;
}; };
@ -93,7 +94,6 @@ public:
private: private:
SkSVGTextLiteral() : INHERITED(SkSVGTag::kTextLiteral) {} SkSVGTextLiteral() : INHERITED(SkSVGTag::kTextLiteral) {}
void onRender(const SkSVGRenderContext&) const override {}
void onRenderText(const SkSVGRenderContext&, SkSVGTextContext*, SkSVGXmlSpace) const override; void onRenderText(const SkSVGRenderContext&, SkSVGTextContext*, SkSVGXmlSpace) const override;
void appendChild(sk_sp<SkSVGNode>) override {} void appendChild(sk_sp<SkSVGNode>) override {}

View File

@ -490,9 +490,8 @@ SkPath SkSVGTextFragment::onAsPath(const SkSVGRenderContext&) const {
} }
void SkSVGTextContainer::appendChild(sk_sp<SkSVGNode> child) { void SkSVGTextContainer::appendChild(sk_sp<SkSVGNode> child) {
// Only allow text nodes. // Only allow text content child nodes.
switch (child->tag()) { switch (child->tag()) {
case SkSVGTag::kText:
case SkSVGTag::kTextLiteral: case SkSVGTag::kTextLiteral:
case SkSVGTag::kTextPath: case SkSVGTag::kTextPath:
case SkSVGTag::kTSpan: case SkSVGTag::kTSpan:
@ -506,10 +505,7 @@ void SkSVGTextContainer::appendChild(sk_sp<SkSVGNode> child) {
void SkSVGTextContainer::onRenderText(const SkSVGRenderContext& ctx, SkSVGTextContext* tctx, void SkSVGTextContainer::onRenderText(const SkSVGRenderContext& ctx, SkSVGTextContext* tctx,
SkSVGXmlSpace) const { SkSVGXmlSpace) const {
if (!tctx) { SkASSERT(tctx);
// No text context => missing top-level <text> node.
return;
}
const SkSVGTextContext::ScopedPosResolver resolver(*this, ctx.lengthContext(), tctx); const SkSVGTextContext::ScopedPosResolver resolver(*this, ctx.lengthContext(), tctx);
@ -542,10 +538,6 @@ bool SkSVGTextContainer::parseAndSetAttribute(const char* name, const char* valu
this->setXmlSpace(SkSVGAttributeParser::parse<SkSVGXmlSpace>("xml:space", name, value)); this->setXmlSpace(SkSVGAttributeParser::parse<SkSVGXmlSpace>("xml:space", name, value));
} }
void SkSVGTextContainer::onRender(const SkSVGRenderContext& ctx) const {
this->onRenderText(ctx, nullptr, this->getXmlSpace());
}
void SkSVGTextLiteral::onRenderText(const SkSVGRenderContext& ctx, SkSVGTextContext* tctx, void SkSVGTextLiteral::onRenderText(const SkSVGRenderContext& ctx, SkSVGTextContext* tctx,
SkSVGXmlSpace xs) const { SkSVGXmlSpace xs) const {
SkASSERT(tctx); SkASSERT(tctx);
@ -553,17 +545,16 @@ void SkSVGTextLiteral::onRenderText(const SkSVGRenderContext& ctx, SkSVGTextCont
tctx->appendFragment(this->getText(), ctx, xs); tctx->appendFragment(this->getText(), ctx, xs);
} }
void SkSVGText::onRenderText(const SkSVGRenderContext& ctx, SkSVGTextContext*, void SkSVGText::onRender(const SkSVGRenderContext& ctx) const {
SkSVGXmlSpace xs) const { // Root <text> nodes establish a text layout context.
// Root text nodes establish a new text layout context.
SkSVGTextContext tctx(ctx); SkSVGTextContext tctx(ctx);
this->INHERITED::onRenderText(ctx, &tctx, xs); this->onRenderText(ctx, &tctx, this->getXmlSpace());
} }
void SkSVGTextPath::onRenderText(const SkSVGRenderContext& ctx, SkSVGTextContext*, void SkSVGTextPath::onRenderText(const SkSVGRenderContext& ctx, SkSVGTextContext*,
SkSVGXmlSpace xs) const { SkSVGXmlSpace xs) const {
// Root text nodes establish a new text layout context. // textPath nodes establish a new text layout context.
SkSVGTextContext tctx(ctx, this); SkSVGTextContext tctx(ctx, this);
this->INHERITED::onRenderText(ctx, &tctx, xs); this->INHERITED::onRenderText(ctx, &tctx, xs);