Add TransformedHitTestLocation helper
This moves code for transforming a HitTestLocation using with an
AffineTransform from the helper function
SVGLayoutSupport::TransformToUserSpaceAndCheckClipping into a helper
class TransformedHitTestLocation.
Calls to SVGLayoutSupport::IntersectsClipPath are hoisted into callers
and SVGLayoutSupport::TransformToUserSpaceAndCheckClipping is removed.
Change-Id: I52f95ba2480df86a509285c2ec2edea776517bc6
Reviewed-on: https://chromium-review.googlesource.com/c/1282930
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#601099}
diff --git a/third_party/blink/renderer/core/layout/svg/BUILD.gn b/third_party/blink/renderer/core/layout/svg/BUILD.gn
index 470debe..8d013890 100644
--- a/third_party/blink/renderer/core/layout/svg/BUILD.gn
+++ b/third_party/blink/renderer/core/layout/svg/BUILD.gn
@@ -91,5 +91,7 @@
"svg_text_metrics.h",
"svg_text_query.cc",
"svg_text_query.h",
+ "transformed_hit_test_location.cc",
+ "transformed_hit_test_location.h",
]
}
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
index 23ec081..c2de62b 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
@@ -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_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.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"
namespace blink {
@@ -179,13 +180,12 @@
const LayoutPoint& accumulated_offset,
HitTestAction hit_test_action) {
DCHECK_EQ(accumulated_offset, LayoutPoint());
- base::Optional<HitTestLocation> local_storage;
- const HitTestLocation* local_location =
- SVGLayoutSupport::TransformToUserSpaceAndCheckClipping(
- *this, LocalToSVGParentTransform(), location_in_container,
- local_storage);
+ TransformedHitTestLocation local_location(location_in_container,
+ LocalToSVGParentTransform());
if (!local_location)
return false;
+ if (!SVGLayoutSupport::IntersectsClipPath(*this, *local_location))
+ return false;
if (SVGLayoutSupport::HitTestChildren(LastChild(), result, *local_location,
accumulated_offset, hit_test_action))
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
index 4ef7808..cd3401b 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
@@ -24,6 +24,7 @@
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.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/svg_foreign_object_painter.h"
#include "third_party/blink/renderer/core/svg/svg_foreign_object_element.h"
@@ -130,23 +131,13 @@
const LayoutPoint& accumulated_offset,
HitTestAction) {
DCHECK_EQ(accumulated_offset, LayoutPoint());
- AffineTransform local_transform = LocalSVGTransform();
- if (!local_transform.IsInvertible())
+ TransformedHitTestLocation local_location(location_in_parent,
+ LocalSVGTransform());
+ if (!local_location)
return false;
- AffineTransform inverse = local_transform.Inverse();
- base::Optional<HitTestLocation> local_location;
- if (location_in_parent.IsRectBasedTest()) {
- local_location.emplace(
- inverse.MapPoint(location_in_parent.TransformedPoint()),
- inverse.MapQuad(location_in_parent.TransformedRect()));
- } else {
- local_location.emplace(
- (inverse.MapPoint(location_in_parent.TransformedPoint())));
- }
-
- // |local_point| already includes the offset of the <foreignObject> element,
- // but PaintLayer::HitTestLayer assumes it has not been.
+ // |local_location| already includes the offset of the <foreignObject>
+ // element, but PaintLayer::HitTestLayer assumes it has not been.
HitTestLocation local_without_offset(
*local_location, -ToLayoutSize(Layer()->LayoutBoxLocation()));
HitTestResult layer_result(result.GetHitTestRequest(), local_without_offset);
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
index 1db7446..12f9d1c 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
@@ -34,6 +34,7 @@
#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_cache.h"
+#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
#include "third_party/blink/renderer/core/paint/svg_image_painter.h"
#include "third_party/blink/renderer/core/svg/svg_image_element.h"
#include "third_party/blink/renderer/platform/geometry/length_functions.h"
@@ -170,7 +171,7 @@
const HitTestLocation& location_in_container,
const LayoutPoint& accumulated_offset,
HitTestAction hit_test_action) {
- DCHECK(accumulated_offset == LayoutPoint());
+ DCHECK_EQ(accumulated_offset, LayoutPoint());
// We only draw in the forground phase, so we only hit-test then.
if (hit_test_action != kHitTestForeground)
return false;
@@ -182,13 +183,12 @@
if (hit_rules.require_visible && style.Visibility() != EVisibility::kVisible)
return false;
- base::Optional<HitTestLocation> local_storage;
- const HitTestLocation* local_location =
- SVGLayoutSupport::TransformToUserSpaceAndCheckClipping(
- *this, LocalToSVGParentTransform(), location_in_container,
- local_storage);
+ TransformedHitTestLocation local_location(location_in_container,
+ LocalToSVGParentTransform());
if (!local_location)
return false;
+ if (!SVGLayoutSupport::IntersectsClipPath(*this, *local_location))
+ return false;
if (hit_rules.can_hit_fill || hit_rules.can_hit_bounding_box) {
if (local_location->Intersects(object_bounding_box_)) {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
index b016e40..12f9895a 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
@@ -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_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.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/svg_root_painter.h"
#include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
@@ -523,23 +524,9 @@
(local_border_box_location.Intersects(PhysicalContentBoxRect()) ||
(!ShouldApplyViewportClip() &&
local_border_box_location.Intersects(VisualOverflowRect())))) {
- const AffineTransform& local_to_border_box_transform =
- LocalToBorderBoxTransform();
- if (local_to_border_box_transform.IsInvertible()) {
- AffineTransform inverse = local_to_border_box_transform.Inverse();
- FloatPoint local_point =
- inverse.MapPoint(local_border_box_location.TransformedPoint());
-
- base::Optional<HitTestLocation> local_location;
- if (location_in_container.IsRectBasedTest()) {
- FloatQuad quad_in_container =
- local_border_box_location.TransformedRect();
-
- local_location.emplace(local_point, inverse.MapQuad(quad_in_container));
- } else {
- local_location.emplace(local_point);
- }
-
+ TransformedHitTestLocation local_location(local_border_box_location,
+ LocalToBorderBoxTransform());
+ if (local_location) {
LayoutPoint accumulated_offset_for_children;
if (SVGLayoutSupport::HitTestChildren(
LastChild(), result, *local_location,
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
index 187e189..b8f1e08 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
@@ -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_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.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/svg/svg_geometry_element.h"
#include "third_party/blink/renderer/core/svg/svg_length_context.h"
@@ -347,13 +348,12 @@
if (hit_test_action != kHitTestForeground)
return false;
- base::Optional<HitTestLocation> local_storage;
- const HitTestLocation* local_location =
- SVGLayoutSupport::TransformToUserSpaceAndCheckClipping(
- *this, LocalToSVGParentTransform(), location_in_parent,
- local_storage);
+ TransformedHitTestLocation local_location(location_in_parent,
+ LocalToSVGParentTransform());
if (!local_location)
return false;
+ if (!SVGLayoutSupport::IntersectsClipPath(*this, *local_location))
+ return false;
PointerEventsHitRules hit_rules(
PointerEventsHitRules::SVG_GEOMETRY_HITTESTING,
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
index b187ea3..ae2a595d 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
@@ -41,6 +41,7 @@
#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_text_layout_attributes_builder.h"
+#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
#include "third_party/blink/renderer/core/paint/svg_text_painter.h"
#include "third_party/blink/renderer/core/style/shadow_list.h"
#include "third_party/blink/renderer/core/svg/svg_text_element.h"
@@ -314,13 +315,12 @@
if (hit_test_action != kHitTestForeground)
return false;
- base::Optional<HitTestLocation> local_storage;
- const HitTestLocation* local_location =
- SVGLayoutSupport::TransformToUserSpaceAndCheckClipping(
- *this, LocalToSVGParentTransform(), location_in_parent,
- local_storage);
+ TransformedHitTestLocation local_location(location_in_parent,
+ LocalToSVGParentTransform());
if (!local_location)
return false;
+ if (!SVGLayoutSupport::IntersectsClipPath(*this, *local_location))
+ return false;
if (LayoutBlock::NodeAtPoint(result, *local_location, accumulated_offset,
hit_test_action))
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
index c1e6a52..4cd2fcc 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
@@ -412,6 +412,11 @@
}
bool SVGLayoutSupport::IntersectsClipPath(const LayoutObject& object,
+ const HitTestLocation& location) {
+ return IntersectsClipPath(object, location.TransformedPoint());
+}
+
+bool SVGLayoutSupport::IntersectsClipPath(const LayoutObject& object,
const FloatPoint& point) {
ClipPathOperation* clip_path_operation = object.StyleRef().ClipPath();
if (!clip_path_operation)
@@ -430,36 +435,6 @@
point);
}
-const HitTestLocation* SVGLayoutSupport::TransformToUserSpaceAndCheckClipping(
- const LayoutObject& object,
- const AffineTransform& local_transform,
- const HitTestLocation& location_in_parent,
- base::Optional<HitTestLocation>& local_storage) {
- // Use a fast path for an identity transform which creates no new
- // HitTestLocation objects or inverse AffineTransforms, and performs no
- // matrix multiplies.
- if (local_transform.IsIdentity()) {
- if (IntersectsClipPath(object, location_in_parent.TransformedPoint()))
- return &location_in_parent;
- return nullptr;
- }
- if (!local_transform.IsInvertible())
- return nullptr;
- const AffineTransform inverse = local_transform.Inverse();
- if (location_in_parent.IsRectBasedTest()) {
- local_storage.emplace(
- HitTestLocation(inverse.MapPoint(location_in_parent.TransformedPoint()),
- inverse.MapQuad(location_in_parent.TransformedRect())));
- } else {
- local_storage.emplace(HitTestLocation(
- inverse.MapPoint(location_in_parent.TransformedPoint())));
- }
-
- if (IntersectsClipPath(object, local_storage->TransformedPoint()))
- return &*local_storage;
- return nullptr;
-}
-
bool SVGLayoutSupport::HitTestChildren(LayoutObject* last_child,
HitTestResult& result,
const HitTestLocation& location,
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_support.h b/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
index 4f2261a..e683dddc 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
+++ b/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
@@ -75,18 +75,7 @@
// Determine whether the passed point intersects the clip path of |object|.
static bool IntersectsClipPath(const LayoutObject&, const FloatPoint&);
-
- // Transform |location_in_parent| to |object|'s user-space and check if it is
- // within the clipping area. Returns a pointer to a HitTestLocation object
- // to use as the local location. Returns nullptr if the transform is singular
- // or the point is outside the clipping area. The object backing
- // the pointer is either |location_in_parent| or an emplacement of
- // |local_storage|.
- static const HitTestLocation* TransformToUserSpaceAndCheckClipping(
- const LayoutObject&,
- const AffineTransform& local_transform,
- const HitTestLocation& location_in_parent,
- base::Optional<HitTestLocation>& local_storage);
+ static bool IntersectsClipPath(const LayoutObject&, const HitTestLocation&);
// Shared child hit-testing code between LayoutSVGRoot/LayoutSVGContainer.
static bool HitTestChildren(LayoutObject* last_child,
diff --git a/third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.cc b/third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.cc
new file mode 100644
index 0000000..a576fcb
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.cc
@@ -0,0 +1,40 @@
+// Copyright 2018 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/transformed_hit_test_location.h"
+
+#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
+
+namespace blink {
+
+namespace {
+
+const HitTestLocation* InverseTransformLocationIfNeeded(
+ const HitTestLocation& location,
+ const AffineTransform& transform,
+ base::Optional<HitTestLocation>& storage) {
+ if (transform.IsIdentity())
+ return &location;
+ if (!transform.IsInvertible())
+ return nullptr;
+ const AffineTransform inverse = transform.Inverse();
+ FloatPoint transformed_point = inverse.MapPoint(location.TransformedPoint());
+ if (UNLIKELY(location.IsRectBasedTest())) {
+ storage.emplace(transformed_point,
+ inverse.MapQuad(location.TransformedRect()));
+ } else {
+ storage.emplace(transformed_point);
+ }
+ return &*storage;
+}
+
+} // namespace
+
+TransformedHitTestLocation::TransformedHitTestLocation(
+ const HitTestLocation& location,
+ const AffineTransform& transform)
+ : location_(
+ InverseTransformLocationIfNeeded(location, transform, storage_)) {}
+
+} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h b/third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h
new file mode 100644
index 0000000..07cfec0
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h
@@ -0,0 +1,48 @@
+// Copyright 2018 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_TRANSFORMED_HIT_TEST_LOCATION_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_TRANSFORMED_HIT_TEST_LOCATION_H_
+
+#include "base/optional.h"
+#include "third_party/blink/renderer/core/layout/hit_test_location.h"
+
+namespace blink {
+
+class AffineTransform;
+
+// Helper class handling the application of a AffineTransform to a
+// HitTestLocation - producing a new, transformed, HitTestLocation if needed.
+//
+// Encapsulates logic to avoid creating/copying the HitTestLocation for example
+// if the AffineTransform is the identity.
+class TransformedHitTestLocation {
+ DISALLOW_NEW();
+
+ public:
+ // The AffineTransform passed is expected to be the "forward"
+ // transform. The inverse will computed and applied (as needed.)
+ //
+ // If the transform is singular, the bool operator will return
+ // false, in which case the object cannot (must not) be used.
+ TransformedHitTestLocation(const HitTestLocation&, const AffineTransform&);
+
+ const HitTestLocation* operator->() const {
+ DCHECK(location_);
+ return location_;
+ }
+ const HitTestLocation& operator*() const {
+ DCHECK(location_);
+ return *location_;
+ }
+ explicit operator bool() const { return location_; }
+
+ private:
+ base::Optional<HitTestLocation> storage_;
+ const HitTestLocation* location_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_TRANSFORMED_HIT_TEST_LOCATION_H_