[svg] Allow clients to pass a custom SkFontMgr

Introduce a Builder helper and plumb the client-provided SkFontMgr for
font resolution.

Also clean up some of the legacy SkSVGDom factories.

Bug: skia:10840
Change-Id: I6e1eabe7c257cb75dfdb5bf67054f93f25769027
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/333577
Commit-Queue: Florin Malita <fmalita@google.com>
Reviewed-by: Tyler Denniston <tdenniston@google.com>
This commit is contained in:
Florin Malita 2020-11-10 15:24:59 -05:00 committed by Skia Commit-Bot
parent 24c18526a5
commit 7006e15df5
10 changed files with 77 additions and 75 deletions

View File

@ -8,6 +8,7 @@
#ifndef SkSVGDOM_DEFINED #ifndef SkSVGDOM_DEFINED
#define SkSVGDOM_DEFINED #define SkSVGDOM_DEFINED
#include "include/core/SkFontMgr.h"
#include "include/core/SkRefCnt.h" #include "include/core/SkRefCnt.h"
#include "include/core/SkSize.h" #include "include/core/SkSize.h"
#include "include/private/SkTemplates.h" #include "include/private/SkTemplates.h"
@ -17,32 +18,43 @@ class SkCanvas;
class SkDOM; class SkDOM;
class SkStream; class SkStream;
class SkSVGNode; class SkSVGNode;
class SkSVGSVG;
class SkSVGDOM : public SkRefCnt { class SkSVGDOM : public SkRefCnt {
public: public:
SkSVGDOM(); class Builder final {
public:
/**
* Specify a font manager for loading SVG fonts.
*/
Builder& setFontManager(sk_sp<SkFontMgr>);
static sk_sp<SkSVGDOM> MakeFromDOM(const SkDOM&); sk_sp<SkSVGDOM> make(SkStream&) const;
static sk_sp<SkSVGDOM> MakeFromStream(SkStream&);
private:
sk_sp<SkFontMgr> fFontMgr;
};
static sk_sp<SkSVGDOM> MakeFromStream(SkStream& str) {
return Builder().make(str);
}
const SkSize& containerSize() const; const SkSize& containerSize() const;
void setContainerSize(const SkSize&); void setContainerSize(const SkSize&);
void setRoot(sk_sp<SkSVGNode>);
// Returns the node with the given id, or nullptr if not found. // Returns the node with the given id, or nullptr if not found.
sk_sp<SkSVGNode>* findNodeById(const char* id); sk_sp<SkSVGNode>* findNodeById(const char* id);
void render(SkCanvas*) const; void render(SkCanvas*) const;
private: private:
SkSize intrinsicSize() const; SkSVGDOM(sk_sp<SkSVGSVG>, sk_sp<SkFontMgr>, SkSVGIDMapper&&);
SkSize fContainerSize; const sk_sp<SkSVGSVG> fRoot;
sk_sp<SkSVGNode> fRoot; const sk_sp<SkFontMgr> fFontMgr;
SkSVGIDMapper fIDMapper; const SkSVGIDMapper fIDMapper;
using INHERITED = SkRefCnt; SkSize fContainerSize;
}; };
#endif // SkSVGDOM_DEFINED #endif // SkSVGDOM_DEFINED

View File

