Bug 1474722 - Prevent large rect integer overflows without forbidding large nine-patches. r=Bas, a=lizzard
☠☠ backed out by b9a609c0b055 ☠ ☠
authorNicolas Silva <nsilva@mozilla.com>
Wed, 01 Aug 2018 17:13:12 +0200
changeset 480825 218d36910b9231648062034b52f49e1e4af43388
parent 480824 bc83bb0212b344803ac00c416052b2520709f7f9
child 480826 bbf140a25c62f36eb0bca2c13a65bd9ce21a0110
push id1757
push userffxbld-merge
push dateFri, 24 Aug 2018 17:02:43 +0000
treeherdermozilla-release@736023aebdb1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas, lizzard
bugs1474722
milestone62.0
Bug 1474722 - Prevent large rect integer overflows without forbidding large nine-patches. r=Bas, a=lizzard
gfx/2d/Rect.h
gfx/thebes/gfxBlur.cpp
--- a/gfx/2d/Rect.h
+++ b/gfx/2d/Rect.h
@@ -288,16 +288,23 @@ IntRectTyped<units> RoundedToInt(const R
   copy.Round();
   return IntRectTyped<units>(int32_t(copy.X()),
                              int32_t(copy.Y()),
                              int32_t(copy.Width()),
                              int32_t(copy.Height()));
 }
 
 template<class units>
+bool RectIsInt32Safe(const RectTyped<units>& aRect) {
+  float min = (float)std::numeric_limits<std::int32_t>::min();
+  float max = (float)std::numeric_limits<std::int32_t>::max();
+  return aRect.x > min && aRect.y > min && aRect.XMost() < max && aRect.YMost() < max;
+}
+
+template<class units>
 IntRectTyped<units> RoundedIn(const RectTyped<units>& aRect)
 {
   return IntRectTyped<units>::RoundIn(aRect);
 }
 
 template<class units>
 IntRectTyped<units> RoundedOut(const RectTyped<units>& aRect)
 {
--- a/gfx/thebes/gfxBlur.cpp
+++ b/gfx/thebes/gfxBlur.cpp
@@ -589,16 +589,22 @@ GetBlur(gfxContext* aDestinationCtx,
   // Instead just render the blur ourself here as one image and send it over for printing.
   // TODO: May need to change this with the blob renderer in WR since it also records.
   Matrix destMatrix = aDestinationCtx->CurrentMatrix();
   bool useDestRect = !destMatrix.IsRectilinear() || destMatrix.HasNonIntegerTranslation() ||
                      aDestinationCtx->GetDrawTarget()->IsRecording();
   if (useDestRect) {
     minSize = aRectSize;
   }
+
+  int32_t maxTextureSize = gfxPlatform::MaxTextureSize();
+  if (minSize.width > maxTextureSize || minSize.height > maxTextureSize) {
+    return nullptr;
+  }
+
   aOutMinSize = minSize;
 
   DrawTarget* destDT = aDestinationCtx->GetDrawTarget();
 
   if (!useDestRect) {
     BlurCacheData* cached = gBlurCache->Lookup(minSize, aBlurRadius,
                                                aCornerRadii, aShadowColor,
                                                destDT->GetBackendType());
@@ -950,23 +956,17 @@ DrawMirroredMinBoxShadow(DrawTarget* aDe
 gfxAlphaBoxBlur::BlurRectangle(gfxContext* aDestinationCtx,
                                const gfxRect& aRect,
                                const RectCornerRadii* aCornerRadii,
                                const gfxPoint& aBlurStdDev,
                                const Color& aShadowColor,
                                const gfxRect& aDirtyRect,
                                const gfxRect& aSkipRect)
 {
-  const double maxSize = (double)gfxPlatform::MaxTextureSize();
-  const double maxPos = (double)std::numeric_limits<std::int16_t>::max();
-  if (aRect.width > maxSize || aRect.height > maxSize ||
-      std::abs(aRect.x) > maxPos || std::abs(aRect.y) > maxPos) {
-    // The rectangle is huge, perhaps due to a very strong perspective or some other
-    // transform. We won't be able to blur something this big so give up now before
-    // overflowing or running into texture size limits later.
+  if (!RectIsInt32Safe(ToRect(aRect))) {
     return;
   }
 
   IntSize blurRadius = CalculateBlurRadius(aBlurStdDev);
   bool mirrorCorners = !aCornerRadii || aCornerRadii->AreRadiiSame();
 
   IntRect rect = RoundedToInt(ToRect(aRect));
   IntMargin blurMargin;
@@ -1015,27 +1015,22 @@ gfxAlphaBoxBlur::BlurRectangle(gfxContex
     }
   }
 
   // A note about anti-aliasing and seems between adjacent parts:
   // We don't explicitly disable anti-aliasing in the DrawSurface calls above,
   // so if there's a transform on destDrawTarget that is not pixel-aligned,
   // there will be seams between adjacent parts of the box-shadow. It's hard to
   // avoid those without the use of an intermediate surface.
-  // You might think that we could avoid those by just turning of AA, but there
+  // You might think that we could avoid those by just turning off AA, but there
   // is a problem with that: Box-shadow rendering needs to clip out the
   // element's border box, and we'd like that clip to have anti-aliasing -
   // especially if the element has rounded corners! So we can't do that unless
   // we have a way to say "Please anti-alias the clip, but don't antialias the
   // destination rect of the DrawSurface call".
-  // On OS X there is an additional problem with turning off AA: CoreGraphics
-  // will not just fill the pixels that have their pixel center inside the
-  // filled shape. Instead, it will fill all the pixels which are partially
-  // covered by the shape. So for pixels on the edge between two adjacent parts,
-  // all those pixels will be painted to by both parts, which looks very bad.
 
   destDrawTarget->PopClip();
 }
 
 static already_AddRefed<Path>
 GetBoxShadowInsetPath(DrawTarget* aDrawTarget,
                       const Rect aOuterRect, const Rect aInnerRect,
                       const RectCornerRadii* aInnerClipRadii)