Bug 1372118 - Part4. Support canvas and video.
MozReview-Commit-ID: 79JNEEZaPXU
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -59,16 +59,17 @@ public:
}
enum { ALLOW_MEMMOVE = true };
FrameDisplayItemKey mKey;
};
class WMImageData;
+class WMCanvasData;
class WMData
{
public:
NS_INLINE_DECL_REFCOUNTING(WMData)
virtual WMAnimationData* AsAnimationData() { return nullptr; }
virtual WMImageData* AsImageData() { return nullptr; }
@@ -96,16 +97,36 @@ public:
wr::MaybeExternalImageId mExternalImageId;
Maybe<wr::ImageKey> mKey;
RefPtr<ImageClient> mImageClient;
CompositableType mImageClientTypeContainer;
Maybe<wr::PipelineId> mPipelineId;
RefPtr<ImageContainer> mContainer;
};
+
+class WMCanvasData : public WMData
+{
+public:
+ virtual WMCanvasData* AsCanvasData() override { return this; }
+ virtual TYPE GetType() override { return TYPE::CANVAS; }
+ static TYPE Type() { return TYPE::CANVAS; }
+
+ void EmptyTransaction();
+ void SetLayer(Layer* aLayer) { mLayer = aLayer; }
+ already_AddRefed<Layer> GetLayer()
+ {
+ RefPtr<Layer> res = mLayer;
+ return res.forget();
+ }
+
+protected:
+ RefPtr<Layer> mLayer;
+};
+
class WebRenderLayerManager final : public LayerManager
{
typedef nsTArray<RefPtr<Layer> > LayerRefArray;
public:
explicit WebRenderLayerManager(nsIWidget* aWidget);
void Initialize(PCompositorBridgeChild* aCBChild, wr::PipelineId aLayersId, TextureFactoryIdentifier* aTextureFactoryIdentifier);
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -11,16 +11,19 @@
#include "mozilla/Assertions.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "nsDisplayList.h"
#include "nsLayoutUtils.h"
#include "nsStyleUtil.h"
#include "ImageLayers.h"
#include "Layers.h"
#include "ActiveLayerTracker.h"
+#include "mozilla/layers/StackingContextHelper.h"
+#include "mozilla/layers/WebRenderLayerManager.h"
+#include "mozilla/layers/WebRenderLayer.h"
#include <algorithm>
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layers;
using namespace mozilla::gfx;
@@ -109,19 +112,46 @@ public:
nsHTMLCanvasFrame* f = static_cast<nsHTMLCanvasFrame*>(Frame());
return f->GetInnerArea() + ToReferenceFrame();
}
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aContainerParameters) override
{
+ CanvasLayer* oldLayer = static_cast<CanvasLayer*>
+ (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
+
return static_cast<nsHTMLCanvasFrame*>(mFrame)->
- BuildLayer(aBuilder, aManager, this, aContainerParameters);
+ BuildLayer(aBuilder, aManager, this, aContainerParameters, oldLayer);
}
+
+ virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+ const StackingContextHelper& aSc,
+ nsTArray<WebRenderParentCommand>& aParentCommands,
+ mozilla::layers::WebRenderLayerManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override
+ {
+ RefPtr<WMCanvasData> canvasData = aManager->CreateOrRecycleWMData<WMCanvasData>(this);
+ ContainerLayerParameters containerParameters;
+ containerParameters.mOffset.x = aSc.Origin().x;
+ containerParameters.mOffset.y = aSc.Origin().y;
+ RefPtr<Layer> oldLayer = canvasData->GetLayer();
+ RefPtr<Layer> layer = static_cast<nsHTMLCanvasFrame*>(mFrame)->BuildLayer(aDisplayListBuilder,
+ aManager,
+ this,
+ containerParameters,
+ oldLayer);
+ canvasData->SetLayer(layer);
+ if (layer) {
+ WebRenderLayer::ToWebRenderLayer(layer)->RenderLayer(aBuilder, aSc);
+ }
+ return true;
+ }
+
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters) override
{
if (HTMLCanvasElement::FromContent(mFrame->GetContent())->ShouldForceInactiveLayer(aManager))
return LAYER_INACTIVE;
// If compositing is cheap, just do that
@@ -316,31 +346,30 @@ nsHTMLCanvasFrame::GetInnerArea() const
r.height = mRect.height - bp.top - bp.bottom;
return r;
}
already_AddRefed<Layer>
nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
nsDisplayItem* aItem,
- const ContainerLayerParameters& aContainerParameters)
+ const ContainerLayerParameters& aContainerParameters,
+ Layer* aOldLayer)
{
nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
HTMLCanvasElement* element = static_cast<HTMLCanvasElement*>(GetContent());
nsIntSize canvasSizeInPx = GetCanvasSize();
nsPresContext* presContext = PresContext();
element->HandlePrintCallback(presContext->Type());
if (canvasSizeInPx.width <= 0 || canvasSizeInPx.height <= 0 || area.IsEmpty())
return nullptr;
- CanvasLayer* oldLayer = static_cast<CanvasLayer*>
- (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
- RefPtr<Layer> layer = element->GetCanvasLayer(aBuilder, oldLayer, aManager);
+ RefPtr<Layer> layer = element->GetCanvasLayer(aBuilder, aOldLayer, aManager);
if (!layer)
return nullptr;
IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSizeInPx);
nsSize intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSizeInPx);
nsRect dest =
nsLayoutUtils::ComputeObjectDestRect(area, intrinsicSize, intrinsicRatio,
--- a/layout/generic/nsHTMLCanvasFrame.h
+++ b/layout/generic/nsHTMLCanvasFrame.h
@@ -46,17 +46,18 @@ public:
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists) override;
already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
nsDisplayItem* aItem,
- const ContainerLayerParameters& aContainerParameters);
+ const ContainerLayerParameters& aContainerParameters,
+ Layer* aOldLayer);
/* get the size of the canvas's image */
nsIntSize GetCanvasSize();
virtual nscoord GetMinISize(gfxContext *aRenderingContext) override;
virtual nscoord GetPrefISize(gfxContext *aRenderingContext) override;
virtual mozilla::IntrinsicSize GetIntrinsicSize() override;
virtual nsSize GetIntrinsicRatio() override;
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -23,16 +23,19 @@
#include "nsIImageLoadingContent.h"
#include "nsContentUtils.h"
#include "ImageContainer.h"
#include "ImageLayers.h"
#include "nsContentList.h"
#include "nsStyleUtil.h"
#include <algorithm>
+#include "mozilla/layers/WebRenderLayerManager.h"
+#include "mozilla/layers/StackingContextHelper.h"
+
using namespace mozilla;
using namespace mozilla::layers;
using namespace mozilla::dom;
using namespace mozilla::gfx;
nsIFrame*
NS_NewHTMLVideoFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
@@ -427,16 +430,99 @@ 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. No point creating a layer.
+ return false;
+ }
+
+ // 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, aBuilder, aSc, container, rect);
+
+// RefPtr<ImageLayer> layer = static_cast<ImageLayer*>
+// (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
+// if (!layer) {
+// layer = aManager->CreateImageLayer();
+// if (!layer)
+// return nullptr;
+// }
+
+// layer->SetContainer(container);
+// layer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(this));
+// // Set a transform on the layer to draw the video in the right place
+// gfxPoint p = destGFXRect.TopLeft() + aContainerParameters.mOffset;
+//
+// Matrix preTransform = ComputeRotationMatrix(destGFXRect.Width(),
+// destGFXRect.Height(),
+// rotationDeg);
+//
+// Matrix transform = preTransform * Matrix::Translation(p.x, p.y);
+//
+// layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
+// layer->SetScaleToSize(scaleHint, ScaleMode::STRETCH);
+// RefPtr<Layer> result = layer.forget();
+// return result.forget();
+
+ }
+
// 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.