@ -8,6 +8,7 @@
#ifndef SkSVGRenderContext_DEFINED #ifndef SkSVGRenderContext_DEFINED
#define SkSVGRenderContext_DEFINED #define SkSVGRenderContext_DEFINED
#include "include/core/SkFontMgr.h"
#include "include/core/SkPaint.h" #include "include/core/SkPaint.h"
#include "include/core/SkPath.h" #include "include/core/SkPath.h"
#include "include/core/SkRect.h" #include "include/core/SkRect.h"
@ -58,8 +59,9 @@ struct SkSVGPresentationContext {
class SkSVGRenderContext { class SkSVGRenderContext {
public: public:
SkSVGRenderContext(SkCanvas*, const SkSVGIDMapper&, const SkSVGLengthContext&, SkSVGRenderContext(SkCanvas*, const sk_sp<SkFontMgr>&, const SkSVGIDMapper&,
const SkSVGPresentationContext&, const SkSVGNode*); const SkSVGLengthContext&, const SkSVGPresentationContext&,
const SkSVGNode*);
SkSVGRenderContext(const SkSVGRenderContext&); SkSVGRenderContext(const SkSVGRenderContext&);
SkSVGRenderContext(const SkSVGRenderContext&, SkCanvas*); SkSVGRenderContext(const SkSVGRenderContext&, SkCanvas*);
SkSVGRenderContext(const SkSVGRenderContext&, const SkSVGNode*); SkSVGRenderContext(const SkSVGRenderContext&, const SkSVGNode*);
@ -123,6 +125,10 @@ public:
// The node being rendered (may be null). // The node being rendered (may be null).
const SkSVGNode* node() const { return fNode; } const SkSVGNode* node() const { return fNode; }
sk_sp<SkFontMgr> fontMgr() const {
return fFontMgr ? fFontMgr : SkFontMgr::RefDefault();
}
private: private:
// Stack-only // Stack-only
void* operator new(size_t) = delete; void* operator new(size_t) = delete;
@ -134,6 +140,7 @@ private:
void applyClip(const SkSVGClip&); void applyClip(const SkSVGClip&);
void updatePaintsWithCurrentColor(const SkSVGPresentationAttributes&); void updatePaintsWithCurrentColor(const SkSVGPresentationAttributes&);
const sk_sp<SkFontMgr>& fFontMgr;
const SkSVGIDMapper& fIDMapper; const SkSVGIDMapper& fIDMapper;
SkTCopyOnFirstWrite<SkSVGLengthContext> fLengthContext; SkTCopyOnFirstWrite<SkSVGLengthContext> fLengthContext;
SkTCopyOnFirstWrite<SkSVGPresentationContext> fPresentationContext; SkTCopyOnFirstWrite<SkSVGPresentationContext> fPresentationContext;

View File

@ -6,6 +6,7 @@
*/ */
#include "include/core/SkCanvas.h" #include "include/core/SkCanvas.h"
#include "include/core/SkFontMgr.h"
#include "include/core/SkString.h" #include "include/core/SkString.h"
#include "include/private/SkTo.h" #include "include/private/SkTo.h"
#include "include/utils/SkParsePath.h" #include "include/utils/SkParsePath.h"
@ -427,49 +428,44 @@ sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext&
} // anonymous namespace } // anonymous namespace
SkSVGDOM::SkSVGDOM() SkSVGDOM::Builder& SkSVGDOM::Builder::setFontManager(sk_sp<SkFontMgr> fmgr) {
: fContainerSize(SkSize::Make(0, 0)) { fFontMgr = std::move(fmgr);
return *this;
} }
sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) { sk_sp<SkSVGDOM> SkSVGDOM::Builder::make(SkStream& str) const {
sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
ConstructionContext ctx(&dom->fIDMapper);
dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
// Reset the default container size to match the intrinsic SVG size.
dom->setContainerSize(dom->intrinsicSize());
return dom;
}
sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
SkDOM xmlDom; SkDOM xmlDom;
if (!xmlDom.build(svgStream)) { if (!xmlDom.build(str)) {
return nullptr; return nullptr;
} }
return MakeFromDOM(xmlDom); SkSVGIDMapper mapper;
ConstructionContext ctx(&mapper);
auto root = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
if (!root || root->tag() != SkSVGTag::kSvg) {
return nullptr;
}
return sk_sp<SkSVGDOM>(new SkSVGDOM(sk_sp<SkSVGSVG>(static_cast<SkSVGSVG*>(root.release())),
std::move(fFontMgr), std::move(mapper)));
} }
SkSVGDOM::SkSVGDOM(sk_sp<SkSVGSVG> root, sk_sp<SkFontMgr> fmgr, SkSVGIDMapper&& mapper)
: fRoot(std::move(root))
, fFontMgr(std::move(fmgr))
, fIDMapper(std::move(mapper))
, fContainerSize(fRoot->intrinsicSize(SkSVGLengthContext(SkSize::Make(0, 0))))
{}
void SkSVGDOM::render(SkCanvas* canvas) const { void SkSVGDOM::render(SkCanvas* canvas) const {
if (fRoot) { if (fRoot) {
SkSVGLengthContext lctx(fContainerSize); SkSVGLengthContext lctx(fContainerSize);
SkSVGPresentationContext pctx; SkSVGPresentationContext pctx;
fRoot->render(SkSVGRenderContext(canvas, fIDMapper, lctx, pctx, nullptr)); fRoot->render(SkSVGRenderContext(canvas, fFontMgr, fIDMapper, lctx, pctx, nullptr));
} }
} }
SkSize SkSVGDOM::intrinsicSize() const {
if (!fRoot || fRoot->tag() != SkSVGTag::kSvg) {
return SkSize::Make(0, 0);
}
// Intrinsic sizes are never relative, so the viewport size is irrelevant.
const SkSVGLengthContext lctx(SkSize::Make(0, 0));
return static_cast<const SkSVGSVG*>(fRoot.get())->intrinsicSize(lctx);
}
const SkSize& SkSVGDOM::containerSize() const { const SkSize& SkSVGDOM::containerSize() const {
return fContainerSize; return fContainerSize;
} }
@ -484,10 +480,6 @@ sk_sp<SkSVGNode>* SkSVGDOM::findNodeById(const char* id) {
return this->fIDMapper.find(idStr); return this->fIDMapper.find(idStr);
} }
void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
fRoot = std::move(root);
}
// TODO(fuego): move this to SkSVGNode or its own CU. // TODO(fuego): move this to SkSVGNode or its own CU.
bool SkSVGNode::setAttribute(const char* attributeName, const char* attributeValue) { bool SkSVGNode::setAttribute(const char* attributeName, const char* attributeValue) {
return set_string_attribute(sk_ref_sp(this), attributeName, attributeValue); return set_string_attribute(sk_ref_sp(this), attributeName, attributeValue);

View File

@ -325,8 +325,9 @@ SkSVGPresentationContext::SkSVGPresentationContext()
// Commit initial values to the paint cache. // Commit initial values to the paint cache.
SkCanvas fakeCanvas(0, 0); SkCanvas fakeCanvas(0, 0);
SkSVGRenderContext fake(&fakeCanvas, SkSVGIDMapper(), SkSVGLengthContext(SkSize::Make(0, 0)), SkSVGRenderContext fake(&fakeCanvas, nullptr, SkSVGIDMapper(),
*this, nullptr); SkSVGLengthContext(SkSize::Make(0, 0)),
*this, nullptr);
commitToPaint<SkSVGAttribute::kFill>(fInherited, fake, this); commitToPaint<SkSVGAttribute::kFill>(fInherited, fake, this);
commitToPaint<SkSVGAttribute::kFillOpacity>(fInherited, fake, this); commitToPaint<SkSVGAttribute::kFillOpacity>(fInherited, fake, this);
@ -339,11 +340,13 @@ SkSVGPresentationContext::SkSVGPresentationContext()
} }
SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas, SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas,
const sk_sp<SkFontMgr>& fmgr,
const SkSVGIDMapper& mapper, const SkSVGIDMapper& mapper,
const SkSVGLengthContext& lctx, const SkSVGLengthContext& lctx,
const SkSVGPresentationContext& pctx, const SkSVGPresentationContext& pctx,
const SkSVGNode* node) const SkSVGNode* node)
: fIDMapper(mapper) : fFontMgr(fmgr)
, fIDMapper(mapper)
, fLengthContext(lctx) , fLengthContext(lctx)
, fPresentationContext(pctx) , fPresentationContext(pctx)
, fCanvas(canvas) , fCanvas(canvas)
@ -352,6 +355,7 @@ SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas,
SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other) SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other)
: SkSVGRenderContext(other.fCanvas, : SkSVGRenderContext(other.fCanvas,
other.fFontMgr,
other.fIDMapper, other.fIDMapper,
*other.fLengthContext, *other.fLengthContext,
*other.fPresentationContext, *other.fPresentationContext,
@ -359,6 +363,7 @@ SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other)
SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other, SkCanvas* canvas) SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other, SkCanvas* canvas)
: SkSVGRenderContext(canvas, : SkSVGRenderContext(canvas,
other.fFontMgr,
other.fIDMapper, other.fIDMapper,
*other.fLengthContext, *other.fLengthContext,
*other.fPresentationContext, *other.fPresentationContext,
@ -366,6 +371,7 @@ SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other, SkCanvas
SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other, const SkSVGNode* node) SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other, const SkSVGNode* node)
: SkSVGRenderContext(other.fCanvas, : SkSVGRenderContext(other.fCanvas,
other.fFontMgr,
other.fIDMapper, other.fIDMapper,
*other.fLengthContext, *other.fLengthContext,
*other.fPresentationContext, *other.fPresentationContext,

View File

@ -62,8 +62,11 @@ SkFont SkSVGText::resolveFont(const SkSVGRenderContext& ctx) const {
ctx.lengthContext().resolve(ctx.presentationContext().fInherited.fFontSize->size(), ctx.lengthContext().resolve(ctx.presentationContext().fInherited.fFontSize->size(),
SkSVGLengthContext::LengthType::kVertical); SkSVGLengthContext::LengthType::kVertical);
// TODO: allow clients to pass an external fontmgr. // TODO: we likely want matchFamilyStyle here, but switching away from legacyMakeTypeface
SkFont font(SkTypeface::MakeFromName(family.c_str(), style), size); // changes all the results when using the default fontmgr.
auto tf = ctx.fontMgr()->legacyMakeTypeface(family.c_str(), style);
SkFont font(std::move(tf), size);
font.setHinting(SkFontHinting::kNone); font.setHinting(SkFontHinting::kNone);
font.setSubpixel(true); font.setSubpixel(true);
font.setLinearMetrics(true); font.setLinearMetrics(true);

View File

@ -39,7 +39,10 @@ int main(int argc, char** argv) {
return 1; return 1;
} }
auto svg_dom = SkSVGDOM::MakeFromStream(in);
auto svg_dom = SkSVGDOM::Builder()
.setFontManager(SkFontMgr::RefDefault())
.make(in);
if (!svg_dom) { if (!svg_dom) {
std::cerr << "Could not parse " << FLAGS_input[0] << "\n"; std::cerr << "Could not parse " << FLAGS_input[0] << "\n";
return 1; return 1;

View File

@ -47,13 +47,7 @@ private:
} }
SkMemoryStream svgStream(std::move(data)); SkMemoryStream svgStream(std::move(data));
SkDOM xmlDom; fDom = SkSVGDOM::MakeFromStream(svgStream);
if (!xmlDom.build(svgStream)) {
SkDebugf("XML parsing failed: \"%s\"\n", fResource);
return;
}
fDom = SkSVGDOM::MakeFromDOM(xmlDom);
if (fDom) { if (fDom) {
fDom->setContainerSize(SkSize::Make(this->width(), this->height())); fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
} }

View File

@ -33,13 +33,7 @@ protected:
return; return;
} }
SkDOM xmlDom; fDom = SkSVGDOM::MakeFromStream(svgStream);
if (!xmlDom.build(svgStream)) {
SkDebugf("XML parsing failed: \"path\"\n", fPath.c_str());
return;
}
fDom = SkSVGDOM::MakeFromDOM(xmlDom);
if (fDom) { if (fDom) {
fDom->setContainerSize(SkSize::Make(this->width(), this->height())); fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
} }

