Bug 1376855 - Support nsDisplayVideo in layers free mode. r=kats,sotaro
MozReview-Commit-ID: HyelfkHokrw
--- 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.