Clamp contents visual overflow for LayoutSVGRoot

If the contents overflow rect for the SVG root is too large, it could
end up shifting the overflow rect such that it is culled and thus never
painted.

To avoid this, clip the content overflow rect with
LayoutRect::InfiniteIntRect(). This gives reasonable enough leeway, and
also matches the rect that is commonly used to represent infinity for
culling and clipping etc.

Bug: 911186
Change-Id: I22d505ac0582f4d1fe6ac3ead9041c4a87176994
Reviewed-on: https://chromium-review.googlesource.com/c/1361225
Reviewed-by: Stephen Chenney <schenney@chromium.org>
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#613692}
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 62a15b2e..0e41ea7 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
@@ -212,12 +212,8 @@
   overflow_.reset();
   AddVisualEffectOverflow();
 
-  if (!ShouldApplyViewportClip()) {
-    FloatRect content_visual_rect = VisualRectInLocalSVGCoordinates();
-    content_visual_rect =
-        local_to_border_box_transform_.MapRect(content_visual_rect);
-    AddContentsVisualOverflow(EnclosingLayoutRect(content_visual_rect));
-  }
+  if (!ShouldApplyViewportClip())
+    AddContentsVisualOverflow(ComputeContentsVisualOverflow());
 
   // The scale of one or more of the SVG elements may have changed, content
   // (the entire SVG) could have moved or new content may have been exposed, so
@@ -255,6 +251,19 @@
   return rect;
 }
 
+LayoutRect LayoutSVGRoot::ComputeContentsVisualOverflow() const {
+  FloatRect content_visual_rect = VisualRectInLocalSVGCoordinates();
+  content_visual_rect =
+      local_to_border_box_transform_.MapRect(content_visual_rect);
+  // Condition the visual overflow rect to avoid being clipped/culled
+  // out if it is huge. This may sacrifice overflow, but usually only
+  // overflow that would never be seen anyway.
+  // To condition, we intersect with something that we oftentimes
+  // consider to be "infinity".
+  return Intersection(EnclosingLayoutRect(content_visual_rect),
+                      LayoutRect(LayoutRect::InfiniteIntRect()));
+}
+
 void LayoutSVGRoot::PaintReplaced(const PaintInfo& paint_info,
                                   const LayoutPoint& paint_offset) const {
   SVGRootPainter(*this).PaintReplaced(paint_info, paint_offset);
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.h b/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
index 91c9721..338bc72 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
@@ -95,6 +95,7 @@
   bool ComputeShouldClipOverflow() const override {
     return LayoutBox::ComputeShouldClipOverflow() || ShouldApplyViewportClip();
   }
+  LayoutRect ComputeContentsVisualOverflow() const;
 
   const LayoutObjectChildList* Children() const { return &children_; }
   LayoutObjectChildList* Children() { return &children_; }
diff --git a/third_party/blink/web_tests/svg/overflow/large-overflow-expected.html b/third_party/blink/web_tests/svg/overflow/large-overflow-expected.html
new file mode 100644
index 0000000..f718ea6
--- /dev/null
+++ b/third_party/blink/web_tests/svg/overflow/large-overflow-expected.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div style="width: 100px; height: 100px; background-color: green"></div>
diff --git a/third_party/blink/web_tests/svg/overflow/large-overflow.html b/third_party/blink/web_tests/svg/overflow/large-overflow.html
new file mode 100644
index 0000000..da29a385e
--- /dev/null
+++ b/third_party/blink/web_tests/svg/overflow/large-overflow.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<div style="overflow: hidden; position: relative">
+  <svg style="overflow: visible">
+    <rect width="100" height="100" fill="green"/>
+    <g transform="translate(0, -9000000000)">
+      <path d="M 3.5 0.5 L 28.5 0.5" stroke="red"/>
+    </g>
+  </svg>
+</div>