Commit c5166e1c authored by Fredrik Söderquist's avatar Fredrik Söderquist Committed by Commit Bot

Refactor SVG transform handling

Move common (or to-be-common) code into a new TransformHelper class.
This class contains logic for computing the reference box as well as the
transform based on computed style. Also move the other transform-related
helper SVGTransformChangeDetector to this new location.
Some to-be-common code is moved from LayoutSVGShape to the super-class,
for reuse by LayoutSVGImage.
In LayoutSVGShape, set the |transform_uses_reference_box_| flag on style
change rather than during layout.

Bug: 1007146
Change-Id: Ie61537126a488a5c6c91cf416351ec2e28c692c9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1821919
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Cr-Commit-Position: refs/heads/master@{#699687}
parent 69fc841b
...@@ -39,10 +39,11 @@ ...@@ -39,10 +39,11 @@
#include "third_party/blink/renderer/core/layout/layout_block.h" #include "third_party/blink/renderer/core/layout/layout_block.h"
#include "third_party/blink/renderer/core/layout/layout_box.h" #include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_grid.h" #include "third_party/blink/renderer/core/layout/layout_grid.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h" #include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/core/style/style_svg_resource.h" #include "third_party/blink/renderer/core/style/style_svg_resource.h"
#include "third_party/blink/renderer/core/style_property_shorthand.h" #include "third_party/blink/renderer/core/style_property_shorthand.h"
#include "third_party/blink/renderer/core/svg/svg_element.h" #include "third_party/blink/renderer/core/svg_element_type_helpers.h"
namespace blink { namespace blink {
...@@ -1697,7 +1698,7 @@ FloatRect ComputedStyleUtils::ReferenceBoxForTransform( ...@@ -1697,7 +1698,7 @@ FloatRect ComputedStyleUtils::ReferenceBoxForTransform(
const LayoutObject& layout_object, const LayoutObject& layout_object,
UsePixelSnappedBox pixel_snap_box) { UsePixelSnappedBox pixel_snap_box) {
if (layout_object.IsSVGChild()) if (layout_object.IsSVGChild())
return ComputeSVGTransformReferenceBox(layout_object); return TransformHelper::ComputeReferenceBox(layout_object);
if (layout_object.IsBox()) { if (layout_object.IsBox()) {
const auto& layout_box = ToLayoutBox(layout_object); const auto& layout_box = ToLayoutBox(layout_object);
if (pixel_snap_box == kUsePixelSnappedBox) if (pixel_snap_box == kUsePixelSnappedBox)
......
...@@ -91,6 +91,8 @@ blink_core_sources("svg_layout") { ...@@ -91,6 +91,8 @@ blink_core_sources("svg_layout") {
"svg_text_metrics.h", "svg_text_metrics.h",
"svg_text_query.cc", "svg_text_query.cc",
"svg_text_query.h", "svg_text_query.h",
"transform_helper.cc",
"transform_helper.h",
"transformed_hit_test_location.cc", "transformed_hit_test_location.cc",
"transformed_hit_test_location.h", "transformed_hit_test_location.h",
] ]
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h" #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h" #include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h" #include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h" #include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
#include "third_party/blink/renderer/core/paint/svg_container_painter.h" #include "third_party/blink/renderer/core/paint/svg_container_painter.h"
......
...@@ -97,6 +97,27 @@ void LayoutSVGModelObject::WillBeDestroyed() { ...@@ -97,6 +97,27 @@ void LayoutSVGModelObject::WillBeDestroyed() {
LayoutObject::WillBeDestroyed(); LayoutObject::WillBeDestroyed();
} }
AffineTransform LayoutSVGModelObject::CalculateLocalTransform() const {
auto* element = GetElement();
if (element->HasTransform(SVGElement::kIncludeMotionTransform))
return element->CalculateTransform(SVGElement::kIncludeMotionTransform);
return AffineTransform();
}
bool LayoutSVGModelObject::CheckForImplicitTransformChange(
bool bbox_changed) const {
// If the transform is relative to the reference box, check relevant
// conditions to see if we need to recompute the transform.
switch (StyleRef().TransformBox()) {
case ETransformBox::kViewBox:
return SVGLayoutSupport::LayoutSizeOfNearestViewportChanged(this);
case ETransformBox::kFillBox:
return bbox_changed;
}
NOTREACHED();
return false;
}
void LayoutSVGModelObject::StyleDidChange(StyleDifference diff, void LayoutSVGModelObject::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) { const ComputedStyle* old_style) {
// Since layout depends on the bounds of the filter, we need to force layout // Since layout depends on the bounds of the filter, we need to force layout
......
...@@ -80,6 +80,9 @@ class LayoutSVGModelObject : public LayoutObject { ...@@ -80,6 +80,9 @@ class LayoutSVGModelObject : public LayoutObject {
protected: protected:
void WillBeDestroyed() override; void WillBeDestroyed() override;
AffineTransform CalculateLocalTransform() const;
bool CheckForImplicitTransformChange(bool bbox_changed) const;
private: private:
// LayoutSVGModelObject subclasses should use GetElement() instead. // LayoutSVGModelObject subclasses should use GetElement() instead.
void GetNode() const = delete; void GetNode() const = delete;
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h"
#include "base/auto_reset.h" #include "base/auto_reset.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h" #include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
namespace blink { namespace blink {
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h" #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h" #include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h" #include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h" #include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/svg_root_painter.h" #include "third_party/blink/renderer/core/paint/svg_root_painter.h"
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h" #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h" #include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h" #include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h" #include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
#include "third_party/blink/renderer/core/paint/svg_shape_painter.h" #include "third_party/blink/renderer/core/paint/svg_shape_painter.h"
#include "third_party/blink/renderer/core/svg/svg_geometry_element.h" #include "third_party/blink/renderer/core/svg/svg_geometry_element.h"
...@@ -58,14 +59,14 @@ LayoutSVGShape::LayoutSVGShape(SVGGeometryElement* node, ...@@ -58,14 +59,14 @@ LayoutSVGShape::LayoutSVGShape(SVGGeometryElement* node,
// Default is true, so we grab a AffineTransform object once from // Default is true, so we grab a AffineTransform object once from
// SVGGeometryElement. // SVGGeometryElement.
needs_transform_update_(true), needs_transform_update_(true),
// Default to false, since |needs_transform_update_| is true this will be
// updated the first time transforms are updated.
transform_uses_reference_box_(false) {} transform_uses_reference_box_(false) {}
LayoutSVGShape::~LayoutSVGShape() = default; LayoutSVGShape::~LayoutSVGShape() = default;
void LayoutSVGShape::StyleDidChange(StyleDifference diff, void LayoutSVGShape::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) { const ComputedStyle* old_style) {
transform_uses_reference_box_ =
TransformHelper::DependsOnReferenceBox(StyleRef());
LayoutSVGModelObject::StyleDidChange(diff, old_style); LayoutSVGModelObject::StyleDidChange(diff, old_style);
SVGResources::UpdatePaints(*GetElement(), old_style, StyleRef()); SVGResources::UpdatePaints(*GetElement(), old_style, StyleRef());
} }
...@@ -94,7 +95,7 @@ void LayoutSVGShape::UpdateShapeFromElement() { ...@@ -94,7 +95,7 @@ void LayoutSVGShape::UpdateShapeFromElement() {
if (HasNonScalingStroke()) { if (HasNonScalingStroke()) {
// NonScalingStrokeTransform may depend on LocalTransform which in turn may // NonScalingStrokeTransform may depend on LocalTransform which in turn may
// depend on ObjectBoundingBox, thus we need to call them in this order. // depend on ObjectBoundingBox, thus we need to call them in this order.
UpdateLocalTransform(); local_transform_ = CalculateLocalTransform();
UpdateNonScalingStrokeData(); UpdateNonScalingStrokeData();
} }
...@@ -209,42 +210,6 @@ bool LayoutSVGShape::StrokeContains(const HitTestLocation& location, ...@@ -209,42 +210,6 @@ bool LayoutSVGShape::StrokeContains(const HitTestLocation& location,
return ShapeDependentStrokeContains(location); return ShapeDependentStrokeContains(location);
} }
static inline bool TransformOriginIsFixed(const ComputedStyle& style) {
// If the transform box is view-box and the transform origin is absolute, then
// is does not depend on the reference box. For fill-box, the origin will
// always move with the bounding box.
return style.TransformBox() == ETransformBox::kViewBox &&
style.TransformOriginX().IsFixed() &&
style.TransformOriginY().IsFixed();
}
static inline bool TransformDependsOnReferenceBox(const ComputedStyle& style) {
// We're passing kExcludeMotionPath here because we're checking that
// explicitly later.
if (!TransformOriginIsFixed(style) &&
style.RequireTransformOrigin(ComputedStyle::kIncludeTransformOrigin,
ComputedStyle::kExcludeMotionPath))
return true;
if (style.Transform().DependsOnBoxSize())
return true;
if (style.Translate() && style.Translate()->DependsOnBoxSize())
return true;
if (style.HasOffset())
return true;
return false;
}
bool LayoutSVGShape::UpdateLocalTransform() {
auto* graphics_element = To<SVGGraphicsElement>(GetElement());
if (graphics_element->HasTransform(SVGElement::kIncludeMotionTransform)) {
local_transform_.SetTransform(graphics_element->CalculateTransform(
SVGElement::kIncludeMotionTransform));
return TransformDependsOnReferenceBox(StyleRef());
}
local_transform_ = AffineTransform();
return false;
}
void LayoutSVGShape::UpdateLayout() { void LayoutSVGShape::UpdateLayout() {
LayoutAnalyzer::Scope analyzer(*this); LayoutAnalyzer::Scope analyzer(*this);
...@@ -278,24 +243,14 @@ void LayoutSVGShape::UpdateLayout() { ...@@ -278,24 +243,14 @@ void LayoutSVGShape::UpdateLayout() {
update_parent_boundaries = true; update_parent_boundaries = true;
} }
// If the transform is relative to the reference box, check relevant
// conditions to see if we need to recompute the transform.
if (!needs_transform_update_ && transform_uses_reference_box_) { if (!needs_transform_update_ && transform_uses_reference_box_) {
switch (StyleRef().TransformBox()) { needs_transform_update_ = CheckForImplicitTransformChange(bbox_changed);
case ETransformBox::kViewBox:
needs_transform_update_ =
SVGLayoutSupport::LayoutSizeOfNearestViewportChanged(this);
break;
case ETransformBox::kFillBox:
needs_transform_update_ = bbox_changed;
break;
}
if (needs_transform_update_) if (needs_transform_update_)
SetNeedsPaintPropertyUpdate(); SetNeedsPaintPropertyUpdate();
} }
if (needs_transform_update_) { if (needs_transform_update_) {
transform_uses_reference_box_ = UpdateLocalTransform(); local_transform_ = CalculateLocalTransform();
needs_transform_update_ = false; needs_transform_update_ = false;
update_parent_boundaries = true; update_parent_boundaries = true;
} }
......
...@@ -179,7 +179,6 @@ class LayoutSVGShape : public LayoutSVGModelObject { ...@@ -179,7 +179,6 @@ class LayoutSVGShape : public LayoutSVGModelObject {
FloatRect ApproximateStrokeBoundingBox(const FloatRect& shape_bounds) const; FloatRect ApproximateStrokeBoundingBox(const FloatRect& shape_bounds) const;
FloatRect CalculateNonScalingStrokeBoundingBox() const; FloatRect CalculateNonScalingStrokeBoundingBox() const;
void UpdateNonScalingStrokeData(); void UpdateNonScalingStrokeData();
bool UpdateLocalTransform();
private: private:
AffineTransform local_transform_; AffineTransform local_transform_;
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h" #include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/svg/svg_g_element.h" #include "third_party/blink/renderer/core/svg/svg_g_element.h"
#include "third_party/blink/renderer/core/svg/svg_graphics_element.h" #include "third_party/blink/renderer/core/svg/svg_graphics_element.h"
#include "third_party/blink/renderer/core/svg/svg_use_element.h" #include "third_party/blink/renderer/core/svg/svg_use_element.h"
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h" #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/svg/svg_svg_element.h" #include "third_party/blink/renderer/core/svg/svg_svg_element.h"
namespace blink { namespace blink {
......
...@@ -178,41 +178,6 @@ class SubtreeContentTransformScope { ...@@ -178,41 +178,6 @@ class SubtreeContentTransformScope {
AffineTransform saved_content_transformation_; AffineTransform saved_content_transformation_;
}; };
// The following enumeration is used to optimize cases where the scale is known
// to be invariant (see: LayoutSVGContainer::layout and LayoutSVGroot). The
// value 'Full' can be used in the general case when the scale change is
// unknown, or known to change.
enum class SVGTransformChange {
kNone,
kScaleInvariant,
kFull,
};
// Helper for computing ("classifying") a change to a transform using the
// categoies defined above.
class SVGTransformChangeDetector {
STACK_ALLOCATED();
public:
explicit SVGTransformChangeDetector(const AffineTransform& previous)
: previous_transform_(previous) {}
SVGTransformChange ComputeChange(const AffineTransform& current) {
if (previous_transform_ == current)
return SVGTransformChange::kNone;
if (ScaleReference(previous_transform_) == ScaleReference(current))
return SVGTransformChange::kScaleInvariant;
return SVGTransformChange::kFull;
}
private:
static std::pair<double, double> ScaleReference(
const AffineTransform& transform) {
return std::make_pair(transform.XScaleSquared(), transform.YScaleSquared());
}
AffineTransform previous_transform_;
};
template <typename LayoutObjectType> template <typename LayoutObjectType>
bool SVGLayoutSupport::ComputeHasNonIsolatedBlendingDescendants( bool SVGLayoutSupport::ComputeHasNonIsolatedBlendingDescendants(
const LayoutObjectType* object) { const LayoutObjectType* object) {
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/svg/svg_element.h"
#include "third_party/blink/renderer/core/svg/svg_length_context.h"
#include "third_party/blink/renderer/platform/geometry/float_rect.h"
#include "third_party/blink/renderer/platform/geometry/float_size.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
namespace blink {
static inline bool TransformOriginIsFixed(const ComputedStyle& style) {
// If the transform box is view-box and the transform origin is absolute,
// then is does not depend on the reference box. For fill-box, the origin
// will always move with the bounding box.
return style.TransformBox() == ETransformBox::kViewBox &&
style.TransformOriginX().IsFixed() &&
style.TransformOriginY().IsFixed();
}
bool TransformHelper::DependsOnReferenceBox(const ComputedStyle& style) {
// We're passing kExcludeMotionPath here because we're checking that
// explicitly later.
if (!TransformOriginIsFixed(style) &&
style.RequireTransformOrigin(ComputedStyle::kIncludeTransformOrigin,
ComputedStyle::kExcludeMotionPath))
return true;
if (style.Transform().DependsOnBoxSize())
return true;
if (style.Translate() && style.Translate()->DependsOnBoxSize())
return true;
if (style.HasOffset())
return true;
return false;
}
FloatRect TransformHelper::ComputeReferenceBox(
const LayoutObject& layout_object) {
const ComputedStyle& style = layout_object.StyleRef();
FloatRect reference_box;
if (style.TransformBox() == ETransformBox::kFillBox) {
reference_box = layout_object.ObjectBoundingBox();
} else {
DCHECK_EQ(style.TransformBox(), ETransformBox::kViewBox);
SVGLengthContext length_context(
DynamicTo<SVGElement>(layout_object.GetNode()));
FloatSize viewport_size;
length_context.DetermineViewport(viewport_size);
reference_box.SetSize(viewport_size);
}
const float zoom = style.EffectiveZoom();
if (zoom != 1)
reference_box.Scale(zoom);
return reference_box;
}
AffineTransform TransformHelper::ComputeTransform(
const LayoutObject& layout_object) {
const ComputedStyle& style = layout_object.StyleRef();
if (DependsOnReferenceBox(style)) {
UseCounter::Count(layout_object.GetDocument(),
WebFeature::kTransformUsesBoxSizeOnSVG);
}
// CSS transforms operate with pre-scaled lengths. To make this work with SVG
// (which applies the zoom factor globally, at the root level) we
//
// * pre-scale the reference box (to bring it into the same space as the
// other CSS values) (Handled by ComputeSVGTransformReferenceBox)
// * invert the zoom factor (to effectively compute the CSS transform under
// a 1.0 zoom)
//
// Note: objectBoundingBox is an empty rect for elements like pattern or
// clipPath. See
// https://svgwg.org/svg2-draft/coords.html#ObjectBoundingBoxUnits
TransformationMatrix transform;
FloatRect reference_box = ComputeReferenceBox(layout_object);
style.ApplyTransform(transform, reference_box,
ComputedStyle::kIncludeTransformOrigin,
ComputedStyle::kIncludeMotionPath,
ComputedStyle::kIncludeIndependentTransformProperties);
const float zoom = style.EffectiveZoom();
if (zoom != 1)
transform.Zoom(1 / zoom);
// Flatten any 3D transform.
return transform.ToAffineTransform();
}
} // namespace blink
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_TRANSFORM_HELPER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_TRANSFORM_HELPER_H_
#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
class ComputedStyle;
class FloatRect;
class LayoutObject;
class TransformHelper {
STATIC_ONLY(TransformHelper);
public:
// Returns true if the passed in ComputedStyle has a transform that needs to
// resolve against the reference box.
static bool DependsOnReferenceBox(const ComputedStyle&);
// Computes the reference box for the LayoutObject based on the
// 'transform-box'. Applies zoom if needed.
static FloatRect ComputeReferenceBox(const LayoutObject&);
// Compute the transform for the LayoutObject based on the various
// 'transform*' properties.
static AffineTransform ComputeTransform(const LayoutObject&);
};
// The following enumeration is used to optimize cases where the scale is known
// to be invariant (see: LayoutSVGContainer::UpdateLayout and
// LayoutSVGRoot). The value 'Full' can be used in the general case when the
// scale change is unknown, or known to have changed.
enum class SVGTransformChange {
kNone,
kScaleInvariant,
kFull,
};
// Helper for computing ("classifying") a change to a transform using the
// categories defined above.
class SVGTransformChangeDetector {
STACK_ALLOCATED();
public:
explicit SVGTransformChangeDetector(const AffineTransform& previous)
: previous_transform_(previous) {}
SVGTransformChange ComputeChange(const AffineTransform& current) {
if (previous_transform_ == current)
return SVGTransformChange::kNone;
if (ScaleReference(previous_transform_) == ScaleReference(current))
return SVGTransformChange::kScaleInvariant;
return SVGTransformChange::kFull;
}
private:
static std::pair<double, double> ScaleReference(
const AffineTransform& transform) {
return std::make_pair(transform.XScaleSquared(), transform.YScaleSquared());
}
AffineTransform previous_transform_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_TRANSFORM_HELPER_H_
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/svg/properties/svg_property.h" #include "third_party/blink/renderer/core/svg/properties/svg_property.h"
#include "third_party/blink/renderer/core/svg/svg_document_extensions.h" #include "third_party/blink/renderer/core/svg/svg_document_extensions.h"
#include "third_party/blink/renderer/core/svg/svg_element_rare_data.h" #include "third_party/blink/renderer/core/svg/svg_element_rare_data.h"
...@@ -59,7 +60,6 @@ ...@@ -59,7 +60,6 @@
#include "third_party/blink/renderer/core/svg_names.h" #include "third_party/blink/renderer/core/svg_names.h"
#include "third_party/blink/renderer/core/xml_names.h" #include "third_party/blink/renderer/core/xml_names.h"
#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/wtf/threading.h" #include "third_party/blink/renderer/platform/wtf/threading.h"
namespace blink { namespace blink {
...@@ -297,76 +297,13 @@ bool SVGElement::HasTransform( ...@@ -297,76 +297,13 @@ bool SVGElement::HasTransform(
HasSVGRareData()); HasSVGRareData());
} }
static inline bool TransformUsesBoxSize(const ComputedStyle& style) {
if ((style.TransformOriginX().IsPercent() ||
style.TransformOriginY().IsPercent()) &&
style.RequireTransformOrigin(ComputedStyle::kIncludeTransformOrigin,
ComputedStyle::kExcludeMotionPath))
return true;
if (style.Transform().DependsOnBoxSize())
return true;
if (style.Translate() && style.Translate()->DependsOnBoxSize())
return true;
if (style.HasOffset())
return true;
return false;
}
FloatRect ComputeSVGTransformReferenceBox(const LayoutObject& layout_object) {
const ComputedStyle& style = layout_object.StyleRef();
FloatRect reference_box;
if (style.TransformBox() == ETransformBox::kFillBox) {
reference_box = layout_object.ObjectBoundingBox();
} else {
DCHECK_EQ(style.TransformBox(), ETransformBox::kViewBox);
SVGLengthContext length_context(
DynamicTo<SVGElement>(layout_object.GetNode()));
FloatSize viewport_size;
length_context.DetermineViewport(viewport_size);
reference_box.SetSize(viewport_size);
}
const float zoom = style.EffectiveZoom();
if (zoom != 1)
reference_box.Scale(zoom);
return reference_box;
}
AffineTransform SVGElement::CalculateTransform( AffineTransform SVGElement::CalculateTransform(
ApplyMotionTransform apply_motion_transform) const { ApplyMotionTransform apply_motion_transform) const {
const ComputedStyle* style = const LayoutObject* layout_object = GetLayoutObject();
GetLayoutObject() ? GetLayoutObject()->Style() : nullptr;
// If CSS property was set, use that, otherwise fallback to attribute (if
// set).
AffineTransform matrix; AffineTransform matrix;
if (style && style->HasTransform()) { if (layout_object && layout_object->StyleRef().HasTransform())
if (TransformUsesBoxSize(*style)) matrix = TransformHelper::ComputeTransform(*layout_object);
UseCounter::Count(GetDocument(), WebFeature::kTransformUsesBoxSizeOnSVG);
// CSS transforms operate with pre-scaled lengths. To make this work with
// SVG (which applies the zoom factor globally, at the root level) we
//
// * pre-scale the reference box (to bring it into the same space as the
// other CSS values) (Handled by ComputeSVGTransformReferenceBox)
// * invert the zoom factor (to effectively compute the CSS transform
// under a 1.0 zoom)
//
// Note: objectBoundingBox is an emptyRect for elements like pattern or
// clipPath. See
// https://svgwg.org/svg2-draft/coords.html#ObjectBoundingBoxUnits
TransformationMatrix transform;
FloatRect reference_box =
ComputeSVGTransformReferenceBox(*GetLayoutObject());
style->ApplyTransform(
transform, reference_box, ComputedStyle::kIncludeTransformOrigin,
ComputedStyle::kIncludeMotionPath,
ComputedStyle::kIncludeIndependentTransformProperties);
const float zoom = style->EffectiveZoom();
if (zoom != 1)
transform.Zoom(1 / zoom);
// Flatten any 3D transform.
matrix = transform.ToAffineTransform();
}
// Apply any "motion transform" contribution if requested (and existing.) // Apply any "motion transform" contribution if requested (and existing.)
if (apply_motion_transform == kIncludeMotionTransform && HasSVGRareData()) if (apply_motion_transform == kIncludeMotionTransform && HasSVGRareData())
......
...@@ -37,7 +37,6 @@ namespace blink { ...@@ -37,7 +37,6 @@ namespace blink {
class AffineTransform; class AffineTransform;
class Document; class Document;
class FloatRect;
class SVGAnimatedPropertyBase; class SVGAnimatedPropertyBase;
class SubtreeLayoutScope; class SubtreeLayoutScope;
class SVGAnimatedString; class SVGAnimatedString;
...@@ -334,8 +333,6 @@ struct SVGAttributeHashTranslator { ...@@ -334,8 +333,6 @@ struct SVGAttributeHashTranslator {
} }
}; };
FloatRect ComputeSVGTransformReferenceBox(const LayoutObject&);
DEFINE_ELEMENT_TYPE_CASTS(SVGElement, IsSVGElement()); DEFINE_ELEMENT_TYPE_CASTS(SVGElement, IsSVGElement());
template <> template <>
......
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