View File

@ -694,11 +694,7 @@ static sk_sp<SkPicture> create_warmup_skp() {
static sk_sp<SkPicture> create_skp_from_svg(SkStream* stream, const char* filename) { static sk_sp<SkPicture> create_skp_from_svg(SkStream* stream, const char* filename) {
#ifdef SK_XML #ifdef SK_XML
SkDOM xml; sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromStream(*stream);
if (!xml.build(*stream)) {
exitf(ExitErr::kData, "failed to parse xml in file %s", filename);
}
sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromDOM(xml);
if (!svg) { if (!svg) {
exitf(ExitErr::kData, "failed to build svg dom from file %s", filename); exitf(ExitErr::kData, "failed to build svg dom from file %s", filename);
} }

View File

@ -28,12 +28,7 @@ sk_sp<BisectSlide> BisectSlide::Create(const char filepath[]) {
sk_sp<BisectSlide> bisect(new BisectSlide(filepath)); sk_sp<BisectSlide> bisect(new BisectSlide(filepath));
if (bisect->fFilePath.endsWith(".svg")) { if (bisect->fFilePath.endsWith(".svg")) {
#ifdef SK_XML #ifdef SK_XML
SkDOM xml; sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromStream(stream);
if (!xml.build(stream)) {
SkDebugf("BISECT: XML parsing failed: \"%s\"\n", filepath);
return nullptr;
}
sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromDOM(xml);
if (!svg) { if (!svg) {
SkDebugf("BISECT: couldn't load svg at \"%s\"\n", filepath); SkDebugf("BISECT: couldn't load svg at \"%s\"\n", filepath);
return nullptr; return nullptr;