[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
|
#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
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user