[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:
parent
24c18526a5
commit
7006e15df5
@ -8,6 +8,7 @@
|
||||
#ifndef SkSVGDOM_DEFINED
|
||||
#define SkSVGDOM_DEFINED
|
||||
|
||||
#include "include/core/SkFontMgr.h"
|
||||
#include "include/core/SkRefCnt.h"
|
||||
#include "include/core/SkSize.h"
|
||||
#include "include/private/SkTemplates.h"
|
||||
@ -17,32 +18,43 @@ class SkCanvas;
|
||||
class SkDOM;
|
||||
class SkStream;
|
||||
class SkSVGNode;
|
||||
class SkSVGSVG;
|
||||
|
||||
class SkSVGDOM : public SkRefCnt {
|
||||
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&);
|
||||
static sk_sp<SkSVGDOM> MakeFromStream(SkStream&);
|
||||
sk_sp<SkSVGDOM> make(SkStream&) const;
|
||||
|
||||
private:
|
||||
sk_sp<SkFontMgr> fFontMgr;
|
||||
};
|
||||
|
||||
static sk_sp<SkSVGDOM> MakeFromStream(SkStream& str) {
|
||||
return Builder().make(str);
|
||||
}
|
||||
|
||||
const SkSize& containerSize() const;
|
||||
void setContainerSize(const SkSize&);
|
||||
|
||||
void setRoot(sk_sp<SkSVGNode>);
|
||||
|
||||
// Returns the node with the given id, or nullptr if not found.
|
||||
sk_sp<SkSVGNode>* findNodeById(const char* id);
|
||||
|
||||
void render(SkCanvas*) const;
|
||||
|
||||
private:
|
||||
SkSize intrinsicSize() const;
|
||||
SkSVGDOM(sk_sp<SkSVGSVG>, sk_sp<SkFontMgr>, SkSVGIDMapper&&);
|
||||
|
||||
SkSize fContainerSize;
|
||||
sk_sp<SkSVGNode> fRoot;
|
||||
SkSVGIDMapper fIDMapper;
|
||||
const sk_sp<SkSVGSVG> fRoot;
|
||||
const sk_sp<SkFontMgr> fFontMgr;
|
||||
const SkSVGIDMapper fIDMapper;
|
||||
|
||||
using INHERITED = SkRefCnt;
|
||||
SkSize fContainerSize;
|
||||
};
|
||||
|
||||
#endif // SkSVGDOM_DEFINED
|
||||
|
@ -8,6 +8,7 @@
|
||||
#ifndef SkSVGRenderContext_DEFINED
|
||||
#define SkSVGRenderContext_DEFINED
|
||||
|
||||
#include "include/core/SkFontMgr.h"
|
||||
#include "include/core/SkPaint.h"
|
||||
#include "include/core/SkPath.h"
|
||||
#include "include/core/SkRect.h"
|
||||
@ -58,8 +59,9 @@ struct SkSVGPresentationContext {
|
||||
|
||||
class SkSVGRenderContext {
|
||||
public:
|
||||
SkSVGRenderContext(SkCanvas*, const SkSVGIDMapper&, const SkSVGLengthContext&,
|
||||
const SkSVGPresentationContext&, const SkSVGNode*);
|
||||
SkSVGRenderContext(SkCanvas*, const sk_sp<SkFontMgr>&, const SkSVGIDMapper&,
|
||||
const SkSVGLengthContext&, const SkSVGPresentationContext&,
|
||||
const SkSVGNode*);
|
||||
SkSVGRenderContext(const SkSVGRenderContext&);
|
||||
SkSVGRenderContext(const SkSVGRenderContext&, SkCanvas*);
|
||||
SkSVGRenderContext(const SkSVGRenderContext&, const SkSVGNode*);
|
||||
@ -123,6 +125,10 @@ public:
|
||||
// The node being rendered (may be null).
|
||||
const SkSVGNode* node() const { return fNode; }
|
||||
|
||||
sk_sp<SkFontMgr> fontMgr() const {
|
||||
return fFontMgr ? fFontMgr : SkFontMgr::RefDefault();
|
||||
}
|
||||
|
||||
private:
|
||||
// Stack-only
|
||||
void* operator new(size_t) = delete;
|
||||
@ -134,6 +140,7 @@ private:
|
||||
void applyClip(const SkSVGClip&);
|
||||
void updatePaintsWithCurrentColor(const SkSVGPresentationAttributes&);
|
||||
|
||||
const sk_sp<SkFontMgr>& fFontMgr;
|
||||
const SkSVGIDMapper& fIDMapper;
|
||||
SkTCopyOnFirstWrite<SkSVGLengthContext> fLengthContext;
|
||||
SkTCopyOnFirstWrite<SkSVGPresentationContext> fPresentationContext;
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/core/SkFontMgr.h"
|
||||
#include "include/core/SkString.h"
|
||||
#include "include/private/SkTo.h"
|
||||
#include "include/utils/SkParsePath.h"
|
||||
@ -427,49 +428,44 @@ sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext&
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SkSVGDOM::SkSVGDOM()
|
||||
: fContainerSize(SkSize::Make(0, 0)) {
|
||||
SkSVGDOM::Builder& SkSVGDOM::Builder::setFontManager(sk_sp<SkFontMgr> fmgr) {
|
||||
fFontMgr = std::move(fmgr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) {
|
||||
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) {
|
||||
sk_sp<SkSVGDOM> SkSVGDOM::Builder::make(SkStream& str) const {
|
||||
SkDOM xmlDom;
|
||||
if (!xmlDom.build(svgStream)) {
|
||||
if (!xmlDom.build(str)) {
|
||||
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 {
|
||||
if (fRoot) {
|
||||
SkSVGLengthContext lctx(fContainerSize);
|
||||
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 {
|
||||
return fContainerSize;
|
||||
}
|
||||
@ -484,10 +480,6 @@ sk_sp<SkSVGNode>* SkSVGDOM::findNodeById(const char* id) {
|
||||
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.
|
||||
bool SkSVGNode::setAttribute(const char* attributeName, const char* attributeValue) {
|
||||
return set_string_attribute(sk_ref_sp(this), attributeName, attributeValue);
|
||||
|
@ -325,8 +325,9 @@ SkSVGPresentationContext::SkSVGPresentationContext()
|
||||
|
||||
// Commit initial values to the paint cache.
|
||||
SkCanvas fakeCanvas(0, 0);
|
||||
SkSVGRenderContext fake(&fakeCanvas, SkSVGIDMapper(), SkSVGLengthContext(SkSize::Make(0, 0)),
|
||||
*this, nullptr);
|
||||
SkSVGRenderContext fake(&fakeCanvas, nullptr, SkSVGIDMapper(),
|
||||
SkSVGLengthContext(SkSize::Make(0, 0)),
|
||||
*this, nullptr);
|
||||
|
||||
commitToPaint<SkSVGAttribute::kFill>(fInherited, fake, this);
|
||||
commitToPaint<SkSVGAttribute::kFillOpacity>(fInherited, fake, this);
|
||||
@ -339,11 +340,13 @@ SkSVGPresentationContext::SkSVGPresentationContext()
|
||||
}
|
||||
|
||||
SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas,
|
||||
const sk_sp<SkFontMgr>& fmgr,
|
||||
const SkSVGIDMapper& mapper,
|
||||
const SkSVGLengthContext& lctx,
|
||||
const SkSVGPresentationContext& pctx,
|
||||
const SkSVGNode* node)
|
||||
: fIDMapper(mapper)
|
||||
: fFontMgr(fmgr)
|
||||
, fIDMapper(mapper)
|
||||
, fLengthContext(lctx)
|
||||
, fPresentationContext(pctx)
|
||||
, fCanvas(canvas)
|
||||
@ -352,6 +355,7 @@ SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas,
|
||||
|
||||
SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other)
|
||||
: SkSVGRenderContext(other.fCanvas,
|
||||
other.fFontMgr,
|
||||
other.fIDMapper,
|
||||
*other.fLengthContext,
|
||||
*other.fPresentationContext,
|
||||
@ -359,6 +363,7 @@ SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other)
|
||||
|
||||
SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other, SkCanvas* canvas)
|
||||
: SkSVGRenderContext(canvas,
|
||||
other.fFontMgr,
|
||||
other.fIDMapper,
|
||||
*other.fLengthContext,
|
||||
*other.fPresentationContext,
|
||||
@ -366,6 +371,7 @@ SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other, SkCanvas
|
||||
|
||||
SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other, const SkSVGNode* node)
|
||||
: SkSVGRenderContext(other.fCanvas,
|
||||
other.fFontMgr,
|
||||
other.fIDMapper,
|
||||
*other.fLengthContext,
|
||||
*other.fPresentationContext,
|
||||
|
@ -62,8 +62,11 @@ SkFont SkSVGText::resolveFont(const SkSVGRenderContext& ctx) const {
|
||||
ctx.lengthContext().resolve(ctx.presentationContext().fInherited.fFontSize->size(),
|
||||
SkSVGLengthContext::LengthType::kVertical);
|
||||
|
||||
// TODO: allow clients to pass an external fontmgr.
|
||||
SkFont font(SkTypeface::MakeFromName(family.c_str(), style), size);
|
||||
// TODO: we likely want matchFamilyStyle here, but switching away from legacyMakeTypeface
|
||||
// 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.setSubpixel(true);
|
||||
font.setLinearMetrics(true);
|
||||
|
@ -39,7 +39,10 @@ int main(int argc, char** argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto svg_dom = SkSVGDOM::MakeFromStream(in);
|
||||
|
||||
auto svg_dom = SkSVGDOM::Builder()
|
||||
.setFontManager(SkFontMgr::RefDefault())
|
||||
.make(in);
|
||||
if (!svg_dom) {
|
||||
std::cerr << "Could not parse " << FLAGS_input[0] << "\n";
|
||||
return 1;
|
||||
|
@ -47,13 +47,7 @@ private:
|
||||
}
|
||||
SkMemoryStream svgStream(std::move(data));
|
||||
|
||||
SkDOM xmlDom;
|
||||
if (!xmlDom.build(svgStream)) {
|
||||
SkDebugf("XML parsing failed: \"%s\"\n", fResource);
|
||||
return;
|
||||
}
|
||||
|
||||
fDom = SkSVGDOM::MakeFromDOM(xmlDom);
|
||||
fDom = SkSVGDOM::MakeFromStream(svgStream);
|
||||
if (fDom) {
|
||||
fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
|
||||
}
|
||||
|
@ -33,13 +33,7 @@ protected:
|
||||
return;
|
||||
}
|
||||
|
||||
SkDOM xmlDom;
|
||||
if (!xmlDom.build(svgStream)) {
|
||||
SkDebugf("XML parsing failed: \"path\"\n", fPath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
fDom = SkSVGDOM::MakeFromDOM(xmlDom);
|
||||
fDom = SkSVGDOM::MakeFromStream(svgStream);
|
||||
if (fDom) {
|
||||
fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
|
||||
}
|
||||
|
@ -694,11 +694,7 @@ static sk_sp<SkPicture> create_warmup_skp() {
|
||||
|
||||
static sk_sp<SkPicture> create_skp_from_svg(SkStream* stream, const char* filename) {
|
||||
#ifdef SK_XML
|
||||
SkDOM xml;
|
||||
if (!xml.build(*stream)) {
|
||||
exitf(ExitErr::kData, "failed to parse xml in file %s", filename);
|
||||
}
|
||||
sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromDOM(xml);
|
||||
sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromStream(*stream);
|
||||
if (!svg) {
|
||||
exitf(ExitErr::kData, "failed to build svg dom from file %s", filename);
|
||||
}
|
||||
|
@ -28,12 +28,7 @@ sk_sp<BisectSlide> BisectSlide::Create(const char filepath[]) {
|
||||
sk_sp<BisectSlide> bisect(new BisectSlide(filepath));
|
||||
if (bisect->fFilePath.endsWith(".svg")) {
|
||||
#ifdef SK_XML
|
||||
SkDOM xml;
|
||||
if (!xml.build(stream)) {
|
||||
SkDebugf("BISECT: XML parsing failed: \"%s\"\n", filepath);
|
||||
return nullptr;
|
||||
}
|
||||
sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromDOM(xml);
|
||||
sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromStream(stream);
|
||||
if (!svg) {
|
||||
SkDebugf("BISECT: couldn't load svg at \"%s\"\n", filepath);
|
||||
return nullptr;
|
||||
|
Loading…
Reference in New Issue
Block a user