Bug 1271765 - Part 1: Remove XUL-specific reflow code of video control. r=dholbert
☠☠ backed out by 60af44ebfa62 ☠ ☠
authorRay Lin <ralin@mozilla.com>
Wed, 12 Oct 2016 13:41:50 +0800
changeset 321589 08811364762917e139d7459faf3b324f076c5e95
parent 321588 476aca2782fef12f2cec84e2d68254716f1d1c56
child 321590 02d34b18d76bf7d59d09149385b00586111146e7
push id83647
push userkwierso@gmail.com
push dateTue, 08 Nov 2016 22:08:41 +0000
treeherdermozilla-inbound@1d0b02250149 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1271765
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1271765 - Part 1: Remove XUL-specific reflow code of video control. r=dholbert MozReview-Commit-ID: KFn3ga2Uqq2
layout/generic/crashtests/1271765.html
layout/generic/crashtests/crashtests.list
layout/generic/nsVideoFrame.cpp
layout/style/res/html.css
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/1271765.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+<body>
+<div id="content" class="entry">
+  <audio controls style="writing-mode: vertical-lr"></audio>
+</div>
+</body>
+</html>
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -636,8 +636,9 @@ load 1279814.html
 load large-border-radius-dashed.html
 load large-border-radius-dashed2.html
 load large-border-radius-dotted.html
 load large-border-radius-dotted2.html
 load 1297427-non-equal-centers.html
 load 1278461-1.html
 load 1278461-2.html
 load 1304441.html
+load 1271765.html
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -293,28 +293,37 @@ nsVideoFrame::Reflow(nsPresContext* aPre
                  ("enter nsVideoFrame::Reflow: availSize=%d,%d",
                   aReflowInput.AvailableWidth(),
                   aReflowInput.AvailableHeight()));
 
   NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow");
 
   aStatus = NS_FRAME_COMPLETE;
 
-  aMetrics.Width() = aReflowInput.ComputedWidth();
-  aMetrics.Height() = aReflowInput.ComputedHeight();
+  const WritingMode myWM = aReflowInput.GetWritingMode();
+  nscoord contentBoxBSize = aReflowInput.ComputedBSize();
+
+  const nscoord borderBoxISize = aReflowInput.ComputedISize() +
+    aReflowInput.ComputedLogicalBorderPadding().IStartEnd(myWM);
+  const bool isBSizeShrinkWrapping = (contentBoxBSize == NS_INTRINSICSIZE);
 
-  // stash this away so we can compute our inner area later
+  nscoord borderBoxBSize;
+  if (!isBSizeShrinkWrapping) {
+    borderBoxBSize = contentBoxBSize +
+      aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM);
+  }
+
   mBorderPadding   = aReflowInput.ComputedPhysicalBorderPadding();
 
