/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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 // for min #include "FrameMetrics.h" // for FrameMetrics #include "Units.h" // for LayerRect, LayerPixel, etc #include "CompositableHost.h" // for CompositableHost #include "gfxEnv.h" // for gfxEnv #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc #include "mozilla/RefPtr.h" // for RefPtr #include "mozilla/StaticPrefs_apz.h" #include "mozilla/StaticPrefs_layers.h" #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/APZSampler.h" // for APZSampler #include "mozilla/layers/BSPTree.h" #include "mozilla/layers/Compositor.h" // for Compositor, etc #include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent #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/APZUtils.h" // for AsyncTransform #include "mozilla/layers/LayerManagerCompositeUtils.h" #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper #include "mozilla/layers/LayersHelpers.h" #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 #include "TextRenderer.h" // for TextRenderer #include #include "GeckoProfiler.h" // for GeckoProfiler static mozilla::LazyLogModule sGfxCullLog("gfx.culling"); #define CULLING_LOG(...) MOZ_LOG(sGfxCullLog, LogLevel::Debug, (__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(visibleRegion.GetBounds().Width(), 500); IntPoint topLeft = visibleRegion.GetBounds().ToUnknownRect().TopLeft(); aManager->GetTextRenderer()->RenderText( aManager->GetCompositor(), ss.str().c_str(), topLeft, aLayer->GetEffectiveTransform(), 16, maxWidth); } static void PrintUniformityInfo(Layer* aLayer) { #if defined(MOZ_GECKO_PROFILER) if (!profiler_thread_is_being_profiled()) { 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->AsHostLayer()->GetShadowBaseTransform(); if (!transform.Is2D()) { return; } Point translation = transform.As2D().GetTranslation(); // Contains the translation applied to a 2d layer so we can track the layer // position at each frame. struct LayerTranslationMarker { static constexpr Span MarkerTypeName() { return MakeStringSpan("LayerTranslation"); } static void StreamJSONMarkerData( baseprofiler::SpliceableJSONWriter& aWriter, ProfileBufferRawPointer aLayer, gfx::Point aPoint) { const size_t bufferSize = 32; char buffer[bufferSize]; SprintfLiteral(buffer, "%p", aLayer.mRawPointer); aWriter.StringProperty("layer", buffer); aWriter.IntProperty("x", aPoint.x); aWriter.IntProperty("y", aPoint.y); } static MarkerSchema MarkerTypeDisplay() { using MS = MarkerSchema; MS schema{MS::Location::markerChart, MS::Location::markerTable}; schema.AddKeyLabelFormat("layer", "Layer", MS::Format::string); schema.AddKeyLabelFormat("x", "X", MS::Format::integer); schema.AddKeyLabelFormat("y", "Y", MS::Format::integer); return schema; } }; profiler_add_marker("LayerTranslation", geckoprofiler::category::GRAPHICS, {}, LayerTranslationMarker{}, WrapProfileBufferRawPointer(aLayer), translation); #endif } static Maybe SelectLayerGeometry( const Maybe& aParentGeometry, const Maybe& aChildGeometry) { // Both the parent and the child layer were split. if (aParentGeometry && aChildGeometry) { return Some(aParentGeometry->ClipPolygon(*aChildGeometry)); } // The parent layer was split. if (aParentGeometry) { return aParentGeometry; } // The child layer was split. if (aChildGeometry) { return aChildGeometry; } // No split. return Nothing(); } void TransformLayerGeometry(Layer* aLayer, Maybe& aGeometry) { Layer* parent = aLayer; gfx::Matrix4x4 transform; // Collect all parent transforms. while (parent != nullptr && !parent->Is3DContextLeaf()) { transform = transform * parent->GetLocalTransform(); parent = parent->GetParent(); } // Transform the geometry to the parent 3D context leaf coordinate space. transform = transform.ProjectTo2D(); if (!transform.IsSingular()) { aGeometry->TransformToScreenSpace(transform.Inverse(), transform); } else { // Discard the geometry since the result might not be correct. aGeometry.reset(); } } template static gfx::IntRect ContainerVisibleRect(ContainerT* aContainer) { gfx::IntRect surfaceRect = aContainer->GetLocalVisibleRegion().GetBounds().ToUnknownRect(); return surfaceRect; } /* all of the per-layer prepared data we need to maintain */ struct PreparedLayer { PreparedLayer(Layer* aLayer, RenderTargetIntRect aClipRect, Maybe&& aGeometry) : mLayer(aLayer), mClipRect(aClipRect), mGeometry(std::move(aGeometry)) {} RefPtr mLayer; RenderTargetIntRect mClipRect; Maybe mGeometry; }; /* all of the prepared data that we need in RenderLayer() */ struct PreparedData { RefPtr mTmpTarget; AutoTArray mLayers; bool mNeedsSurfaceCopy; }; // ContainerPrepare is shared between RefLayer and ContainerLayer template void ContainerPrepare(ContainerT* aContainer, LayerManagerComposite* aManager, const RenderTargetIntRect& aClipRect) { // We can end up calling prepare multiple times if we duplicated // layers due to preserve-3d plane splitting. The results // should be identical, so we only need to do it once. if (aContainer->mPrepared) { return; } aContainer->mPrepared = MakeUnique(); aContainer->mPrepared->mNeedsSurfaceCopy = false; const ContainerLayerComposite::SortMode sortMode = aManager->GetCompositor()->SupportsLayerGeometry() ? ContainerLayerComposite::SortMode::WITH_GEOMETRY : ContainerLayerComposite::SortMode::WITHOUT_GEOMETRY; nsTArray polygons = aContainer->SortChildrenBy3DZOrder(sortMode); for (LayerPolygon& layer : polygons) { LayerComposite* layerToRender = static_cast(layer.layer->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()) { 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, std::move(layer.geometry))); } 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 surface = nullptr; RefPtr& 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 void RenderMinimap(ContainerT* aContainer, const RefPtr& aSampler, LayerManagerComposite* aManager, const RenderTargetIntRect& aClipRect, Layer* aLayer) { Compositor* compositor = aManager->GetCompositor(); MOZ_ASSERT(aSampler); if (aLayer->GetScrollMetadataCount() < 1) { return; } LayerMetricsWrapper wrapper(aLayer, 0); if (!wrapper.GetApzc()) { return; } const FrameMetrics& fm = wrapper.Metrics(); MOZ_ASSERT(fm.IsScrollable()); ParentLayerPoint scrollOffset = aSampler->GetCurrentAsyncScrollOffset(wrapper); // Options const int verticalPadding = 10; const int horizontalPadding = 5; gfx::DeviceColor backgroundColor(0.3f, 0.3f, 0.3f, 0.3f); gfx::DeviceColor tileActiveColor(1, 1, 1, 0.4f); gfx::DeviceColor tileBorderColor(0, 0, 0, 0.1f); gfx::DeviceColor pageBorderColor(0, 0, 0); gfx::DeviceColor criticalDisplayPortColor(1.f, 1.f, 0); gfx::DeviceColor displayPortColor(0, 1.f, 0); gfx::DeviceColor layoutPortColor(1.f, 0, 0); gfx::DeviceColor visualPortColor(0, 0, 1.f, 0.3f); // Rects ParentLayerRect compositionBounds = fm.GetCompositionBounds(); LayerRect scrollRect = fm.GetScrollableRect() * fm.LayersPixelsPerCSSPixel(); LayerRect visualRect = ParentLayerRect(scrollOffset, compositionBounds.Size()) / LayerToParentLayerScale(1); LayerRect dp = (fm.GetDisplayPort() + fm.GetLayoutScrollOffset()) * fm.LayersPixelsPerCSSPixel(); Maybe layoutRect; Maybe cdp; if (fm.IsRootContent()) { CSSRect viewport = aSampler->GetCurrentAsyncLayoutViewport(wrapper); layoutRect = Some(viewport * fm.LayersPixelsPerCSSPixel()); } if (!fm.GetCriticalDisplayPort().IsEmpty()) { cdp = Some((fm.GetCriticalDisplayPort() + fm.GetLayoutScrollOffset()) * fm.LayersPixelsPerCSSPixel()); } // Don't render trivial minimap. They can show up from textboxes and other // tiny frames. if (visualRect.Width() < 64 && visualRect.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()); // 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 layout viewport if it exists (which is only in the root // content APZC). if (layoutRect) { r = transform.TransformBounds(layoutRect->ToUnknownRect()); compositor->SlowDrawRect(r, layoutPortColor, clipRect, aContainer->GetEffectiveTransform()); } // Render the visual viewport. r = transform.TransformBounds(visualRect.ToUnknownRect()); compositor->SlowDrawRect(r, visualPortColor, clipRect, aContainer->GetEffectiveTransform(), 2); } template void RenderLayers(ContainerT* aContainer, LayerManagerComposite* aManager, const RenderTargetIntRect& aClipRect, const Maybe& aGeometry) { Compositor* compositor = aManager->GetCompositor(); RefPtr sampler; if (CompositorBridgeParent* cbp = compositor->GetCompositorBridgeParent()) { sampler = cbp->GetAPZSampler(); } for (size_t i = 0u; i < aContainer->mPrepared->mLayers.Length(); i++) { PreparedLayer& preparedData = aContainer->mPrepared->mLayers[i]; const gfx::IntRect clipRect = preparedData.mClipRect.ToUnknownRect(); LayerComposite* layerToRender = static_cast(preparedData.mLayer->ImplData()); const Maybe& childGeometry = preparedData.mGeometry; Layer* layer = layerToRender->GetLayer(); if (layerToRender->HasStaleCompositor()) { continue; } if (StaticPrefs::layers_acceleration_draw_fps()) { for (const auto& metadata : layer->GetAllScrollMetadata()) { if (metadata.IsApzForceDisabled()) { aManager->DisabledApzWarning(); break; } } } 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 { // Since we force an intermediate surface for nested 3D contexts, // aGeometry and childGeometry are both in the same coordinate space. Maybe geometry = SelectLayerGeometry(aGeometry, childGeometry); // If we are dealing with a nested 3D context, we might need to transform // the geometry back to the coordinate space of the current layer before // rendering the layer. ContainerLayer* container = layer->AsContainerLayer(); const bool isLeafLayer = !container || container->UseIntermediateSurface(); if (geometry && isLeafLayer) { TransformLayerGeometry(layer, geometry); } layerToRender->RenderLayer(clipRect, geometry); } if (StaticPrefs::layers_uniformity_info_AtStartup()) { PrintUniformityInfo(layer); } if (StaticPrefs::layers_draw_layer_info()) { DrawLayerInfo(preparedData.mClipRect, 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; if (sampler) { for (uint32_t i = layer->GetScrollMetadataCount(); i > 0; --i) { LayerMetricsWrapper wrapper(layer, i - 1); if (wrapper.GetApzc()) { MOZ_ASSERT(wrapper.Metrics().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 = wrapper.Metrics().GetCompositionBounds(); aManager->GetCompositor()->DrawDiagnostics( DiagnosticFlags::CONTAINER, compositionBounds.ToUnknownRect(), aClipRect.ToUnknownRect(), asyncTransform * aContainer->GetEffectiveTransform()); asyncTransform = sampler->GetCurrentAsyncTransformWithOverscroll(wrapper) .ToUnknownMatrix() * asyncTransform; } } if (StaticPrefs::apz_minimap_enabled()) { RenderMinimap(aContainer, sampler, aManager, aClipRect, layer); } } // invariant: our GL context should be current here, I don't think we can // assert it though } } template RefPtr 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& 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 RefPtr CreateTemporaryTargetAndCopyFromBackground( ContainerT* aContainer, LayerManagerComposite* aManager) { Compositor* compositor = aManager->GetCompositor(); gfx::IntRect visibleRect = aContainer->GetLocalVisibleRegion().GetBounds().ToUnknownRect(); RefPtr 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 transform2d; MOZ_ASSERT(transform.Is2D(&transform2d) && !gfx::ThebesMatrix(transform2d).HasNonIntegerTranslation()); sourcePoint += gfx::IntPoint::Truncate(transform._41, transform._42); sourcePoint -= previousTarget->GetOrigin(); return compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint); } template void RenderIntermediate(ContainerT* aContainer, LayerManagerComposite* aManager, const gfx::IntRect& aClipRect, RefPtr surface) { Compositor* compositor = aManager->GetCompositor(); RefPtr previousTarget = compositor->GetCurrentRenderTarget(); if (!surface) { return; } compositor->SetRenderTarget(surface); // pre-render all of the layers into our temporary RenderLayers(aContainer, aManager, RenderTargetIntRect::FromUnknownRect(aClipRect), Nothing()); // Unbind the current surface and rebind the previous one. compositor->SetRenderTarget(previousTarget); } template void ContainerRender(ContainerT* aContainer, LayerManagerComposite* aManager, const gfx::IntRect& aClipRect, const Maybe& aGeometry) { MOZ_ASSERT(aContainer->mPrepared); if (aContainer->UseIntermediateSurface()) { RefPtr 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) { return; } gfx::Rect visibleRect( aContainer->GetLocalVisibleRegion().GetBounds().ToUnknownRect()); RefPtr compositor = aManager->GetCompositor(); #ifdef MOZ_DUMP_PAINTING if (gfxEnv::DumpCompositorTextures()) { RefPtr surf = surface->Dump(compositor); if (surf) { WriteSnapshotToDumpFile(aContainer, surf); } } #endif RefPtr container = aContainer; RenderWithAllMasks(aContainer, compositor, aClipRect, [&, surface, compositor, container]( EffectChain& effectChain, const IntRect& clipRect) { effectChain.mPrimaryEffect = new EffectRenderTarget(surface); compositor->DrawGeometry( visibleRect, clipRect, effectChain, container->GetEffectiveOpacity(), container->GetEffectiveTransform(), aGeometry); }); } else { RenderLayers(aContainer, aManager, RenderTargetIntRect::FromUnknownRect(aClipRect), aGeometry); } // 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 (StaticPrefs::layers_acceleration_draw_fps() && aContainer->IsScrollableWithoutContent()) { RefPtr sampler = aManager->GetCompositor()->GetCompositorBridgeParent()->GetAPZSampler(); // 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 (sampler->HasUnusedAsyncTransform(i)) { aManager->UnusedApzTransformWarning(); break; } } } } ContainerLayerComposite::ContainerLayerComposite( LayerManagerComposite* aManager) : ContainerLayer(aManager, nullptr), LayerComposite(aManager) { MOZ_COUNT_CTOR(ContainerLayerComposite); mImplData = static_cast(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. RemoveAllChildren(); } void ContainerLayerComposite::Destroy() { if (!mDestroyed) { while (mFirstChild) { GetFirstChildComposite()->Destroy(); RemoveChild(mFirstChild); } mDestroyed = true; } } LayerComposite* ContainerLayerComposite::GetFirstChildComposite() { if (!mFirstChild) { return nullptr; } return static_cast(mFirstChild->AsHostLayer()); } void ContainerLayerComposite::Cleanup() { mPrepared = nullptr; for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) { static_cast(l->AsHostLayer())->Cleanup(); } } void ContainerLayerComposite::RenderLayer( const gfx::IntRect& aClipRect, const Maybe& aGeometry) { ContainerRender(this, mCompositeManager, aClipRect, aGeometry); } 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()) { static_cast(l->AsHostLayer())->CleanupResources(); } } const LayerIntRegion& ContainerLayerComposite::GetShadowVisibleRegion() { if (!UseIntermediateSurface()) { RecomputeShadowVisibleRegionFromChildren(); } return mShadowVisibleRegion; } const LayerIntRegion& RefLayerComposite::GetShadowVisibleRegion() { if (!UseIntermediateSurface()) { RecomputeShadowVisibleRegionFromChildren(); } return mShadowVisibleRegion; } RefLayerComposite::RefLayerComposite(LayerManagerComposite* aManager) : RefLayer(aManager, nullptr), LayerComposite(aManager) { mImplData = static_cast(this); } RefLayerComposite::~RefLayerComposite() { Destroy(); } void RefLayerComposite::Destroy() { MOZ_ASSERT(!mFirstChild); mDestroyed = true; } LayerComposite* RefLayerComposite::GetFirstChildComposite() { if (!mFirstChild) { return nullptr; } return static_cast(mFirstChild->AsHostLayer()); } void RefLayerComposite::RenderLayer(const gfx::IntRect& aClipRect, const Maybe& aGeometry) { ContainerRender(this, mCompositeManager, aClipRect, aGeometry); } void RefLayerComposite::Prepare(const RenderTargetIntRect& aClipRect) { ContainerPrepare(this, mCompositeManager, aClipRect); } void RefLayerComposite::Cleanup() { mPrepared = nullptr; for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) { static_cast(l->AsHostLayer())->Cleanup(); } } void RefLayerComposite::CleanupResources() { mLastIntermediateSurface = nullptr; mPrepared = nullptr; } } // namespace layers } // namespace mozilla