Commit bc2589c3 authored by fmalita's avatar fmalita Committed by Commit bot

[SVG] Shared <use> path geometry

Based on Fredrik Söderquist <fs@opera.com>'s idea.

For <use>-instanced SVGPathElements, reuse the referenced Path object (now
cached in SVGPath).  This ensures that all <path> instances paint using the
same SkPath, which in turn reduces the pressure on internal Skia path caches.

BUG=skia:4527,549242
R=fs@opera.com

Review URL: https://codereview.chromium.org/1425913004

Cr-Commit-Position: refs/heads/master@{#357138}
parent a3c75658
......@@ -130,6 +130,9 @@ private:
private:
OwnPtr<AffineTransform> m_localTransform;
// TODO(fmalita): the Path is now cached in SVGPath; while this additional cache is just a
// shallow copy, it certainly has a complexity/state management cost (plus allocation & storage
// overhead) - so we should look into removing it.
OwnPtr<Path> m_path;
mutable OwnPtr<LayoutSVGShapeRareData> m_rareData;
......
......@@ -542,7 +542,7 @@ void SVGElement::cursorImageValueRemoved()
}
#endif
SVGElement* SVGElement::correspondingElement()
SVGElement* SVGElement::correspondingElement() const
{
ASSERT(!hasSVGRareData() || !svgRareData()->correspondingElement() || containingShadowRoot());
return hasSVGRareData() ? svgRareData()->correspondingElement() : 0;
......
......@@ -124,7 +124,7 @@ public:
void cursorImageValueRemoved();
#endif
SVGElement* correspondingElement();
SVGElement* correspondingElement() const;
void setCorrespondingElement(SVGElement*);
SVGUseElement* correspondingUseElement() const;
......
......@@ -63,7 +63,7 @@ public:
SVGCursorElement* cursorElement() const { return m_cursorElement; }
void setCursorElement(SVGCursorElement* cursorElement) { m_cursorElement = cursorElement; }
SVGElement* correspondingElement() { return m_correspondingElement.get(); }
SVGElement* correspondingElement() const { return m_correspondingElement.get(); }
void setCorrespondingElement(SVGElement* correspondingElement) { m_correspondingElement = correspondingElement; }
CSSCursorImageValue* cursorImageValue() const { return m_cursorImageValue; }
......
......@@ -32,6 +32,7 @@
#include "core/svg/SVGPathByteStreamSource.h"
#include "core/svg/SVGPathParser.h"
#include "core/svg/SVGPathUtilities.h"
#include "platform/graphics/Path.h"
namespace blink {
......@@ -50,6 +51,16 @@ SVGPath::~SVGPath()
{
}
const Path& SVGPath::path() const
{
if (!m_cachedPath) {
m_cachedPath = adoptPtr(new Path);
buildPathFromByteStream(byteStream(), *m_cachedPath);
}
return *m_cachedPath;
}
PassRefPtrWillBeRawPtr<SVGPath> SVGPath::clone() const
{
return adoptRefWillBeNoop(new SVGPath(byteStream().copy()));
......@@ -62,16 +73,28 @@ PassRefPtrWillBeRawPtr<SVGPropertyBase> SVGPath::cloneForAnimation(const String&
return svgPath;
}
SVGPathByteStream& SVGPath::ensureByteStream()
{
if (!m_byteStream)
m_byteStream = SVGPathByteStream::create();
return *m_byteStream.get();
}
void SVGPath::byteStreamWillChange()
{
m_cachedPath.clear();
}
const SVGPathByteStream& SVGPath::byteStream() const
{
return const_cast<SVGPath*>(this)->mutableByteStream();
return const_cast<SVGPath*>(this)->ensureByteStream();
}
SVGPathByteStream& SVGPath::mutableByteStream()
{
if (!m_byteStream)
m_byteStream = SVGPathByteStream::create();
return *m_byteStream.get();
byteStreamWillChange();
return ensureByteStream();
}
String SVGPath::valueAsString() const
......@@ -118,6 +141,8 @@ void SVGPath::calculateAnimatedValue(SVGAnimationElement* animationElement, floa
fromStream = copy.get();
}
byteStreamWillChange();
// If the 'from' value is given and it's length doesn't match the 'to' value list length, fallback to a discrete animation.
if (fromStream->size() != toStream.size() && fromStream->size()) {
if (percentage < 0.5) {
......
......@@ -36,6 +36,7 @@
namespace blink {
class ExceptionState;
class Path;
class SVGPathByteStream;
class SVGPath : public SVGPropertyBase {
......@@ -49,6 +50,8 @@ public:
~SVGPath() override;
const Path& path() const;
const SVGPathByteStream& byteStream() const;
SVGPathByteStream& mutableByteStream();
......@@ -68,7 +71,11 @@ private:
SVGPath();
explicit SVGPath(PassOwnPtr<SVGPathByteStream>);
SVGPathByteStream& ensureByteStream();
void byteStreamWillChange();
OwnPtr<SVGPathByteStream> m_byteStream;
mutable OwnPtr<Path> m_cachedPath;
};
inline PassRefPtrWillBeRawPtr<SVGPath> toSVGPath(PassRefPtrWillBeRawPtr<SVGPropertyBase> passBase)
......
......@@ -72,9 +72,11 @@ DEFINE_NODE_FACTORY(SVGPathElement)
Path SVGPathElement::asPath() const
{
Path path;
buildPathFromByteStream(pathByteStream(), path);
return path;
// If this is a <use> instance, return the referenced path to maximize geometry sharing.
if (const SVGElement* element = correspondingElement())
return toSVGPathElement(element)->asPath();
return m_path->currentValue()->path();
}
float SVGPathElement::getTotalLength()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment