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

Plumb HitTestLocation further in LayoutSVG*

Plumb HitTestLocation into clip-path handling and
LayoutSVGShape::*Contains.

Change-Id: Ibd4e433e868ac427e637f906ff3d778fd33e1a80
Reviewed-on: https://chromium-review.googlesource.com/c/1291409Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#601413}
parent 9024e95a
......@@ -99,15 +99,17 @@ void LayoutSVGEllipse::CalculateRadiiAndCenter() {
}
}
bool LayoutSVGEllipse::ShapeDependentStrokeContains(const FloatPoint& point) {
bool LayoutSVGEllipse::ShapeDependentStrokeContains(
const HitTestLocation& location) {
if (radii_.Width() < 0 || radii_.Height() < 0)
return false;
// The optimized check below for circles does not support non-circular and
// the cases that we set use_path_fallback_ in UpdateShapeFromElement().
if (use_path_fallback_ || radii_.Width() != radii_.Height())
return LayoutSVGShape::ShapeDependentStrokeContains(point);
return LayoutSVGShape::ShapeDependentStrokeContains(location);
const FloatPoint& point = location.TransformedPoint();
const FloatPoint center =
FloatPoint(center_.X() - point.X(), center_.Y() - point.Y());
const float half_stroke_width = StrokeWidth() / 2;
......@@ -116,8 +118,9 @@ bool LayoutSVGEllipse::ShapeDependentStrokeContains(const FloatPoint& point) {
}
bool LayoutSVGEllipse::ShapeDependentFillContains(
const FloatPoint& point,
const HitTestLocation& location,
const WindRule fill_rule) const {
const FloatPoint& point = location.TransformedPoint();
const FloatPoint center =
FloatPoint(center_.X() - point.X(), center_.Y() - point.Y());
......
......@@ -48,8 +48,8 @@ class LayoutSVGEllipse final : public LayoutSVGShape {
return use_path_fallback_ ? LayoutSVGShape::IsShapeEmpty()
: fill_bounding_box_.IsEmpty();
}
bool ShapeDependentStrokeContains(const FloatPoint&) override;
bool ShapeDependentFillContains(const FloatPoint&,
bool ShapeDependentStrokeContains(const HitTestLocation&) override;
bool ShapeDependentFillContains(const HitTestLocation&,
const WindRule) const override;
void CalculateRadiiAndCenter();
bool HasContinuousStroke() const;
......
......@@ -80,12 +80,14 @@ void LayoutSVGRect::UpdateShapeFromElement() {
stroke_bounding_box_ = CalculateStrokeBoundingBox();
}
bool LayoutSVGRect::ShapeDependentStrokeContains(const FloatPoint& point) {
bool LayoutSVGRect::ShapeDependentStrokeContains(
const HitTestLocation& location) {
// The optimized code below does not support the cases that we set
// use_path_fallback_ in UpdateShapeFromElement().
if (use_path_fallback_)
return LayoutSVGShape::ShapeDependentStrokeContains(point);
return LayoutSVGShape::ShapeDependentStrokeContains(location);
const FloatPoint& point = location.TransformedPoint();
const float half_stroke_width = StrokeWidth() / 2;
const float half_width = fill_bounding_box_.Width() / 2;
const float half_height = fill_bounding_box_.Height() / 2;
......@@ -104,10 +106,11 @@ bool LayoutSVGRect::ShapeDependentStrokeContains(const FloatPoint& point) {
(half_height - half_stroke_width <= abs_delta_y);
}
bool LayoutSVGRect::ShapeDependentFillContains(const FloatPoint& point,
bool LayoutSVGRect::ShapeDependentFillContains(const HitTestLocation& location,
const WindRule fill_rule) const {
if (use_path_fallback_)
return LayoutSVGShape::ShapeDependentFillContains(point, fill_rule);
return LayoutSVGShape::ShapeDependentFillContains(location, fill_rule);
const FloatPoint& point = location.TransformedPoint();
return fill_bounding_box_.Contains(point.X(), point.Y());
}
......
......@@ -49,8 +49,8 @@ class LayoutSVGRect final : public LayoutSVGShape {
return use_path_fallback_ ? LayoutSVGShape::IsShapeEmpty()
: fill_bounding_box_.IsEmpty();
}
bool ShapeDependentStrokeContains(const FloatPoint&) override;
bool ShapeDependentFillContains(const FloatPoint&,
bool ShapeDependentStrokeContains(const HitTestLocation&) override;
bool ShapeDependentFillContains(const HitTestLocation&,
const WindRule) const override;
bool DefinitelyHasSimpleStroke() const;
......
......@@ -26,6 +26,7 @@
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/svg/svg_clip_path_element.h"
#include "third_party/blink/renderer/core/svg/svg_geometry_element.h"
......@@ -236,30 +237,26 @@ AffineTransform LayoutSVGResourceClipper::CalculateClipTransform(
bool LayoutSVGResourceClipper::HitTestClipContent(
const FloatRect& object_bounding_box,
const FloatPoint& node_at_point) {
FloatPoint point = node_at_point;
if (!SVGLayoutSupport::IntersectsClipPath(*this, point))
const HitTestLocation& location) const {
if (!SVGLayoutSupport::IntersectsClipPath(*this, location))
return false;
AffineTransform user_space_transform =
CalculateClipTransform(object_bounding_box);
if (!user_space_transform.IsInvertible())
TransformedHitTestLocation local_location(
location, CalculateClipTransform(object_bounding_box));
if (!local_location)
return false;
point = user_space_transform.Inverse().MapPoint(point);
HitTestResult result(HitTestRequest::kSVGClipContent, *local_location);
for (const SVGElement& child_element :
Traversal<SVGElement>::ChildrenOf(*GetElement())) {
if (!ContributesToClip(child_element))
continue;
HitTestLocation location(point);
HitTestResult result(HitTestRequest::kSVGClipContent, location);
LayoutObject* layout_object = child_element.GetLayoutObject();
DCHECK(!layout_object->IsBoxModelObject() ||
!ToLayoutBoxModelObject(layout_object)->HasSelfPaintingLayer());
if (layout_object->NodeAtPoint(result, location, LayoutPoint(),
if (layout_object->NodeAtPoint(result, *local_location, LayoutPoint(),
kHitTestForeground))
return true;
}
......
......@@ -42,7 +42,7 @@ class LayoutSVGResourceClipper final : public LayoutSVGResourceContainer {
static const LayoutSVGResourceType kResourceType = kClipperResourceType;
LayoutSVGResourceType ResourceType() const override { return kResourceType; }
bool HitTestClipContent(const FloatRect&, const FloatPoint&);
bool HitTestClipContent(const FloatRect&, const HitTestLocation&) const;
SVGUnitTypes::SVGUnitType ClipPathUnits() const;
AffineTransform CalculateClipTransform(const FloatRect& reference_box) const;
......
......@@ -146,7 +146,8 @@ FloatRect LayoutSVGShape::HitTestStrokeBoundingBox() const {
return ApproximateStrokeBoundingBox();
}
bool LayoutSVGShape::ShapeDependentStrokeContains(const FloatPoint& point) {
bool LayoutSVGShape::ShapeDependentStrokeContains(
const HitTestLocation& location) {
// In case the subclass didn't create path during UpdateShapeFromElement()
// for optimization but still calls this method.
if (!HasPath())
......@@ -161,50 +162,50 @@ bool LayoutSVGShape::ShapeDependentStrokeContains(const FloatPoint& point) {
if (!rare_data_)
UpdateNonScalingStrokeData();
return NonScalingStrokePath().StrokeContains(
NonScalingStrokeTransform().MapPoint(point), stroke_data);
NonScalingStrokeTransform().MapPoint(location.TransformedPoint()),
stroke_data);
}
return path_->StrokeContains(point, stroke_data);
return path_->StrokeContains(location.TransformedPoint(), stroke_data);
}
bool LayoutSVGShape::ShapeDependentFillContains(
const FloatPoint& point,
const HitTestLocation& location,
const WindRule fill_rule) const {
return GetPath().Contains(point, fill_rule);
return GetPath().Contains(location.TransformedPoint(), fill_rule);
}
bool LayoutSVGShape::FillContains(const FloatPoint& point,
bool LayoutSVGShape::FillContains(const HitTestLocation& location,
bool requires_fill,
const WindRule fill_rule) {
if (!fill_bounding_box_.Contains(point))
if (!fill_bounding_box_.Contains(location.TransformedPoint()))
return false;
if (requires_fill && !SVGPaintServer::ExistsForLayoutObject(*this, StyleRef(),
kApplyToFillMode))
return false;
return ShapeDependentFillContains(point, fill_rule);
return ShapeDependentFillContains(location, fill_rule);
}
bool LayoutSVGShape::StrokeContains(const FloatPoint& point,
bool LayoutSVGShape::StrokeContains(const HitTestLocation& location,
bool requires_stroke) {
// "A zero value causes no stroke to be painted."
if (StyleRef().SvgStyle().StrokeWidth().IsZero())
return false;
if (requires_stroke) {
if (!StrokeBoundingBox().Contains(point))
if (!StrokeBoundingBox().Contains(location.TransformedPoint()))
return false;
if (!SVGPaintServer::ExistsForLayoutObject(*this, StyleRef(),
kApplyToStrokeMode))
return false;
} else {
if (!HitTestStrokeBoundingBox().Contains(point))
if (!HitTestStrokeBoundingBox().Contains(location.TransformedPoint()))
return false;
}
return ShapeDependentStrokeContains(point);
return ShapeDependentStrokeContains(location);
}
static inline bool TransformOriginIsFixed(const ComputedStyle& style) {
......@@ -384,16 +385,14 @@ bool LayoutSVGShape::NodeAtPointInternal(const HitTestRequest& request,
const SVGComputedStyle& svg_style = style.SvgStyle();
if (hit_rules.can_hit_stroke &&
(svg_style.HasStroke() || !hit_rules.require_stroke) &&
StrokeContains(local_location.TransformedPoint(),
hit_rules.require_stroke))
StrokeContains(local_location, hit_rules.require_stroke))
return true;
WindRule fill_rule = svg_style.FillRule();
if (request.SvgClipContent())
fill_rule = svg_style.ClipRule();
if (hit_rules.can_hit_fill &&
(svg_style.HasFill() || !hit_rules.require_fill) &&
FillContains(local_location.TransformedPoint(), hit_rules.require_fill,
fill_rule))
FillContains(local_location, hit_rules.require_fill, fill_rule))
return true;
return false;
}
......
......@@ -36,7 +36,6 @@
namespace blink {
class FloatPoint;
class PointerEventsHitRules;
class SVGGeometryElement;
......@@ -140,8 +139,8 @@ class LayoutSVGShape : public LayoutSVGModelObject {
// Update (cached) shape data and the (object) bounding box.
virtual void UpdateShapeFromElement();
FloatRect CalculateStrokeBoundingBox() const;
virtual bool ShapeDependentStrokeContains(const FloatPoint&);
virtual bool ShapeDependentFillContains(const FloatPoint&,
virtual bool ShapeDependentStrokeContains(const HitTestLocation&);
virtual bool ShapeDependentFillContains(const HitTestLocation&,
const WindRule) const;
FloatRect fill_bounding_box_;
......@@ -151,10 +150,10 @@ class LayoutSVGShape : public LayoutSVGModelObject {
private:
// Hit-detection separated for the fill and the stroke
bool FillContains(const FloatPoint&,
bool FillContains(const HitTestLocation&,
bool requires_fill = true,
const WindRule fill_rule = RULE_NONZERO);
bool StrokeContains(const FloatPoint&, bool requires_stroke = true);
bool StrokeContains(const HitTestLocation&, bool requires_stroke = true);
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectSVGShape ||
......@@ -166,7 +165,7 @@ class LayoutSVGShape : public LayoutSVGModelObject {
bool NodeAtPoint(HitTestResult&,
const HitTestLocation& location_in_parent,
const LayoutPoint& accumulated_offset,
HitTestAction) override;
HitTestAction) final;
FloatRect StrokeBoundingBox() const final { return stroke_bounding_box_; }
......
......@@ -413,26 +413,22 @@ bool SVGLayoutSupport::HasFilterResource(const LayoutObject& object) {
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)
return true;
const FloatRect& reference_box = object.ObjectBoundingBox();
if (clip_path_operation->GetType() == ClipPathOperation::SHAPE) {
ShapeClipPathOperation& clip_path =
ToShapeClipPathOperation(*clip_path_operation);
return clip_path.GetPath(object.ObjectBoundingBox()).Contains(point);
return clip_path.GetPath(reference_box)
.Contains(location.TransformedPoint());
}
DCHECK_EQ(clip_path_operation->GetType(), ClipPathOperation::REFERENCE);
SVGResources* resources =
SVGResourcesCache::CachedResourcesForLayoutObject(object);
if (!resources || !resources->Clipper())
return true;
return resources->Clipper()->HitTestClipContent(object.ObjectBoundingBox(),
point);
return resources->Clipper()->HitTestClipContent(reference_box, location);
}
bool SVGLayoutSupport::HitTestChildren(LayoutObject* last_child,
......
......@@ -73,8 +73,7 @@ class CORE_EXPORT SVGLayoutSupport {
// Determine if the LayoutObject references a filter resource object.
static bool HasFilterResource(const LayoutObject&);
// Determine whether the passed point intersects the clip path of |object|.
static bool IntersectsClipPath(const LayoutObject&, const FloatPoint&);
// Determine whether the passed location intersects the clip path of |object|.
static bool IntersectsClipPath(const LayoutObject&, const HitTestLocation&);
// Shared child hit-testing code between LayoutSVGRoot/LayoutSVGContainer.
......
......@@ -2501,7 +2501,8 @@ bool PaintLayer::HitTestClippedOutByClipPath(
float inverse_zoom = 1 / GetLayoutObject().StyleRef().EffectiveZoom();
point.Scale(inverse_zoom, inverse_zoom);
reference_box.Scale(inverse_zoom);
return !clipper->HitTestClipContent(reference_box, point);
HitTestLocation location(point);
return !clipper->HitTestClipContent(reference_box, location);
}
bool PaintLayer::IntersectsDamageRect(
......
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