-  aMetrics.Width() += mBorderPadding.left + mBorderPadding.right;
-  aMetrics.Height() += mBorderPadding.top + mBorderPadding.bottom;
+  // Reflow the child frames. We may have up to three: an image
+  // frame (for the poster image), a container frame for the controls,
+  // and a container frame for the caption.
+  for (nsIFrame* child : mFrames) {
+    nsSize oldChildSize = child->GetSize();
 
-  // Reflow the child frames. We may have up to two, an image frame
-  // which is the poster, and a box frame, which is the video controls.
-  for (nsIFrame* child : mFrames) {
     if (child->GetContent() == mPosterImage) {
       // Reflow the poster frame.
       nsImageFrame* imageFrame = static_cast<nsImageFrame*>(child);
       ReflowOutput kidDesiredSize(aReflowInput);
       WritingMode wm = imageFrame->GetWritingMode();
       LogicalSize availableSize = aReflowInput.AvailableSize(wm);
       LogicalSize cbSize = aMetrics.Size(aMetrics.GetWritingMode()).
                              ConvertTo(wm, aMetrics.GetWritingMode());
@@ -333,56 +342,78 @@ nsVideoFrame::Reflow(nsPresContext* aPre
       }
       kidReflowInput.SetComputedWidth(posterRenderRect.width);
       kidReflowInput.SetComputedHeight(posterRenderRect.height);
       ReflowChild(imageFrame, aPresContext, kidDesiredSize, kidReflowInput,
                   posterRenderRect.x, posterRenderRect.y, 0, aStatus);
       FinishReflowChild(imageFrame, aPresContext,
                         kidDesiredSize, &kidReflowInput,
                         posterRenderRect.x, posterRenderRect.y, 0);
+
+// Android still uses XUL media controls & hence needs this XUL-friendly
+// custom reflow code. This will go away in bug 1310907.
+#ifdef ANDROID
     } else if (child->GetContent() == mVideoControls) {
       // Reflow the video controls frame.
       nsBoxLayoutState boxState(PresContext(), aReflowInput.mRenderingContext);
       nsSize size = child->GetSize();
       nsBoxFrame::LayoutChildAt(boxState,
                                 child,
                                 nsRect(mBorderPadding.left,
                                        mBorderPadding.top,
                                        aReflowInput.ComputedWidth(),
                                        aReflowInput.ComputedHeight()));
-      if (child->GetSize() != size) {
-        RefPtr<Runnable> event = new DispatchResizeToControls(child->GetContent());
-        nsContentUtils::AddScriptRunner(event);
-      }
-    } else if (child->GetContent() == mCaptionDiv) {
-      // Reflow to caption div
-      ReflowOutput kidDesiredSize(aReflowInput);
+
+#endif // ANDROID
+    } else if (child->GetContent() == mCaptionDiv ||
+               child->GetContent() == mVideoControls) {
+      // Reflow the caption and control bar frames.
       WritingMode wm = child->GetWritingMode();
-      LogicalSize availableSize = aReflowInput.AvailableSize(wm);
-      LogicalSize cbSize = aMetrics.Size(aMetrics.GetWritingMode()).
-                             ConvertTo(wm, aMetrics.GetWritingMode());
+      LogicalSize availableSize = aReflowInput.ComputedSize(wm);
+      availableSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
+
       ReflowInput kidReflowInput(aPresContext,
                                        aReflowInput,
                                        child,
-                                       availableSize,
-                                       &cbSize);
-      nsSize size(aReflowInput.ComputedWidth(), aReflowInput.ComputedHeight());
-      size.width -= kidReflowInput.ComputedPhysicalBorderPadding().LeftRight();
-      size.height -= kidReflowInput.ComputedPhysicalBorderPadding().TopBottom();
-
-      kidReflowInput.SetComputedWidth(std::max(size.width, 0));
-      kidReflowInput.SetComputedHeight(std::max(size.height, 0));
-
+                                       availableSize);
+      ReflowOutput kidDesiredSize(kidReflowInput);
       ReflowChild(child, aPresContext, kidDesiredSize, kidReflowInput,
                   mBorderPadding.left, mBorderPadding.top, 0, aStatus);
+
+      if (child->GetContent() == mVideoControls && isBSizeShrinkWrapping) {
+        contentBoxBSize = kidDesiredSize.BSize(myWM);
+      }
+
       FinishReflowChild(child, aPresContext,
                         kidDesiredSize, &kidReflowInput,
                         mBorderPadding.left, mBorderPadding.top, 0);
     }
+
+    if (child->GetContent() == mVideoControls && child->GetSize() != oldChildSize) {
+      RefPtr<Runnable> event = new DispatchResizeToControls(child->GetContent());
+      nsContentUtils::AddScriptRunner(event);
+    }
   }
