Bug 1324713 - Fix integer overflow in CreateClipPathCircle(). draft
authorTing-Yu Lin <tlin@mozilla.com>
Tue, 20 Dec 2016 15:54:18 +0800
changeset 452164 67ab251395081989d53287a1b0349a95cf4fa240
parent 451264 567894f026558e6dada617a3998f29aed06ac7d8
child 540162 f43a4aec5f7b0ef54e760b62e8310ad4045b3756
push id39333
push userbmo:tlin@mozilla.com
push dateWed, 21 Dec 2016 07:20:37 +0000
bugs1324713
milestone53.0a1
Bug 1324713 - Fix integer overflow in CreateClipPathCircle(). Before this patch, we did a sum-of-squares operation with nscoord variables, which could overflow (to a negative value), and that would then produce NaN when sqrt()'ed. We'll now avoid this by using 'double' variables & NS_hypot. Without this patch, clip-path-circle-021.html will be rendered as a rectangle. MozReview-Commit-ID: 70xNvDdHUJc
layout/reftests/svg/svg-integration/clip-path/clip-path-circle-021-ref.html
layout/reftests/svg/svg-integration/clip-path/clip-path-circle-021.html
layout/reftests/svg/svg-integration/clip-path/reftest.list
layout/svg/nsCSSClipPathInstance.cpp
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/svg-integration/clip-path/clip-path-circle-021-ref.html
@@ -0,0 +1,16 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html>
+<head>
+  <title>CSS Masking: Test clip-path property and circle function on circle 021</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+</head>
+<body>
+  <p>The test passes if there is a green circle.</p>
+  <div style="width: 600px; height: 600px; background-color: green; clip-path: circle();"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/svg-integration/clip-path/clip-path-circle-021.html
@@ -0,0 +1,20 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html>
+<head>
+  <title>CSS Masking: Test clip-path property and circle function on circle 021</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="http://www.w3.org/TR/css-masking-1/#clipping-paths">
+  <link rel="help" href="http://www.w3.org/TR/css-masking-1/#propdef-clip-path">
+  <link rel="match" href="clip-path-circle-021-ref.html">
+  <meta name="assert" content="The clip-path property takes the basic shape circle() with large reference box and percentage radius.">
+</head>
+<body>
+  <p>The test passes if there is a green circle.</p>
+  <div style="width: 600px; height: 600px; background-color: green; clip-path: circle(50%);"></div>
+</body>
+</html>
--- a/layout/reftests/svg/svg-integration/clip-path/reftest.list
+++ b/layout/reftests/svg/svg-integration/clip-path/reftest.list
@@ -33,16 +33,17 @@ default-preferences pref(layout.css.clip
 == clip-path-circle-013.html clip-path-circle-002-ref.html
 == clip-path-circle-014.html clip-path-circle-007-ref.html
 == clip-path-circle-015.html clip-path-circle-008-ref.html
 == clip-path-circle-016.html clip-path-circle-009-ref.html
 == clip-path-circle-017.html clip-path-circle-007-ref.html
 == clip-path-circle-018.html clip-path-circle-010-ref.html
 == clip-path-circle-019.html clip-path-circle-002-ref.html
 == clip-path-circle-020.html clip-path-circle-002-ref.html
+== clip-path-circle-021.html clip-path-circle-021-ref.html
 
 == clip-path-ellipse-001.html clip-path-ellipse-001-ref.html
 == clip-path-ellipse-002.html clip-path-ellipse-001-ref.html
 == clip-path-ellipse-003.html clip-path-ellipse-001-ref.html
 == clip-path-ellipse-004.html clip-path-ellipse-001-ref.html
 == clip-path-ellipse-005.html clip-path-ellipse-001-ref.html
 == clip-path-ellipse-006.html clip-path-ellipse-001-ref.html
 == clip-path-ellipse-007.html clip-path-ellipse-001-ref.html
--- a/layout/svg/nsCSSClipPathInstance.cpp
+++ b/layout/svg/nsCSSClipPathInstance.cpp
@@ -8,16 +8,17 @@
 
 #include "gfx2DGlue.h"
 #include "gfxPlatform.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "nsCSSRendering.h"
 #include "nsIFrame.h"
+#include "nsMathUtils.h"
 #include "nsRenderingContext.h"
 #include "nsRuleNode.h"
 #include "nsSVGElement.h"
 #include "nsSVGUtils.h"
 #include "nsSVGViewBox.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -245,32 +246,35 @@ nsCSSClipPathInstance::CreateClipPathCir
   nsSize size = nsSize(aRefBox.width, aRefBox.height);
   nsImageRenderer::ComputeObjectAnchorPoint(basicShape->GetPosition(),
                                             size, size,
                                             &topLeft, &anchor);
   Point center = Point(anchor.x + aRefBox.x, anchor.y + aRefBox.y);
 
   const nsTArray<nsStyleCoord>& coords = basicShape->Coordinates();
   MOZ_ASSERT(coords.Length() == 1, "wrong number of arguments");
-  float referenceLength = sqrt((aRefBox.width * aRefBox.width +
-                                aRefBox.height * aRefBox.height) / 2.0);
   nscoord r = 0;
   if (coords[0].GetUnit() == eStyleUnit_Enumerated) {
     nscoord horizontal, vertical;
     EnumerationToLength(horizontal, coords[0].GetIntValue(),
                         center.x, aRefBox.x, aRefBox.x + aRefBox.width);
     EnumerationToLength(vertical, coords[0].GetIntValue(),
                         center.y, aRefBox.y, aRefBox.y + aRefBox.height);
     if (coords[0].GetIntValue() == NS_RADIUS_FARTHEST_SIDE) {
       r = horizontal > vertical ? horizontal : vertical;
     } else {
       r = horizontal < vertical ? horizontal : vertical;
     }
   } else {
-    r = nsRuleNode::ComputeCoordPercentCalc(coords[0], referenceLength);
+    // We resolve percent <shape-radius> value for circle() as defined here:
+    // https://drafts.csswg.org/css-shapes/#funcdef-circle
+    const double sqrt2 = std::sqrt(2.0);
+    double referenceLength = NS_hypot(aRefBox.width, aRefBox.height) / sqrt2;
+    r = nsRuleNode::ComputeCoordPercentCalc(coords[0],
+                                            NSToCoordRound(referenceLength));
   }
 
   nscoord appUnitsPerDevPixel =
     mTargetFrame->PresContext()->AppUnitsPerDevPixel();
   builder->Arc(center / appUnitsPerDevPixel, r / appUnitsPerDevPixel,
                0, Float(2 * M_PI));
   builder->Close();
   return builder->Finish();