Bug 577824 - Part 1. Set the frame size in nsIFrame::FinishAndStoreOverflow before the ComputeEffectsRect call that uses it. draft
authorcku <cku@mozilla.com>
Wed, 09 Aug 2017 01:04:49 +0800
changeset 648620 4131812d1553771f6b80d10ec7d775618a0c41a9
parent 648573 a6a1f5c1d971dbee67ba6eec7ead7902351ddca2
child 648621 a861ecbaea060c5ea48d28279f1fad2c85e07e40
push id74818
push userbmo:cku@mozilla.com
push dateFri, 18 Aug 2017 02:24:01 +0000
bugs577824
milestone57.0a1
Bug 577824 - Part 1. Set the frame size in nsIFrame::FinishAndStoreOverflow before the ComputeEffectsRect call that uses it. This change ensures that HTML frames with SVG filters applied are given the correct overflow regions so that they will display and invalidate correctly. The bug that this commit fixes does not manifest in many cases since often elements happen to be reflowed more than once when a document loads. When that happened the bug would be masked because the filtered frame would be given a size during the first reflow, and that would then make the overflow calculations in subsequent reflows work. It was only in cases where the filtered frame was only reflowed once (such as when dynamically inserting a filtered element into the DOM using script) that the lack of a valid frame size during the overflow calculations would result in bad overflow regions being calculated. MozReview-Commit-ID: 79lR27KRSym
layout/generic/nsFrame.cpp
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -9050,41 +9050,46 @@ nsIFrame::FinishAndStoreOverflow(nsOverf
                             disp->mAppearance, &r)) {
       nsRect& vo = aOverflowAreas.VisualOverflow();
       vo.UnionRectEdges(vo, r);
     }
   }
 
   ComputeAndIncludeOutlineArea(this, aOverflowAreas, aNewSize);
 
+  nsSize oldSize = mRect.Size();
+  bool sizeChanged = ((aOldSize ? *aOldSize : oldSize) != aNewSize);
+
+  // Our frame size may not have been computed and set yet, but code under
+  // functions such as ComputeEffectsRect (which we're about to call) use the
+  // values that are stored in our frame rect to compute their results.  We
+  // need the results from those functions to be based on the frame size that
+  // we *will* have, so we temporarily set our frame size here before calling
+  // those functions.
+  //
+  // XXX Someone should document here why we revert the frame size before we
+  // return rather than just leaving it set.
+  SetSize(aNewSize);
+
   // Nothing in here should affect scrollable overflow.
   aOverflowAreas.VisualOverflow() =
     ComputeEffectsRect(this, aOverflowAreas.VisualOverflow(), aNewSize);
 
   // Absolute position clipping
   const nsStyleEffects* effects = StyleEffects();
   Maybe<nsRect> clipPropClipRect =
     GetClipPropClipRect(disp, effects, aNewSize);
   if (clipPropClipRect) {
     NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
       nsRect& o = aOverflowAreas.Overflow(otype);
       o.IntersectRect(o, *clipPropClipRect);
     }
   }
 
   /* If we're transformed, transform the overflow rect by the current transformation. */
-  nsSize oldSize = mRect.Size();
-  bool sizeChanged = ((aOldSize ? *aOldSize : oldSize) != aNewSize);
-
-  /* Since our size might not actually have been computed yet, we need to make sure that we use the
-   * correct dimensions by overriding the stored bounding rectangle with the value the caller has
-   * ensured us we'll use.
-   */
-  SetSize(aNewSize);
-
   if (ChildrenHavePerspective(disp) && sizeChanged) {
     nsRect newBounds(nsPoint(0, 0), aNewSize);
     RecomputePerspectiveChildrenOverflow(this, effectSet);
   }
 
   if (hasTransform) {
     SetProperty(nsIFrame::PreTransformOverflowAreasProperty(),
                 new nsOverflowAreas(aOverflowAreas));