+
+  if (isBSizeShrinkWrapping) {
+    if (contentBoxBSize == NS_INTRINSICSIZE) {
+      // We didn't get a BSize from our intrinsic size/ratio, nor did we
+      // get one from our controls. Just use BSize of 0.
+      contentBoxBSize = 0;
+    }
+    contentBoxBSize = NS_CSS_MINMAX(contentBoxBSize,
+                                    aReflowInput.ComputedMinBSize(),
+                                    aReflowInput.ComputedMaxBSize());
+    borderBoxBSize = contentBoxBSize +
+      aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM);
+  }
+
+  LogicalSize logicalDesiredSize(myWM, borderBoxISize, borderBoxBSize);
+  aMetrics.SetSize(myWM, logicalDesiredSize);
+
   aMetrics.SetOverflowAreasToDesiredBounds();
 
   FinishAndStoreOverflow(&aMetrics);
 
   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
                  ("exit nsVideoFrame::Reflow: size=%d,%d",
                   aMetrics.Width(), aMetrics.Height()));
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics);
@@ -521,16 +552,32 @@ nsVideoFrame::ComputeSize(nsRenderingCon
                           WritingMode aWM,
                           const LogicalSize& aCBSize,
                           nscoord aAvailableISize,
                           const LogicalSize& aMargin,
                           const LogicalSize& aBorder,
                           const LogicalSize& aPadding,
                           ComputeSizeFlags aFlags)
 {
+// When in no video scenario, it should fall back to inherited method.
+// We keep old codepath here since Android still uses XUL media controls.
+// This will go away in bug 1310907.
+#ifndef ANDROID
+  if (!HasVideoElement()) {
+    return nsContainerFrame::ComputeSize(aRenderingContext,
+                                         aWM,
+                                         aCBSize,
+                                         aAvailableISize,
+                                         aMargin,
+                                         aBorder,
+                                         aPadding,
+                                         aFlags);
+  }
+#endif // ANDROID
+
   nsSize size = GetVideoIntrinsicSize(aRenderingContext);
 
   IntrinsicSize intrinsicSize;
   intrinsicSize.width.SetCoordValue(size.width);
   intrinsicSize.height.SetCoordValue(size.height);
 
   // Only video elements have an intrinsic ratio.
   nsSize intrinsicRatio = HasVideoElement() ? size : nsSize(0, 0);
@@ -538,27 +585,55 @@ nsVideoFrame::ComputeSize(nsRenderingCon
   return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
                                             intrinsicSize, intrinsicRatio,
                                             aCBSize, aMargin, aBorder, aPadding,
                                             aFlags);
 }
 
 nscoord nsVideoFrame::GetMinISize(nsRenderingContext *aRenderingContext)
 {
-  nsSize size = GetVideoIntrinsicSize(aRenderingContext);
-  nscoord result = GetWritingMode().IsVertical() ? size.height : size.width;
+  nscoord result;
   DISPLAY_MIN_WIDTH(this, result);
+
+  if (HasVideoElement()) {
+    nsSize size = GetVideoIntrinsicSize(aRenderingContext);
+    result = GetWritingMode().IsVertical() ? size.height : size.width;
+  } else {
+    // We expect last and only child of audio elements to be control if
+    // "controls" attribute is present.
+    nsIFrame* kid = mFrames.LastChild();
+    if (kid) {
+      result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
+                                                    kid,
+                                                    nsLayoutUtils::MIN_ISIZE);
+    }
+  }
+
   return result;
 }
 
 nscoord nsVideoFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
 {
-  nsSize size = GetVideoIntrinsicSize(aRenderingContext);
-  nscoord result = GetWritingMode().IsVertical() ? size.height : size.width;
+  nscoord result;
   DISPLAY_PREF_WIDTH(this, result);
+
+  if (HasVideoElement()) {
+    nsSize size = GetVideoIntrinsicSize(aRenderingContext);
+    result = GetWritingMode().IsVertical() ? size.height : size.width;
+  } else {
+    // We expect last and only child of audio elements to be control if
+    // "controls" attribute is present.
+    nsIFrame* kid = mFrames.LastChild();
+    if (kid) {
+      result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
+                                                    kid,
+                                                    nsLayoutUtils::PREF_ISIZE);
+    }
+  }
+
   return result;
 }
 
 nsSize nsVideoFrame::GetIntrinsicRatio()
 {
   if (!HasVideoElement()) {
     // Audio elements have no intrinsic ratio.
     return nsSize(0, 0);
@@ -595,26 +670,30 @@ bool nsVideoFrame::ShouldDisplayPoster()
 }
 
 nsSize
 nsVideoFrame::GetVideoIntrinsicSize(nsRenderingContext *aRenderingContext)
 {
   // Defaulting size to 300x150 if no size given.
   nsIntSize size(300, 150);
 
+// All media controls have been converted to HTML except Android. Hence
+// we keep this codepath for Android until removal in bug 1310907.
+#ifdef ANDROID
   if (!HasVideoElement()) {
     if (!mFrames.FirstChild()) {
       return nsSize(0, 0);
     }
 
     // Ask the controls frame what its preferred height is
     nsBoxLayoutState boxState(PresContext(), aRenderingContext, 0);
     nscoord prefHeight = mFrames.LastChild()->GetXULPrefSize(boxState).height;
     return nsSize(nsPresContext::CSSPixelsToAppUnits(size.width), prefHeight);
   }
+#endif // ANDROID
 
   HTMLVideoElement* element = static_cast<HTMLVideoElement*>(GetContent());
   if (NS_FAILED(element->GetVideoSize(&size)) && ShouldDisplayPoster()) {
     // Use the poster image frame's size.
     nsIFrame *child = mPosterImage->GetPrimaryFrame();
     nsImageFrame* imageFrame = do_QueryFrame(child);
     nsSize imgsize;
     if (NS_SUCCEEDED(imageFrame->GetIntrinsicImageSize(imgsize))) {
--- a/layout/style/res/html.css
+++ b/layout/style/res/html.css
@@ -758,16 +758,18 @@ audio:not([controls]) {
 
 *|*::-moz-html-canvas-content {
   display: block !important;
   /* we want to be an absolute and fixed container */
   transform: translate(0) !important;
 }
 
 video > .caption-box {
+  width: 100%;
+  height: 100%;
   position: relative;
   overflow: hidden;
 }
 
 /* datetime elements */
 
 input[type="time"] > xul|datetimebox {
   display: flex;