Bug 1376855 - Support nsDisplayVideo in layers free mode. r=kats,sotaro draft
authorMorris Tseng <mtseng@mozilla.com>
Wed, 28 Jun 2017 15:12:25 -0700
changeset 603971 74ec9bc3b66ad0c1bd478725f88052419e5b28fd
parent 603970 859960e7df22bcfc1cab42aca72872dee237b235
child 603972 eba6917c83526c797f7920cea9d209e0fdf07c15
push id66921
push userbmo:mtseng@mozilla.com
push dateWed, 05 Jul 2017 03:31:35 +0000
reviewerskats, sotaro
bugs1376855
milestone56.0a1
Bug 1376855 - Support nsDisplayVideo in layers free mode. r=kats,sotaro MozReview-Commit-ID: HyelfkHokrw
layout/generic/nsVideoFrame.cpp
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -7,16 +7,17 @@
 /* rendering object for the HTML <video> element */
 
 #include "nsVideoFrame.h"
 
 #include "nsCOMPtr.h"
 #include "nsGkAtoms.h"
 
 #include "mozilla/dom/HTMLVideoElement.h"
+#include "mozilla/layers/WebRenderLayerManager.h"
 #include "nsIDOMHTMLImageElement.h"
 #include "nsDisplayList.h"
 #include "nsGenericHTMLElement.h"
 #include "nsPresContext.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsBoxLayoutState.h"
 #include "nsBoxFrame.h"
 #include "nsImageFrame.h"
@@ -427,16 +428,74 @@ public:
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayVideo() {
     MOZ_COUNT_DTOR(nsDisplayVideo);
   }
 #endif
 
   NS_DISPLAY_DECL_NAME("Video", TYPE_VIDEO)
 
+  virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                       const mozilla::layers::StackingContextHelper& aSc,
+                                       nsTArray<mozilla::layers::WebRenderParentCommand>& aParentCommands,
+                                       mozilla::layers::WebRenderLayerManager* aManager,
+                                       nsDisplayListBuilder* aDisplayListBuilder) override
+  {
+    nsRect area = Frame()->GetContentRectRelativeToSelf() + ToReferenceFrame();
+    HTMLVideoElement* element = static_cast<HTMLVideoElement*>(Frame()->GetContent());
+
+    nsIntSize videoSizeInPx;
+    if (NS_FAILED(element->GetVideoSize(&videoSizeInPx)) || area.IsEmpty()) {
+      return false;
+    }
+
+    RefPtr<ImageContainer> container = element->GetImageContainer();
+    if (!container) {
+      return false;
+    }
+
+    // Retrieve the size of the decoded video frame, before being scaled
+    // by pixel aspect ratio.
+    mozilla::gfx::IntSize frameSize = container->GetCurrentSize();
+    if (frameSize.width == 0 || frameSize.height == 0) {
+      // No image, or zero-sized image. Don't render.
+      return true;
+    }
+
+    // Convert video size from pixel units into app units, to get an aspect-ratio
+    // (which has to be represented as a nsSize) and an IntrinsicSize that we
+    // can pass to ComputeObjectRenderRect.
+    nsSize aspectRatio(nsPresContext::CSSPixelsToAppUnits(videoSizeInPx.width),
+                       nsPresContext::CSSPixelsToAppUnits(videoSizeInPx.height));
+    IntrinsicSize intrinsicSize;
+    intrinsicSize.width.SetCoordValue(aspectRatio.width);
+    intrinsicSize.height.SetCoordValue(aspectRatio.height);
+
+    nsRect dest = nsLayoutUtils::ComputeObjectDestRect(area,
+                                                       intrinsicSize,
+                                                       aspectRatio,
+                                                       Frame()->StylePosition());
+
+    gfxRect destGFXRect = Frame()->PresContext()->AppUnitsToGfxUnits(dest);
+    destGFXRect.Round();
+    if (destGFXRect.IsEmpty()) {
+      return false;
+    }
+
+    VideoInfo::Rotation rotationDeg = element->RotationDegrees();
+    IntSize scaleHint(static_cast<int32_t>(destGFXRect.Width()),
+                      static_cast<int32_t>(destGFXRect.Height()));
+    // scaleHint is set regardless of rotation, so swap w/h if needed.
+    SwapScaleWidthHeightForRotation(scaleHint, rotationDeg);
+    container->SetScaleHint(scaleHint);
+
+    LayerRect rect(destGFXRect.x, destGFXRect.y, destGFXRect.width, destGFXRect.height);
+    return aManager->PushImage(this, container, aBuilder, aSc, rect);
+  }
+
   // It would be great if we could override GetOpaqueRegion to return nonempty here,
   // but it's probably not safe to do so in general. Video frames are
   // updated asynchronously from decoder threads, and it's possible that
   // we might have an opaque video frame when GetOpaqueRegion is called, but
   // when we come to paint, the video frame is transparent or has gone
   // away completely (e.g. because of a decoder error). The problem would
   // be especially acute if we have off-main-thread rendering.