[SVGDom] Expose intrinsic size info

* expose intrinsic size info on <svg> nodes.

  * tweak the SkSVGDOM constructor to no longer take an container size
    param, but instead default to intrinsic size
  * update clients to call SkSVGDOM::setContainerSize() explicitly, when
    needed

R=robertphillips@google.com,stephana@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2345533002

Review-Url: https://codereview.chromium.org/2345533002
This commit is contained in:
fmalita 2016-09-14 12:04:30 -07:00 committed by Commit bot
parent be362774f9
commit e1baa7c105
8 changed files with 63 additions and 16 deletions

View File

@ -651,16 +651,21 @@ public:
return nullptr; return nullptr;
} }
// TODO: use intrinsic size? make tunable via flag? sk_sp<SkSVGDOM> svgDom = SkSVGDOM::MakeFromStream(stream);
static const SkSize kContainerSize = SkSize::Make(128, 128);
sk_sp<SkSVGDOM> svgDom = SkSVGDOM::MakeFromStream(stream, kContainerSize);
if (!svgDom) { if (!svgDom) {
SkDebugf("Could not parse %s.\n", path); SkDebugf("Could not parse %s.\n", path);
return nullptr; return nullptr;
} }
// Use the intrinsic SVG size if available, otherwise fall back to a default value.
static const SkSize kDefaultContainerSize = SkSize::Make(128, 128);
if (svgDom->containerSize().isEmpty()) {
svgDom->setContainerSize(kDefaultContainerSize);
}
SkPictureRecorder recorder; SkPictureRecorder recorder;
svgDom->render(recorder.beginRecording(kContainerSize.width(), kContainerSize.height())); svgDom->render(recorder.beginRecording(svgDom->containerSize().width(),
svgDom->containerSize().height()));
return recorder.finishRecordingAsPicture(); return recorder.finishRecordingAsPicture();
} }

View File

@ -1043,11 +1043,12 @@ Error SVGSrc::draw(SkCanvas* canvas) const {
return SkStringPrintf("Unable to open file: %s", fPath.c_str()); return SkStringPrintf("Unable to open file: %s", fPath.c_str());
} }
sk_sp<SkSVGDOM> dom = SkSVGDOM::MakeFromStream(stream, kSVGSize); sk_sp<SkSVGDOM> dom = SkSVGDOM::MakeFromStream(stream);
if (!dom) { if (!dom) {
return SkStringPrintf("Unable to parse file: %s", fPath.c_str()); return SkStringPrintf("Unable to parse file: %s", fPath.c_str());
} }
dom->setContainerSize(kSVGSize);
dom->render(canvas); dom->render(canvas);
return ""; return "";

View File

