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

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/1282930Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#601099}
parent a337f08f
......@@ -91,5 +91,7 @@ blink_core_sources("svg_layout") {
"svg_text_metrics.h",
"svg_text_query.cc",
"svg_text_query.h",
"transformed_hit_test_location.cc",
"transformed_hit_test_location.h",
]
}
......@@ -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 @@ bool LayoutSVGContainer::NodeAtPoint(
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))
......
......@@ -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 @@ bool LayoutSVGForeignObject::NodeAtPointFromSVG(
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);
......
......@@ -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 @@ bool LayoutSVGImage::NodeAtPoint(HitTestResult& result,
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 @@ bool LayoutSVGImage::NodeAtPoint(HitTestResult& result,
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_)) {
......
......@@ -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 @@ bool LayoutSVGRoot::NodeAtPoint(HitTestResult& result,
(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,
......
......@@ -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 @@ bool LayoutSVGShape::NodeAtPoint(HitTestResult& result,
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,
......
......@@ -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 @@ bool LayoutSVGText::NodeAtPoint(HitTestResult& result,
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))
......
......@@ -411,6 +411,11 @@ bool SVGLayoutSupport::HasFilterResource(const LayoutObject& object) {
return resources && resources->Filter();
}
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();
......@@ -430,36 +435,6 @@ bool SVGLayoutSupport::IntersectsClipPath(const LayoutObject& object,
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,
......
......@@ -75,18 +75,7 @@ class CORE_EXPORT SVGLayoutSupport {
// 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,
......
// 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
// 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_
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