Index: third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp |
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp b/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp |
index 32073042bd914cd8999f8fd2c593feade0f70a23..7e9b0cbaca3a30dfaa7b4aa46e364de01fca71c1 100644 |
--- a/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp |
+++ b/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp |
@@ -44,6 +44,17 @@ |
namespace blink { |
+struct SearchCandidate { |
+ SearchCandidate() {} |
+ SearchCandidate(LayoutObject* layoutObject, float dist) |
+ : candidateLayoutObject(layoutObject) |
+ , distance(dist) |
+ { |
+ } |
+ LayoutObject* candidateLayoutObject; |
+ float distance; |
+}; |
+ |
static inline LayoutRect adjustedEnclosingIntRect(const FloatRect& rect, |
const AffineTransform& rootTransform, float strokeWidthForHairlinePadding) |
{ |
@@ -476,4 +487,64 @@ float SVGLayoutSupport::calculateScreenFontSizeScalingFactor(const LayoutObject* |
return narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2)); |
} |
+static inline bool compareCandidateDistance(const SearchCandidate& r1, const SearchCandidate& r2) |
+{ |
+ return r1.distance < r2.distance; |
+} |
+ |
+static inline float distanceToChildLayoutObject(LayoutObject* child, const FloatPoint& point) |
+{ |
+ const AffineTransform& localToParentTransform = child->localToParentTransform(); |
+ if (!localToParentTransform.isInvertible()) |
+ return std::numeric_limits<float>::max(); |
+ FloatPoint childLocalPoint = localToParentTransform.inverse().mapPoint(point); |
+ return child->objectBoundingBox().squaredDistanceTo(childLocalPoint); |
+} |
+ |
+LayoutObject* SVGLayoutSupport::findClosestLayoutSVGText(LayoutObject* layoutObject, const FloatPoint& point) |
+{ |
+ // Try to find the closest LayoutSVGText. If not find this level, try to search on candidates. |
+ LayoutObject* closestLayoutObject = nullptr; |
+ float closestDistance = std::numeric_limits<float>::max(); |
+ Vector<SearchCandidate> candidates; |
+ for (LayoutObject* child = layoutObject->slowLastChild(); child; child = child->previousSibling()) { |
+ if (child->isSVGText()) { |
+ float distance = distanceToChildLayoutObject(child, point); |
+ if (distance >= closestDistance) |
+ continue; |
+ candidates.clear(); |
+ closestLayoutObject = child; |
+ closestDistance = distance; |
+ continue; |
+ } |
+ |
+ if (child->isSVGContainer() && !layoutObject->isSVGHiddenContainer()) { |
+ float distance = distanceToChildLayoutObject(child, point); |
+ if (distance > closestDistance) |
+ continue; |
+ candidates.append(SearchCandidate(child, distance)); |
+ } |
+ } |
+ |
+ if (closestLayoutObject && closestLayoutObject->isSVGText()) |
+ return closestLayoutObject; |
+ |
+ if (candidates.isEmpty()) |
+ return nullptr; |
+ |
+ // Sort using the distance between the mouse point and a candidate. |
+ // Because if the distance is close, It is high priority to search LayoutSVGText. |
+ std::stable_sort(candidates.begin(), candidates.end(), compareCandidateDistance); |
+ |
+ // If not find LayoutSVGText on this level of tree, try to search it on sub-tree of |condidate|. |
+ for (SearchCandidate& searchCandidate : candidates) { |
+ LayoutObject* candidateLayoutObject = searchCandidate.candidateLayoutObject; |
+ FloatPoint candidateLocalPoint = candidateLayoutObject->localToParentTransform().inverse().mapPoint(point); |
+ if (LayoutObject* result = findClosestLayoutSVGText(candidateLayoutObject, candidateLocalPoint)) |
+ return result; |
+ } |
+ |
+ return nullptr; |
+} |
+ |
} |