@ -384,26 +384,29 @@ sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext&
} // anonymous namespace } // anonymous namespace
SkSVGDOM::SkSVGDOM(const SkSize& containerSize) SkSVGDOM::SkSVGDOM()
: fContainerSize(containerSize) { : fContainerSize(SkSize::Make(0, 0)) {
} }
sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom, const SkSize& containerSize) { sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) {
sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>(containerSize); sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
ConstructionContext ctx(&dom->fIDMapper); ConstructionContext ctx(&dom->fIDMapper);
dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode()); 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; return dom;
} }
sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream, const SkSize& containerSize) { sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
SkDOM xmlDom; SkDOM xmlDom;
if (!xmlDom.build(svgStream)) { if (!xmlDom.build(svgStream)) {
return nullptr; return nullptr;
} }
return MakeFromDOM(xmlDom, containerSize); return MakeFromDOM(xmlDom);
} }
void SkSVGDOM::render(SkCanvas* canvas) const { void SkSVGDOM::render(SkCanvas* canvas) const {
@ -416,6 +419,20 @@ void SkSVGDOM::render(SkCanvas* canvas) const {
} }
} }
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;
}
void SkSVGDOM::setContainerSize(const SkSize& containerSize) { void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
// TODO: inval // TODO: inval
fContainerSize = containerSize; fContainerSize = containerSize;

View File

@ -20,18 +20,22 @@ class SkSVGNode;
class SkSVGDOM : public SkRefCnt { class SkSVGDOM : public SkRefCnt {
public: public:
SkSVGDOM(const SkSize& containerSize); SkSVGDOM();
~SkSVGDOM() = default; ~SkSVGDOM() = default;
static sk_sp<SkSVGDOM> MakeFromDOM(const SkDOM&, const SkSize& containerSize); static sk_sp<SkSVGDOM> MakeFromDOM(const SkDOM&);
static sk_sp<SkSVGDOM> MakeFromStream(SkStream&, const SkSize& containerSize); static sk_sp<SkSVGDOM> MakeFromStream(SkStream&);
const SkSize& containerSize() const;
void setContainerSize(const SkSize&); void setContainerSize(const SkSize&);
void setRoot(sk_sp<SkSVGNode>); void setRoot(sk_sp<SkSVGNode>);
void render(SkCanvas*) const; void render(SkCanvas*) const;
private: private:
SkSize intrinsicSize() const;
SkSize fContainerSize; SkSize fContainerSize;
sk_sp<SkSVGNode> fRoot; sk_sp<SkSVGNode> fRoot;
SkSVGIDMapper fIDMapper; SkSVGIDMapper fIDMapper;

View File

@ -95,3 +95,15 @@ void SkSVGSVG::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
this->INHERITED::onSetAttribute(attr, v); this->INHERITED::onSetAttribute(attr, v);
} }
} }
// https://www.w3.org/TR/SVG/coords.html#IntrinsicSizing
SkSize SkSVGSVG::intrinsicSize(const SkSVGLengthContext& lctx) const {
// Percentage values do not provide an intrinsic size.
if (fWidth.unit() == SkSVGLength::Unit::kPercentage ||
fHeight.unit() == SkSVGLength::Unit::kPercentage) {
return SkSize::Make(0, 0);
}
return SkSize::Make(lctx.resolve(fWidth, SkSVGLengthContext::LengthType::kHorizontal),
lctx.resolve(fHeight, SkSVGLengthContext::LengthType::kVertical));
}

View File

@ -12,6 +12,8 @@
#include "SkSVGTypes.h" #include "SkSVGTypes.h"
#include "SkTLazy.h" #include "SkTLazy.h"
class SkSVGLengthContext;
class SkSVGSVG : public SkSVGContainer { class SkSVGSVG : public SkSVGContainer {
public: public:
virtual ~SkSVGSVG() = default; virtual ~SkSVGSVG() = default;
@ -24,6 +26,8 @@ public:
void setHeight(const SkSVGLength&); void setHeight(const SkSVGLength&);
void setViewBox(const SkSVGViewBoxType&); void setViewBox(const SkSVGViewBoxType&);
SkSize intrinsicSize(const SkSVGLengthContext&) const;
protected: protected:
bool onPrepareToRender(SkSVGRenderContext*) const override; bool onPrepareToRender(SkSVGRenderContext*) const override;

View File

@ -35,7 +35,10 @@ protected:
return; return;
} }
fDom = SkSVGDOM::MakeFromDOM(xmlDom, SkSize::Make(this->width(), this->height())); fDom = SkSVGDOM::MakeFromDOM(xmlDom);
if (fDom) {
fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
}
} }
void onDrawContent(SkCanvas* canvas) override { void onDrawContent(SkCanvas* canvas) override {

View File

@ -136,7 +136,8 @@ protected:
// Handle everything in a normalized 1x1 space. // Handle everything in a normalized 1x1 space.
root->setViewBox(SkSVGViewBoxType(SkRect::MakeWH(1, 1))); root->setViewBox(SkSVGViewBoxType(SkRect::MakeWH(1, 1)));
fDom = sk_sp<SkSVGDOM>(new SkSVGDOM(SkSize::Make(this->width(), this->height()))); fDom = sk_sp<SkSVGDOM>(new SkSVGDOM());
fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
fDom->setRoot(std::move(root)); fDom->setRoot(std::move(root));
// Off we go. // Off we go.