summaryrefslogtreecommitdiffstats
path: root/gfx/layers/composite/ContainerLayerComposite.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/composite/ContainerLayerComposite.cpp')
-rwxr-xr-xgfx/layers/composite/ContainerLayerComposite.cpp698
1 files changed, 698 insertions, 0 deletions
diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp
new file mode 100755
index 000000000..35070cad6
--- /dev/null
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -0,0 +1,698 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ContainerLayerComposite.h"
+#include <algorithm> // for min
+#include "apz/src/AsyncPanZoomController.h" // for AsyncPanZoomController
+#include "FrameMetrics.h" // for FrameMetrics
+#include "Units.h" // for LayerRect, LayerPixel, etc
+#include "CompositableHost.h" // for CompositableHost
+#include "gfxEnv.h" // for gfxEnv
+#include "gfxPrefs.h" // for gfxPrefs
+#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
+#include "mozilla/RefPtr.h" // for RefPtr
+#include "mozilla/UniquePtr.h" // for UniquePtr
+#include "mozilla/gfx/BaseRect.h" // for BaseRect
+#include "mozilla/gfx/Matrix.h" // for Matrix4x4
+#include "mozilla/gfx/Point.h" // for Point, IntPoint
+#include "mozilla/gfx/Rect.h" // for IntRect, Rect
+#include "mozilla/layers/Compositor.h" // for Compositor, etc
+#include "mozilla/layers/CompositorTypes.h" // for DiagnosticFlags::CONTAINER
+#include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
+#include "mozilla/layers/TextureHost.h" // for CompositingRenderTarget
+#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
+#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
+#include "mozilla/mozalloc.h" // for operator delete, etc
+#include "mozilla/RefPtr.h" // for nsRefPtr
+#include "nsDebug.h" // for NS_ASSERTION
+#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
+#include "nsRegion.h" // for nsIntRegion
+#include "nsTArray.h" // for AutoTArray
+#include <stack>
+#include "TextRenderer.h" // for TextRenderer
+#include <vector>
+#include "GeckoProfiler.h" // for GeckoProfiler
+#ifdef MOZ_ENABLE_PROFILER_SPS
+#include "ProfilerMarkers.h" // for ProfilerMarkers
+#endif
+
+#define CULLING_LOG(...)
+// #define CULLING_LOG(...) printf_stderr("CULLING: " __VA_ARGS__)
+
+#define DUMP(...) do { if (gfxEnv::DumpDebug()) { printf_stderr(__VA_ARGS__); } } while(0)
+#define XYWH(k) (k).x, (k).y, (k).width, (k).height
+#define XY(k) (k).x, (k).y
+#define WH(k) (k).width, (k).height
+
+namespace mozilla {
+namespace layers {
+
+using namespace gfx;
+
+static void DrawLayerInfo(const RenderTargetIntRect& aClipRect,
+ LayerManagerComposite* aManager,
+ Layer* aLayer)
+{
+
+ if (aLayer->GetType() == Layer::LayerType::TYPE_CONTAINER) {
+ // XXX - should figure out a way to render this, but for now this
+ // is hard to do, since it will often get superimposed over the first
+ // child of the layer, which is bad.
+ return;
+ }
+
+ std::stringstream ss;
+ aLayer->PrintInfo(ss, "");
+
+ LayerIntRegion visibleRegion = aLayer->GetVisibleRegion();
+
+ uint32_t maxWidth = std::min<uint32_t>(visibleRegion.GetBounds().width, 500);
+
+ IntPoint topLeft = visibleRegion.ToUnknownRegion().GetBounds().TopLeft();
+ aManager->GetTextRenderer()->RenderText(ss.str().c_str(), topLeft,
+ aLayer->GetEffectiveTransform(), 16,
+ maxWidth);
+}
+
+template<class ContainerT>
+static gfx::IntRect ContainerVisibleRect(ContainerT* aContainer)
+{
+ gfx::IntRect surfaceRect = aContainer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds();
+ return surfaceRect;
+}
+
+static void PrintUniformityInfo(Layer* aLayer)
+{
+#ifdef MOZ_ENABLE_PROFILER_SPS
+ if (!profiler_is_active()) {
+ return;
+ }
+
+ // Don't want to print a log for smaller layers
+ if (aLayer->GetLocalVisibleRegion().GetBounds().width < 300 ||
+ aLayer->GetLocalVisibleRegion().GetBounds().height < 300) {
+ return;
+ }
+
+ Matrix4x4 transform = aLayer->AsLayerComposite()->GetShadowBaseTransform();
+ if (!transform.Is2D()) {
+ return;
+ }
+
+ Point translation = transform.As2D().GetTranslation();
+ LayerTranslationPayload* payload = new LayerTranslationPayload(aLayer, translation);
+ PROFILER_MARKER_PAYLOAD("LayerTranslation", payload);
+#endif
+}
+
+/* all of the per-layer prepared data we need to maintain */
+struct PreparedLayer
+{
+ PreparedLayer(Layer *aLayer, RenderTargetIntRect aClipRect) :
+ mLayer(aLayer), mClipRect(aClipRect) {}
+ RefPtr<Layer> mLayer;
+ RenderTargetIntRect mClipRect;
+};
+
+/* all of the prepared data that we need in RenderLayer() */
+struct PreparedData
+{
+ RefPtr<CompositingRenderTarget> mTmpTarget;
+ AutoTArray<PreparedLayer, 12> mLayers;
+ bool mNeedsSurfaceCopy;
+};
+
+// ContainerPrepare is shared between RefLayer and ContainerLayer
+template<class ContainerT> void
+ContainerPrepare(ContainerT* aContainer,
+ LayerManagerComposite* aManager,
+ const RenderTargetIntRect& aClipRect)
+{
+ aContainer->mPrepared = MakeUnique<PreparedData>();
+ aContainer->mPrepared->mNeedsSurfaceCopy = false;
+
+ /**
+ * Determine which layers to draw.
+ */
+ AutoTArray<Layer*, 12> children;
+ aContainer->SortChildrenBy3DZOrder(children);
+
+ for (uint32_t i = 0; i < children.Length(); i++) {
+ LayerComposite* layerToRender = static_cast<LayerComposite*>(children.ElementAt(i)->ImplData());
+
+ RenderTargetIntRect clipRect = layerToRender->GetLayer()->
+ CalculateScissorRect(aClipRect);
+
+ if (layerToRender->GetLayer()->IsBackfaceHidden()) {
+ continue;
+ }
+
+ // We don't want to skip container layers because otherwise their mPrepared
+ // may be null which is not allowed.
+ if (!layerToRender->GetLayer()->AsContainerLayer()) {
+ if (!layerToRender->GetLayer()->IsVisible() &&
+ !layerToRender->NeedToDrawCheckerboarding(nullptr)) {
+ CULLING_LOG("Sublayer %p has no effective visible region\n", layerToRender->GetLayer());
+ continue;
+ }
+
+ if (clipRect.IsEmpty()) {
+ CULLING_LOG("Sublayer %p has an empty world clip rect\n", layerToRender->GetLayer());
+ continue;
+ }
+ }
+
+ CULLING_LOG("Preparing sublayer %p\n", layerToRender->GetLayer());
+
+ layerToRender->Prepare(clipRect);
+ aContainer->mPrepared->mLayers.AppendElement(PreparedLayer(layerToRender->GetLayer(),
+ clipRect));
+ }
+
+ CULLING_LOG("Preparing container layer %p\n", aContainer->GetLayer());
+
+ /**
+ * Setup our temporary surface for rendering the contents of this container.
+ */
+
+ gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
+ if (surfaceRect.IsEmpty()) {
+ return;
+ }
+
+ bool surfaceCopyNeeded;
+ // DefaultComputeSupportsComponentAlphaChildren can mutate aContainer so call it unconditionally
+ aContainer->DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
+ if (aContainer->UseIntermediateSurface()) {
+ if (!surfaceCopyNeeded) {
+ RefPtr<CompositingRenderTarget> surface = nullptr;
+
+ RefPtr<CompositingRenderTarget>& lastSurf = aContainer->mLastIntermediateSurface;
+ if (lastSurf && !aContainer->mChildrenChanged && lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
+ surface = lastSurf;
+ }
+
+ if (!surface) {
+ // If we don't need a copy we can render to the intermediate now to avoid
+ // unecessary render target switching. This brings a big perf boost on mobile gpus.
+ surface = CreateOrRecycleTarget(aContainer, aManager);
+
+ MOZ_PERFORMANCE_WARNING("gfx", "[%p] Container layer requires intermediate surface rendering\n", aContainer);
+ RenderIntermediate(aContainer, aManager, aClipRect.ToUnknownRect(), surface);
+ aContainer->SetChildrenChanged(false);
+ }
+
+ aContainer->mPrepared->mTmpTarget = surface;
+ } else {
+ MOZ_PERFORMANCE_WARNING("gfx", "[%p] Container layer requires intermediate surface copy\n", aContainer);
+ aContainer->mPrepared->mNeedsSurfaceCopy = true;
+ aContainer->mLastIntermediateSurface = nullptr;
+ }
+ } else {
+ aContainer->mLastIntermediateSurface = nullptr;
+ }
+}
+
+template<class ContainerT> void
+RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager,
+ const RenderTargetIntRect& aClipRect, Layer* aLayer)
+{
+ Compositor* compositor = aManager->GetCompositor();
+
+ if (aLayer->GetScrollMetadataCount() < 1) {
+ return;
+ }
+
+ AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(0);
+ if (!controller) {
+ return;
+ }
+
+ ParentLayerPoint scrollOffset = controller->GetCurrentAsyncScrollOffset(AsyncPanZoomController::RESPECT_FORCE_DISABLE);
+
+ // Options
+ const int verticalPadding = 10;
+ const int horizontalPadding = 5;
+ gfx::Color backgroundColor(0.3f, 0.3f, 0.3f, 0.3f);
+ gfx::Color tileActiveColor(1, 1, 1, 0.4f);
+ gfx::Color tileBorderColor(0, 0, 0, 0.1f);
+ gfx::Color pageBorderColor(0, 0, 0);
+ gfx::Color criticalDisplayPortColor(1.f, 1.f, 0);
+ gfx::Color displayPortColor(0, 1.f, 0);
+ gfx::Color viewPortColor(0, 0, 1.f, 0.3f);
+ gfx::Color visibilityColor(1.f, 0, 0);
+
+ // Rects
+ const FrameMetrics& fm = aLayer->GetFrameMetrics(0);
+ ParentLayerRect compositionBounds = fm.GetCompositionBounds();
+ LayerRect scrollRect = fm.GetScrollableRect() * fm.LayersPixelsPerCSSPixel();
+ LayerRect viewRect = ParentLayerRect(scrollOffset, compositionBounds.Size()) / LayerToParentLayerScale(1);
+ LayerRect dp = (fm.GetDisplayPort() + fm.GetScrollOffset()) * fm.LayersPixelsPerCSSPixel();
+ Maybe<LayerRect> cdp;
+ if (!fm.GetCriticalDisplayPort().IsEmpty()) {
+ cdp = Some((fm.GetCriticalDisplayPort() + fm.GetScrollOffset()) * fm.LayersPixelsPerCSSPixel());
+ }
+
+ // Don't render trivial minimap. They can show up from textboxes and other tiny frames.
+ if (viewRect.width < 64 && viewRect.height < 64) {
+ return;
+ }
+
+ // Compute a scale with an appropriate aspect ratio
+ // We allocate up to 100px of width and the height of this layer.
+ float scaleFactor;
+ float scaleFactorX;
+ float scaleFactorY;
+ Rect dest = Rect(aClipRect.ToUnknownRect());
+ if (aLayer->GetLocalClipRect()) {
+ dest = Rect(aLayer->GetLocalClipRect().value().ToUnknownRect());
+ } else {
+ dest = aContainer->GetEffectiveTransform().Inverse().TransformBounds(dest);
+ }
+ dest = dest.Intersect(compositionBounds.ToUnknownRect());
+ scaleFactorX = std::min(100.f, dest.width - (2 * horizontalPadding)) / scrollRect.width;
+ scaleFactorY = (dest.height - (2 * verticalPadding)) / scrollRect.height;
+ scaleFactor = std::min(scaleFactorX, scaleFactorY);
+ if (scaleFactor <= 0) {
+ return;
+ }
+
+ Matrix4x4 transform = Matrix4x4::Scaling(scaleFactor, scaleFactor, 1);
+ transform.PostTranslate(horizontalPadding + dest.x, verticalPadding + dest.y, 0);
+
+ Rect transformedScrollRect = transform.TransformBounds(scrollRect.ToUnknownRect());
+
+ IntRect clipRect = RoundedOut(aContainer->GetEffectiveTransform().TransformBounds(transformedScrollRect));
+
+ // Render the scrollable area.
+ compositor->FillRect(transformedScrollRect, backgroundColor, clipRect, aContainer->GetEffectiveTransform());
+ compositor->SlowDrawRect(transformedScrollRect, pageBorderColor, clipRect, aContainer->GetEffectiveTransform());
+
+ // If enabled, render information about visibility.
+ if (gfxPrefs::APZMinimapVisibilityEnabled()) {
+ // Retrieve the APZC scrollable layer guid, which we'll use to get the
+ // appropriate visibility information from the layer manager.
+ AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(0);
+ MOZ_ASSERT(controller);
+
+ ScrollableLayerGuid guid = controller->GetGuid();
+
+ // Get the approximately visible region.
+ static CSSIntRegion emptyRegion;
+ CSSIntRegion* visibleRegion = aManager->GetApproximatelyVisibleRegion(guid);
+ if (!visibleRegion) {
+ visibleRegion = &emptyRegion;
+ }
+
+ // Iterate through and draw the rects in the region.
+ for (CSSIntRegion::RectIterator iterator = visibleRegion->RectIter();
+ !iterator.Done();
+ iterator.Next())
+ {
+ CSSIntRect rect = iterator.Get();
+ LayerRect scaledRect = rect * fm.LayersPixelsPerCSSPixel();
+ Rect r = transform.TransformBounds(scaledRect.ToUnknownRect());
+ compositor->FillRect(r, visibilityColor, clipRect, aContainer->GetEffectiveTransform());
+ }
+ }
+
+ // Render the displayport.
+ Rect r = transform.TransformBounds(dp.ToUnknownRect());
+ compositor->FillRect(r, tileActiveColor, clipRect, aContainer->GetEffectiveTransform());
+ compositor->SlowDrawRect(r, displayPortColor, clipRect, aContainer->GetEffectiveTransform());
+
+ // Render the critical displayport if there is one
+ if (cdp) {
+ r = transform.TransformBounds(cdp->ToUnknownRect());
+ compositor->SlowDrawRect(r, criticalDisplayPortColor, clipRect, aContainer->GetEffectiveTransform());
+ }
+
+ // Render the viewport.
+ r = transform.TransformBounds(viewRect.ToUnknownRect());
+ compositor->SlowDrawRect(r, viewPortColor, clipRect, aContainer->GetEffectiveTransform(), 2);
+}
+
+
+template<class ContainerT> void
+RenderLayers(ContainerT* aContainer,
+ LayerManagerComposite* aManager,
+ const RenderTargetIntRect& aClipRect)
+{
+ Compositor* compositor = aManager->GetCompositor();
+
+ for (size_t i = 0u; i < aContainer->mPrepared->mLayers.Length(); i++) {
+ PreparedLayer& preparedData = aContainer->mPrepared->mLayers[i];
+ LayerComposite* layerToRender = static_cast<LayerComposite*>(preparedData.mLayer->ImplData());
+ const RenderTargetIntRect& clipRect = preparedData.mClipRect;
+ Layer* layer = layerToRender->GetLayer();
+
+ if (layerToRender->HasStaleCompositor()) {
+ continue;
+ }
+
+ if (gfxPrefs::LayersDrawFPS()) {
+ for (const auto& metadata : layer->GetAllScrollMetadata()) {
+ if (metadata.IsApzForceDisabled()) {
+ aManager->DisabledApzWarning();
+ break;
+ }
+ }
+ }
+
+ Color color;
+ if (layerToRender->NeedToDrawCheckerboarding(&color)) {
+ if (gfxPrefs::APZHighlightCheckerboardedAreas()) {
+ color = Color(255 / 255.f, 188 / 255.f, 217 / 255.f, 1.f); // "Cotton Candy"
+ }
+ // Ideally we would want to intersect the checkerboard region from the APZ with the layer bounds
+ // and only fill in that area. However the layer bounds takes into account the base translation
+ // for the painted layer whereas the checkerboard region does not. One does not simply
+ // intersect areas in different coordinate spaces. So we do this a little more permissively
+ // and only fill in the background when we know there is checkerboard, which in theory
+ // should only occur transiently.
+ gfx::IntRect layerBounds = layer->GetLayerBounds();
+ EffectChain effectChain(layer);
+ effectChain.mPrimaryEffect = new EffectSolidColor(color);
+ aManager->GetCompositor()->DrawQuad(gfx::Rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height),
+ clipRect.ToUnknownRect(),
+ effectChain, layer->GetEffectiveOpacity(),
+ layer->GetEffectiveTransform());
+ }
+
+ if (layerToRender->HasLayerBeenComposited()) {
+ // Composer2D will compose this layer so skip GPU composition
+ // this time. The flag will be reset for the next composition phase
+ // at the beginning of LayerManagerComposite::Rener().
+ gfx::IntRect clearRect = layerToRender->GetClearRect();
+ if (!clearRect.IsEmpty()) {
+ // Clear layer's visible rect on FrameBuffer with transparent pixels
+ gfx::Rect fbRect(clearRect.x, clearRect.y, clearRect.width, clearRect.height);
+ compositor->ClearRect(fbRect);
+ layerToRender->SetClearRect(gfx::IntRect(0, 0, 0, 0));
+ }
+ } else {
+ layerToRender->RenderLayer(clipRect.ToUnknownRect());
+ }
+
+ if (gfxPrefs::UniformityInfo()) {
+ PrintUniformityInfo(layer);
+ }
+
+ if (gfxPrefs::DrawLayerInfo()) {
+ DrawLayerInfo(clipRect, aManager, layer);
+ }
+
+ // Draw a border around scrollable layers.
+ // A layer can be scrolled by multiple scroll frames. Draw a border
+ // for each.
+ // Within the list of scroll frames for a layer, the layer border for a
+ // scroll frame lower down is affected by the async transforms on scroll
+ // frames higher up, so loop from the top down, and accumulate an async
+ // transform as we go along.
+ Matrix4x4 asyncTransform;
+ for (uint32_t i = layer->GetScrollMetadataCount(); i > 0; --i) {
+ if (layer->GetFrameMetrics(i - 1).IsScrollable()) {
+ // Since the composition bounds are in the parent layer's coordinates,
+ // use the parent's effective transform rather than the layer's own.
+ ParentLayerRect compositionBounds = layer->GetFrameMetrics(i - 1).GetCompositionBounds();
+ aManager->GetCompositor()->DrawDiagnostics(DiagnosticFlags::CONTAINER,
+ compositionBounds.ToUnknownRect(),
+ aClipRect.ToUnknownRect(),
+ asyncTransform * aContainer->GetEffectiveTransform());
+ if (AsyncPanZoomController* apzc = layer->GetAsyncPanZoomController(i - 1)) {
+ asyncTransform =
+ apzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::RESPECT_FORCE_DISABLE).ToUnknownMatrix()
+ * asyncTransform;
+ }
+ }
+ }
+
+ if (gfxPrefs::APZMinimap()) {
+ RenderMinimap(aContainer, aManager, aClipRect, layer);
+ }
+
+ // invariant: our GL context should be current here, I don't think we can
+ // assert it though
+ }
+}
+
+template<class ContainerT> RefPtr<CompositingRenderTarget>
+CreateOrRecycleTarget(ContainerT* aContainer,
+ LayerManagerComposite* aManager)
+{
+ Compositor* compositor = aManager->GetCompositor();
+ SurfaceInitMode mode = INIT_MODE_CLEAR;
+ gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
+ if (aContainer->GetLocalVisibleRegion().GetNumRects() == 1 &&
+ (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE))
+ {
+ mode = INIT_MODE_NONE;
+ }
+
+ RefPtr<CompositingRenderTarget>& lastSurf = aContainer->mLastIntermediateSurface;
+ if (lastSurf && lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
+ if (mode == INIT_MODE_CLEAR) {
+ lastSurf->ClearOnBind();
+ }
+
+ return lastSurf;
+ } else {
+ lastSurf = compositor->CreateRenderTarget(surfaceRect, mode);
+
+ return lastSurf;
+ }
+}
+
+template<class ContainerT> RefPtr<CompositingRenderTarget>
+CreateTemporaryTargetAndCopyFromBackground(ContainerT* aContainer,
+ LayerManagerComposite* aManager)
+{
+ Compositor* compositor = aManager->GetCompositor();
+ gfx::IntRect visibleRect = aContainer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds();
+ RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
+ gfx::IntRect surfaceRect = gfx::IntRect(visibleRect.x, visibleRect.y,
+ visibleRect.width, visibleRect.height);
+
+ gfx::IntPoint sourcePoint = gfx::IntPoint(visibleRect.x, visibleRect.y);
+
+ gfx::Matrix4x4 transform = aContainer->GetEffectiveTransform();
+ DebugOnly<gfx::Matrix> transform2d;
+ MOZ_ASSERT(transform.Is2D(&transform2d) && !gfx::ThebesMatrix(transform2d).HasNonIntegerTranslation());
+ sourcePoint += gfx::IntPoint::Truncate(transform._41, transform._42);
+
+ sourcePoint -= compositor->GetCurrentRenderTarget()->GetOrigin();
+
+ return compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint);
+}
+
+template<class ContainerT> void
+RenderIntermediate(ContainerT* aContainer,
+ LayerManagerComposite* aManager,
+ const gfx::IntRect& aClipRect,
+ RefPtr<CompositingRenderTarget> surface)
+{
+ Compositor* compositor = aManager->GetCompositor();
+ RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
+
+ if (!surface) {
+ return;
+ }
+
+ compositor->SetRenderTarget(surface);
+ // pre-render all of the layers into our temporary
+ RenderLayers(aContainer, aManager, RenderTargetIntRect::FromUnknownRect(aClipRect));
+ // Unbind the current surface and rebind the previous one.
+ compositor->SetRenderTarget(previousTarget);
+}
+
+template<class ContainerT> void
+ContainerRender(ContainerT* aContainer,
+ LayerManagerComposite* aManager,
+ const gfx::IntRect& aClipRect)
+{
+ MOZ_ASSERT(aContainer->mPrepared);
+
+ if (aContainer->UseIntermediateSurface()) {
+ RefPtr<CompositingRenderTarget> surface;
+
+ if (aContainer->mPrepared->mNeedsSurfaceCopy) {
+ // we needed to copy the background so we waited until now to render the intermediate
+ surface = CreateTemporaryTargetAndCopyFromBackground(aContainer, aManager);
+ RenderIntermediate(aContainer, aManager,
+ aClipRect, surface);
+ } else {
+ surface = aContainer->mPrepared->mTmpTarget;
+ }
+
+ if (!surface) {
+ aContainer->mPrepared = nullptr;
+ return;
+ }
+
+ gfx::Rect visibleRect(aContainer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds());
+ RefPtr<Compositor> compositor = aManager->GetCompositor();
+#ifdef MOZ_DUMP_PAINTING
+ if (gfxEnv::DumpCompositorTextures()) {
+ RefPtr<gfx::DataSourceSurface> surf = surface->Dump(compositor);
+ if (surf) {
+ WriteSnapshotToDumpFile(aContainer, surf);
+ }
+ }
+#endif
+
+ RefPtr<ContainerT> container = aContainer;
+ RenderWithAllMasks(aContainer, compositor, aClipRect,
+ [&, surface, compositor, container](EffectChain& effectChain, const IntRect& clipRect) {
+ effectChain.mPrimaryEffect = new EffectRenderTarget(surface);
+ compositor->DrawQuad(visibleRect, clipRect, effectChain,
+ container->GetEffectiveOpacity(),
+ container->GetEffectiveTransform());
+ });
+ } else {
+ RenderLayers(aContainer, aManager, RenderTargetIntRect::FromUnknownRect(aClipRect));
+ }
+ aContainer->mPrepared = nullptr;
+
+ // If it is a scrollable container layer with no child layers, and one of the APZCs
+ // attached to it has a nonempty async transform, then that transform is not applied
+ // to any visible content. Display a warning box (conditioned on the FPS display being
+ // enabled).
+ if (gfxPrefs::LayersDrawFPS() && aContainer->IsScrollInfoLayer()) {
+ // Since aContainer doesn't have any children we can just iterate from the top metrics
+ // on it down to the bottom using GetFirstChild and not worry about walking onto another
+ // underlying layer.
+ for (LayerMetricsWrapper i(aContainer); i; i = i.GetFirstChild()) {
+ if (AsyncPanZoomController* apzc = i.GetApzc()) {
+ if (!apzc->GetAsyncTransformAppliedToContent()
+ && !AsyncTransformComponentMatrix(apzc->GetCurrentAsyncTransform(AsyncPanZoomController::NORMAL)).IsIdentity()) {
+ aManager->UnusedApzTransformWarning();
+ break;
+ }
+ }
+ }
+ }
+}
+
+ContainerLayerComposite::ContainerLayerComposite(LayerManagerComposite *aManager)
+ : ContainerLayer(aManager, nullptr)
+ , LayerComposite(aManager)
+{
+ MOZ_COUNT_CTOR(ContainerLayerComposite);
+ mImplData = static_cast<LayerComposite*>(this);
+}
+
+ContainerLayerComposite::~ContainerLayerComposite()
+{
+ MOZ_COUNT_DTOR(ContainerLayerComposite);
+
+ // We don't Destroy() on destruction here because this destructor
+ // can be called after remote content has crashed, and it may not be
+ // safe to free the IPC resources of our children. Those resources
+ // are automatically cleaned up by IPDL-generated code.
+ //
+ // In the common case of normal shutdown, either
+ // LayerManagerComposite::Destroy(), a parent
+ // *ContainerLayerComposite::Destroy(), or Disconnect() will trigger
+ // cleanup of our resources.
+ while (mFirstChild) {
+ RemoveChild(mFirstChild);
+ }
+}
+
+void
+ContainerLayerComposite::Destroy()
+{
+ if (!mDestroyed) {
+ while (mFirstChild) {
+ static_cast<LayerComposite*>(GetFirstChild()->ImplData())->Destroy();
+ RemoveChild(mFirstChild);
+ }
+ mDestroyed = true;
+ }
+}
+
+LayerComposite*
+ContainerLayerComposite::GetFirstChildComposite()
+{
+ if (!mFirstChild) {
+ return nullptr;
+ }
+ return static_cast<LayerComposite*>(mFirstChild->ImplData());
+}
+
+void
+ContainerLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
+{
+ ContainerRender(this, mCompositeManager, aClipRect);
+}
+
+void
+ContainerLayerComposite::Prepare(const RenderTargetIntRect& aClipRect)
+{
+ ContainerPrepare(this, mCompositeManager, aClipRect);
+}
+
+void
+ContainerLayerComposite::CleanupResources()
+{
+ mLastIntermediateSurface = nullptr;
+ mPrepared = nullptr;
+
+ for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
+ LayerComposite* layerToCleanup = static_cast<LayerComposite*>(l->ImplData());
+ layerToCleanup->CleanupResources();
+ }
+}
+
+RefLayerComposite::RefLayerComposite(LayerManagerComposite* aManager)
+ : RefLayer(aManager, nullptr)
+ , LayerComposite(aManager)
+{
+ mImplData = static_cast<LayerComposite*>(this);
+}
+
+RefLayerComposite::~RefLayerComposite()
+{
+ Destroy();
+}
+
+void
+RefLayerComposite::Destroy()
+{
+ MOZ_ASSERT(!mFirstChild);
+ mDestroyed = true;
+}
+
+LayerComposite*
+RefLayerComposite::GetFirstChildComposite()
+{
+ if (!mFirstChild) {
+ return nullptr;
+ }
+ return static_cast<LayerComposite*>(mFirstChild->ImplData());
+}
+
+void
+RefLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
+{
+ ContainerRender(this, mCompositeManager, aClipRect);
+}
+
+void
+RefLayerComposite::Prepare(const RenderTargetIntRect& aClipRect)
+{
+ ContainerPrepare(this, mCompositeManager, aClipRect);
+}
+
+void
+RefLayerComposite::CleanupResources()
+{
+ mLastIntermediateSurface = nullptr;
+ mPrepared = nullptr;
+}
+
+} // namespace layers
+} // namespace mozilla