Commit d798a7a8 authored by pdr's avatar pdr Committed by Commit bot

Add support for caching and invalidating SVG marker transforms

This patch adds a cache of the SVG marker transform, similar to the pattern
used in LayoutSVGViewportContainer. This should be a small perf win because
we no longer re-calculate the transform when painting each marker instance.
With this new cache logic, invalidation logic has been added which includes
a fix for paint property under-invalidation (marker-viewBox-changes.svg).

BUG=645667,600618

Review-Url: https://codereview.chromium.org/2565943002
Cr-Commit-Position: refs/heads/master@{#437993}
parent a30e9a7d
...@@ -101,7 +101,6 @@ crbug.com/646176 virtual/spinvalidation/paint/invalidation/ [ Pass ] ...@@ -101,7 +101,6 @@ crbug.com/646176 virtual/spinvalidation/paint/invalidation/ [ Pass ]
crbug.com/645667 virtual/spinvalidation/paint/invalidation/outline-clip-change.html [ Crash Failure ] crbug.com/645667 virtual/spinvalidation/paint/invalidation/outline-clip-change.html [ Crash Failure ]
crbug.com/645667 virtual/spinvalidation/paint/invalidation/filter-repaint-accelerated-on-accelerated-filter.html [ Crash ] crbug.com/645667 virtual/spinvalidation/paint/invalidation/filter-repaint-accelerated-on-accelerated-filter.html [ Crash ]
crbug.com/645667 virtual/spinvalidation/paint/invalidation/position-change-keeping-geometry.html [ Crash ] crbug.com/645667 virtual/spinvalidation/paint/invalidation/position-change-keeping-geometry.html [ Crash ]
crbug.com/645667 virtual/spinvalidation/paint/invalidation/svg/marker-viewBox-changes.svg [ Crash Failure ]
crbug.com/645667 virtual/spinvalidation/paint/invalidation/compositing/should-not-repaint-composited-descendants.html [ Crash ] crbug.com/645667 virtual/spinvalidation/paint/invalidation/compositing/should-not-repaint-composited-descendants.html [ Crash ]
crbug.com/645667 virtual/spinvalidation/paint/invalidation/compositing/resize-repaint.html [ Crash ] crbug.com/645667 virtual/spinvalidation/paint/invalidation/compositing/resize-repaint.html [ Crash ]
crbug.com/645667 virtual/spinvalidation/paint/invalidation/compositing/shrink-layer.html [ Crash ] crbug.com/645667 virtual/spinvalidation/paint/invalidation/compositing/shrink-layer.html [ Crash ]
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
namespace blink { namespace blink {
LayoutSVGResourceMarker::LayoutSVGResourceMarker(SVGMarkerElement* node) LayoutSVGResourceMarker::LayoutSVGResourceMarker(SVGMarkerElement* node)
: LayoutSVGResourceContainer(node) {} : LayoutSVGResourceContainer(node), m_needsTransformUpdate(true) {}
LayoutSVGResourceMarker::~LayoutSVGResourceMarker() {} LayoutSVGResourceMarker::~LayoutSVGResourceMarker() {}
...@@ -72,10 +72,6 @@ FloatRect LayoutSVGResourceMarker::markerBoundaries( ...@@ -72,10 +72,6 @@ FloatRect LayoutSVGResourceMarker::markerBoundaries(
return markerTransformation.mapRect(coordinates); return markerTransformation.mapRect(coordinates);
} }
AffineTransform LayoutSVGResourceMarker::localToSVGParentTransform() const {
return viewportTransform();
}
FloatPoint LayoutSVGResourceMarker::referencePoint() const { FloatPoint LayoutSVGResourceMarker::referencePoint() const {
SVGMarkerElement* marker = toSVGMarkerElement(element()); SVGMarkerElement* marker = toSVGMarkerElement(element());
ASSERT(marker); ASSERT(marker);
...@@ -119,7 +115,7 @@ AffineTransform LayoutSVGResourceMarker::markerTransformation( ...@@ -119,7 +115,7 @@ AffineTransform LayoutSVGResourceMarker::markerTransformation(
// The reference point (refX, refY) is in the coordinate space of the marker's // The reference point (refX, refY) is in the coordinate space of the marker's
// contents so we include the value in each marker's transform. // contents so we include the value in each marker's transform.
FloatPoint mappedReferencePoint = FloatPoint mappedReferencePoint =
viewportTransform().mapPoint(referencePoint()); localToSVGParentTransform().mapPoint(referencePoint());
transform.translate(-mappedReferencePoint.x(), -mappedReferencePoint.y()); transform.translate(-mappedReferencePoint.x(), -mappedReferencePoint.y());
return transform; return transform;
} }
...@@ -133,17 +129,19 @@ bool LayoutSVGResourceMarker::shouldPaint() const { ...@@ -133,17 +129,19 @@ bool LayoutSVGResourceMarker::shouldPaint() const {
!marker->viewBox()->currentValue()->value().isEmpty(); !marker->viewBox()->currentValue()->value().isEmpty();
} }
AffineTransform LayoutSVGResourceMarker::viewportTransform() const { void LayoutSVGResourceMarker::setNeedsTransformUpdate() {
SVGMarkerElement* marker = toSVGMarkerElement(element()); setMayNeedPaintInvalidationSubtree();
ASSERT(marker); if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()) {
// The transform paint property relies on the SVG transform being up-to-date
return marker->viewBoxToViewTransform(m_viewportSize.width(), // (see: PaintPropertyTreeBuilder::updateTransformForNonRootSVG).
m_viewportSize.height()); setNeedsPaintPropertyUpdate();
}
m_needsTransformUpdate = true;
} }
void LayoutSVGResourceMarker::calcViewport() { SVGTransformChange LayoutSVGResourceMarker::calculateLocalTransform() {
if (!selfNeedsLayout()) if (!m_needsTransformUpdate)
return; return SVGTransformChange::None;
SVGMarkerElement* marker = toSVGMarkerElement(element()); SVGMarkerElement* marker = toSVGMarkerElement(element());
ASSERT(marker); ASSERT(marker);
...@@ -152,14 +150,13 @@ void LayoutSVGResourceMarker::calcViewport() { ...@@ -152,14 +150,13 @@ void LayoutSVGResourceMarker::calcViewport() {
float width = marker->markerWidth()->currentValue()->value(lengthContext); float width = marker->markerWidth()->currentValue()->value(lengthContext);
float height = marker->markerHeight()->currentValue()->value(lengthContext); float height = marker->markerHeight()->currentValue()->value(lengthContext);
m_viewportSize = FloatSize(width, height); m_viewportSize = FloatSize(width, height);
}
SVGTransformChange LayoutSVGResourceMarker::calculateLocalTransform() { SVGTransformChangeDetector changeDetector(m_localToParentTransform);
// TODO(fs): Temporarily, needing a layout implies that the local transform m_localToParentTransform = marker->viewBoxToViewTransform(
// has changed. This should be updated to be more precise and factor in the m_viewportSize.width(), m_viewportSize.height());
// actual (relevant) changes to the computed user-space transform.
return selfNeedsLayout() ? SVGTransformChange::Full m_needsTransformUpdate = false;
: SVGTransformChange::None; return changeDetector.computeChange(m_localToParentTransform);
} }
} // namespace blink } // namespace blink
...@@ -42,11 +42,19 @@ class LayoutSVGResourceMarker final : public LayoutSVGResourceContainer { ...@@ -42,11 +42,19 @@ class LayoutSVGResourceMarker final : public LayoutSVGResourceContainer {
// Calculates marker boundaries, mapped to the target element's coordinate // Calculates marker boundaries, mapped to the target element's coordinate
// space. // space.
FloatRect markerBoundaries(const AffineTransform& markerTransformation) const; FloatRect markerBoundaries(const AffineTransform& markerTransformation) const;
AffineTransform localToSVGParentTransform() const override;
AffineTransform markerTransformation(const FloatPoint& origin, AffineTransform markerTransformation(const FloatPoint& origin,
float angle, float angle,
float strokeWidth) const; float strokeWidth) const;
AffineTransform localToSVGParentTransform() const final {
return m_localToParentTransform;
}
void setNeedsTransformUpdate() final;
// The viewport origin is (0,0) and not the reference point because each
// marker instance includes the reference in markerTransformation().
FloatRect viewport() const { return FloatRect(FloatPoint(), m_viewportSize); }
bool shouldPaint() const; bool shouldPaint() const;
FloatPoint referencePoint() const; FloatPoint referencePoint() const;
...@@ -54,21 +62,16 @@ class LayoutSVGResourceMarker final : public LayoutSVGResourceContainer { ...@@ -54,21 +62,16 @@ class LayoutSVGResourceMarker final : public LayoutSVGResourceContainer {
SVGMarkerUnitsType markerUnits() const; SVGMarkerUnitsType markerUnits() const;
SVGMarkerOrientType orientType() const; SVGMarkerOrientType orientType() const;
// The viewport origin is (0,0) and not the reference point because each
// marker instance includes the reference in markerTransformation().
FloatRect viewport() const { return FloatRect(FloatPoint(), m_viewportSize); }
static const LayoutSVGResourceType s_resourceType = MarkerResourceType; static const LayoutSVGResourceType s_resourceType = MarkerResourceType;
LayoutSVGResourceType resourceType() const override { return s_resourceType; } LayoutSVGResourceType resourceType() const override { return s_resourceType; }
private: private:
void layout() override; void layout() override;
void calcViewport() override; SVGTransformChange calculateLocalTransform() final;
SVGTransformChange calculateLocalTransform() override;
AffineTransform viewportTransform() const;
AffineTransform m_localToParentTransform;
FloatSize m_viewportSize; FloatSize m_viewportSize;
bool m_needsTransformUpdate;
}; };
DEFINE_LAYOUT_SVG_RESOURCE_TYPE_CASTS(LayoutSVGResourceMarker, DEFINE_LAYOUT_SVG_RESOURCE_TYPE_CASTS(LayoutSVGResourceMarker,
......
...@@ -99,22 +99,26 @@ AffineTransform SVGMarkerElement::viewBoxToViewTransform( ...@@ -99,22 +99,26 @@ AffineTransform SVGMarkerElement::viewBoxToViewTransform(
} }
void SVGMarkerElement::svgAttributeChanged(const QualifiedName& attrName) { void SVGMarkerElement::svgAttributeChanged(const QualifiedName& attrName) {
bool isLengthAttr = attrName == SVGNames::refXAttr || bool viewboxAttributeChanged = SVGFitToViewBox::isKnownAttribute(attrName);
attrName == SVGNames::refYAttr || bool lengthAttributeChanged = attrName == SVGNames::refXAttr ||
attrName == SVGNames::markerWidthAttr || attrName == SVGNames::refYAttr ||
attrName == SVGNames::markerHeightAttr; attrName == SVGNames::markerWidthAttr ||
attrName == SVGNames::markerHeightAttr;
if (isLengthAttr) if (lengthAttributeChanged)
updateRelativeLengthsInformation(); updateRelativeLengthsInformation();
if (isLengthAttr || attrName == SVGNames::markerUnitsAttr || if (viewboxAttributeChanged || lengthAttributeChanged ||
attrName == SVGNames::orientAttr || attrName == SVGNames::markerUnitsAttr ||
SVGFitToViewBox::isKnownAttribute(attrName)) { attrName == SVGNames::orientAttr) {
SVGElement::InvalidationGuard invalidationGuard(this); SVGElement::InvalidationGuard invalidationGuard(this);
LayoutSVGResourceContainer* layoutObject = auto* resourceContainer = toLayoutSVGResourceContainer(layoutObject());
toLayoutSVGResourceContainer(this->layoutObject()); if (resourceContainer) {
if (layoutObject) // The marker transform depends on both viewbox attributes, and the marker
layoutObject->invalidateCacheAndMarkForLayout(); // size attributes (width, height).
if (viewboxAttributeChanged || lengthAttributeChanged)
resourceContainer->setNeedsTransformUpdate();
resourceContainer->invalidateCacheAndMarkForLayout();
}
return; return;
} }
......
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