Bug 1397795 - Fix stack overflow crash due to box-shadow. r=mstange, a=jcristau
authorJonathan Watt <jwatt@jwatt.org>
Fri, 23 Feb 2018 10:40:12 +0000
changeset 462788 4a040f2fca3068bfa710338ca87eedfae8231db5
parent 462787 99a22b7c1e8e98d9beb91ebc772526695b0f8ae4
child 462789 d37345171e91d91e70f59b5f4db9c27040f81ef3
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange, jcristau
bugs1397795
milestone60.0
Bug 1397795 - Fix stack overflow crash due to box-shadow. r=mstange, a=jcristau GetBoxShadowRectForFrame is called while we're calculating the visual overflow bounds for a frame. So it is not valid for it to use the frame's "current" visual overflow rect (which may be uninitialized or stale). MozReview-Commit-ID: J52dxIMrMg5
layout/base/nsLayoutUtils.cpp
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -8742,35 +8742,39 @@ nsLayoutUtils::FontSizeInflationEnabled(
 nsLayoutUtils::GetBoxShadowRectForFrame(nsIFrame* aFrame,
                                         const nsSize& aFrameSize)
 {
   nsCSSShadowArray* boxShadows = aFrame->StyleEffects()->mBoxShadow;
   if (!boxShadows) {
     return nsRect();
   }
 
-  bool nativeTheme;
+  nsRect inputRect(nsPoint(0, 0), aFrameSize);
+
+  // According to the CSS spec, box-shadow should be based on the border box.
+  // However, that looks broken when the background extends outside the border
+  // box, as can be the case with native theming.  To fix that we expand the
+  // area that we shadow to include the bounds of any native theme drawing.
   const nsStyleDisplay* styleDisplay = aFrame->StyleDisplay();
   nsITheme::Transparency transparency;
   if (aFrame->IsThemed(styleDisplay, &transparency)) {
     // For opaque (rectangular) theme widgets we can take the generic
     // border-box path with border-radius disabled.
-    nativeTheme = transparency != nsITheme::eOpaque;
-  } else {
-    nativeTheme = false;
-  }
-
-  nsRect frameRect = nativeTheme ?
-    aFrame->GetVisualOverflowRectRelativeToSelf() :
-    nsRect(nsPoint(0, 0), aFrameSize);
+    if (transparency != nsITheme::eOpaque) {
+      nsPresContext *presContext = aFrame->PresContext();
+      presContext->GetTheme()->
+        GetWidgetOverflow(presContext->DeviceContext(), aFrame,
+                          styleDisplay->mAppearance, &inputRect);
+    }
+  }
 
   nsRect shadows;
   int32_t A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
   for (uint32_t i = 0; i < boxShadows->Length(); ++i) {
-    nsRect tmpRect = frameRect;
+    nsRect tmpRect = inputRect;
     nsCSSShadowItem* shadow = boxShadows->ShadowAt(i);
 
     // inset shadows are never painted outside the frame
     if (shadow->mInset)
       continue;
 
     tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
     tmpRect.Inflate(shadow->mSpread);