void LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaqueRegion) { nsIntRegion localOpaque; Matrix transform2d; bool isTranslation = false; // If aLayer has a simple transform (only an integer translation) then we // can easily convert aOpaqueRegion into pre-transform coordinates and include // that region. if (aLayer->GetLocalTransform().Is2D(&transform2d)) { if (transform2d.IsIntegerTranslation()) { isTranslation = true; localOpaque = aOpaqueRegion; localOpaque.MoveBy(-transform2d._31, -transform2d._32); } } // Subtract any areas that we know to be opaque from our // visible region. LayerComposite *composite = aLayer->AsLayerComposite(); if (!localOpaque.IsEmpty()) { nsIntRegion visible = composite->GetShadowVisibleRegion(); visible.Sub(visible, localOpaque); composite->SetShadowVisibleRegion(visible); } // Compute occlusions for our descendants (in front-to-back order) and allow them to // contribute to localOpaque. for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) { ApplyOcclusionCulling(child, localOpaque); } // If we have a simple transform, then we can add our opaque area into // aOpaqueRegion. if (isTranslation && !aLayer->HasMaskLayers() && aLayer->GetLocalOpacity() == 1.0f) { if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) { localOpaque.Or(localOpaque, composite->GetFullyRenderedRegion()); } localOpaque.MoveBy(transform2d._31, transform2d._32); const Maybe<ParentLayerIntRect>& clip = aLayer->GetEffectiveClipRect(); if (clip) { localOpaque.And(localOpaque, ParentLayerIntRect::ToUntyped(*clip)); } aOpaqueRegion.Or(aOpaqueRegion, localOpaque); } }
// Go down the composite layer tree, setting properties to match their // content-side counterparts. static void SetShadowProperties(Layer* aLayer) { // FIXME: Bug 717688 -- Do these updates in LayerTransactionParent::RecvUpdate. LayerComposite* layerComposite = aLayer->AsLayerComposite(); // Set the layerComposite's base transform to the layer's base transform. layerComposite->SetShadowTransform(aLayer->GetBaseTransform()); layerComposite->SetShadowTransformSetByAnimation(false); layerComposite->SetShadowVisibleRegion(aLayer->GetVisibleRegion()); layerComposite->SetShadowClipRect(aLayer->GetClipRect()); layerComposite->SetShadowOpacity(aLayer->GetOpacity()); for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { SetShadowProperties(child); } }
// Go down shadow layer tree and apply transformations for scrollable layers. static void TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader, nsIFrame* aFrame, Layer* aLayer, const ViewTransform& aTransform, float aTempScaleDiffX = 1.0, float aTempScaleDiffY = 1.0) { LayerComposite* shadow = aLayer->AsLayerComposite(); shadow->SetShadowClipRect(aLayer->GetClipRect()); shadow->SetShadowVisibleRegion(aLayer->GetVisibleRegion()); shadow->SetShadowOpacity(aLayer->GetOpacity()); const FrameMetrics* metrics = GetFrameMetrics(aLayer); gfx3DMatrix shadowTransform = aLayer->GetTransform(); ViewTransform layerTransform = aTransform; if (metrics && metrics->IsScrollable()) { const ViewID scrollId = metrics->mScrollId; const nsContentView* view = aFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId); NS_ABORT_IF_FALSE(view, "Array of views should be consistent with layer tree"); const gfx3DMatrix& currentTransform = aLayer->GetTransform(); const ViewConfig& config = view->GetViewConfig(); // With temporary scale we should compensate translation // using temporary scale value aTempScaleDiffX *= GetXScale(shadowTransform) * config.mXScale; aTempScaleDiffY *= GetYScale(shadowTransform) * config.mYScale; ViewTransform viewTransform = ComputeShadowTreeTransform( aFrame, aFrameLoader, metrics, view->GetViewConfig(), aTempScaleDiffX, aTempScaleDiffY ); // Apply the layer's own transform *before* the view transform shadowTransform = gfx3DMatrix(viewTransform) * currentTransform; layerTransform = viewTransform; if (metrics->IsRootScrollable()) { // Apply the translation *before* we do the rest of the transforms. nsIntPoint offset = GetContentRectLayerOffset(aFrame, aBuilder); shadowTransform = shadowTransform * gfx3DMatrix::Translation(float(offset.x), float(offset.y), 0.0); } } if (aLayer->GetIsFixedPosition() && !aLayer->GetParent()->GetIsFixedPosition()) { // Alter the shadow transform of fixed position layers in the situation // that the view transform's scroll position doesn't match the actual // scroll position, due to asynchronous layer scrolling. float offsetX = layerTransform.mTranslation.x; float offsetY = layerTransform.mTranslation.y; ReverseTranslate(shadowTransform, gfxPoint(offsetX, offsetY)); const nsIntRect* clipRect = shadow->GetShadowClipRect(); if (clipRect) { nsIntRect transformedClipRect(*clipRect); transformedClipRect.MoveBy(-offsetX, -offsetY); shadow->SetShadowClipRect(&transformedClipRect); } } // The transform already takes the resolution scale into account. Since we // will apply the resolution scale again when computing the effective // transform, we must apply the inverse resolution scale here. if (ContainerLayer* c = aLayer->AsContainerLayer()) { shadowTransform.Scale(1.0f/c->GetPreXScale(), 1.0f/c->GetPreYScale(), 1); } shadowTransform.ScalePost(1.0f/aLayer->GetPostXScale(), 1.0f/aLayer->GetPostYScale(), 1); shadow->SetShadowTransform(shadowTransform); for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { TransformShadowTree(aBuilder, aFrameLoader, aFrame, child, layerTransform, aTempScaleDiffX, aTempScaleDiffY); } }
template<class ContainerT> void ContainerRender(ContainerT* aContainer, LayerManagerComposite* aManager, const nsIntRect& aClipRect) { /** * Setup our temporary surface for rendering the contents of this container. */ RefPtr<CompositingRenderTarget> surface; Compositor* compositor = aManager->GetCompositor(); RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget(); nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds(); aContainer->mSupportsComponentAlphaChildren = false; float opacity = aContainer->GetEffectiveOpacity(); bool needsSurface = aContainer->UseIntermediateSurface(); if (needsSurface) { SurfaceInitMode mode = INIT_MODE_CLEAR; bool surfaceCopyNeeded = false; gfx::IntRect surfaceRect = gfx::IntRect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height); gfx::IntPoint sourcePoint = gfx::IntPoint(visibleRect.x, visibleRect.y); // we're about to create a framebuffer backed by textures to use as an intermediate // surface. What to do if its size (as given by framebufferRect) would exceed the // maximum texture size supported by the GL? The present code chooses the compromise // of just clamping the framebuffer's size to the max supported size. // This gives us a lower resolution rendering of the intermediate surface (children layers). // See bug 827170 for a discussion. int32_t maxTextureSize = compositor->GetMaxTextureSize(); surfaceRect.width = std::min(maxTextureSize, surfaceRect.width); surfaceRect.height = std::min(maxTextureSize, surfaceRect.height); if (aContainer->GetEffectiveVisibleRegion().GetNumRects() == 1 && (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE)) { // don't need a background, we're going to paint all opaque stuff aContainer->mSupportsComponentAlphaChildren = true; mode = INIT_MODE_NONE; } else { const gfx3DMatrix& transform3D = aContainer->GetEffectiveTransform(); gfxMatrix transform; // If we have an opaque ancestor layer, then we can be sure that // all the pixels we draw into are either opaque already or will be // covered by something opaque. Otherwise copying up the background is // not safe. if (HasOpaqueAncestorLayer(aContainer) && transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation()) { surfaceCopyNeeded = gfxPlatform::ComponentAlphaEnabled(); sourcePoint.x += transform.x0; sourcePoint.y += transform.y0; aContainer->mSupportsComponentAlphaChildren = gfxPlatform::ComponentAlphaEnabled(); } } sourcePoint -= compositor->GetCurrentRenderTarget()->GetOrigin(); if (surfaceCopyNeeded) { surface = compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint); } else { surface = compositor->CreateRenderTarget(surfaceRect, mode); } if (!surface) { return; } compositor->SetRenderTarget(surface); } else { surface = previousTarget; aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) || (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren()); } nsAutoTArray<Layer*, 12> children; aContainer->SortChildrenBy3DZOrder(children); /** * Render this container's contents. */ for (uint32_t i = 0; i < children.Length(); i++) { LayerComposite* layerToRender = static_cast<LayerComposite*>(children.ElementAt(i)->ImplData()); if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty() && !layerToRender->GetLayer()->AsContainerLayer()) { continue; } if (i + 1 < children.Length() && layerToRender->GetLayer()->GetEffectiveTransform().IsIdentity()) { LayerComposite* nextLayer = static_cast<LayerComposite*>(children.ElementAt(i + 1)->ImplData()); nsIntRect nextLayerOpaqueRect; if (nextLayer && nextLayer->GetLayer()) { nextLayerOpaqueRect = GetOpaqueRect(nextLayer->GetLayer()); } if (!nextLayerOpaqueRect.IsEmpty()) { nsIntRegion visibleRegion; visibleRegion.Sub(layerToRender->GetShadowVisibleRegion(), nextLayerOpaqueRect); layerToRender->SetShadowVisibleRegion(visibleRegion); if (visibleRegion.IsEmpty()) { continue; } } } nsIntRect clipRect = layerToRender->GetLayer()-> CalculateScissorRect(aClipRect, &aManager->GetWorldTransform()); if (clipRect.IsEmpty()) { continue; } if (layerToRender->HasLayerBeenComposited()) { // Composer2D will compose this layer so skip GPU composition // this time & reset composition flag for next composition phase layerToRender->SetLayerComposited(false); } else { layerToRender->RenderLayer(clipRect); } // invariant: our GL context should be current here, I don't think we can // assert it though } if (needsSurface) { // Unbind the current surface and rebind the previous one. #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { nsRefPtr<gfxImageSurface> surf = surface->Dump(aManager->GetCompositor()); WriteSnapshotToDumpFile(aContainer, surf); } #endif compositor->SetRenderTarget(previousTarget); EffectChain effectChain; LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(aContainer->GetMaskLayer(), effectChain, !aContainer->GetTransform().CanDraw2D()); effectChain.mPrimaryEffect = new EffectRenderTarget(surface); gfx::Matrix4x4 transform; ToMatrix4x4(aContainer->GetEffectiveTransform(), transform); gfx::Rect rect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); aManager->GetCompositor()->DrawQuad(rect, clipRect, effectChain, opacity, transform); } if (aContainer->GetFrameMetrics().IsScrollable()) { gfx::Matrix4x4 transform; ToMatrix4x4(aContainer->GetEffectiveTransform(), transform); const FrameMetrics& frame = aContainer->GetFrameMetrics(); LayerRect layerBounds = ScreenRect(frame.mCompositionBounds) * ScreenToLayerScale(1.0); gfx::Rect rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); aManager->GetCompositor()->DrawDiagnostics(DIAGNOSTIC_CONTAINER, rect, clipRect, transform); } }
void LayerManagerComposite::PostProcessLayers(Layer* aLayer, nsIntRegion& aOpaqueRegion, LayerIntRegion& aVisibleRegion, const Maybe<ParentLayerIntRect>& aClipFromAncestors) { if (aLayer->Extend3DContext()) { // For layers participating 3D rendering context, their visible // region should be empty (invisible), so we pass through them // without doing anything. // Direct children of the establisher may have a clip, becaue the // item containing it; ex. of nsHTMLScrollFrame, may give it one. Maybe<ParentLayerIntRect> layerClip = aLayer->AsHostLayer()->GetShadowClipRect(); Maybe<ParentLayerIntRect> ancestorClipForChildren = IntersectMaybeRects(layerClip, aClipFromAncestors); MOZ_ASSERT(!layerClip || !aLayer->Combines3DTransformWithAncestors(), "Only direct children of the establisher could have a clip"); for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) { PostProcessLayers(child, aOpaqueRegion, aVisibleRegion, ancestorClipForChildren); } return; } nsIntRegion localOpaque; // Treat layers on the path to the root of the 3D rendering context as // a giant layer if it is a leaf. Matrix4x4 transform = GetAccTransformIn3DContext(aLayer); Matrix transform2d; Maybe<IntPoint> integerTranslation; // If aLayer has a simple transform (only an integer translation) then we // can easily convert aOpaqueRegion into pre-transform coordinates and include // that region. if (transform.Is2D(&transform2d)) { if (transform2d.IsIntegerTranslation()) { integerTranslation = Some(IntPoint::Truncate(transform2d.GetTranslation())); localOpaque = aOpaqueRegion; localOpaque.MoveBy(-*integerTranslation); } } // Compute a clip that's the combination of our layer clip with the clip // from our ancestors. LayerComposite* composite = static_cast<LayerComposite*>(aLayer->AsHostLayer()); Maybe<ParentLayerIntRect> layerClip = composite->GetShadowClipRect(); MOZ_ASSERT(!layerClip || !aLayer->Combines3DTransformWithAncestors(), "The layer with a clip should not participate " "a 3D rendering context"); Maybe<ParentLayerIntRect> outsideClip = IntersectMaybeRects(layerClip, aClipFromAncestors); // Convert the combined clip into our pre-transform coordinate space, so // that it can later be intersected with our visible region. // If our transform is a perspective, there's no meaningful insideClip rect // we can compute (it would need to be a cone). Maybe<LayerIntRect> insideClip; if (outsideClip && !transform.HasPerspectiveComponent()) { Matrix4x4 inverse = transform; if (inverse.Invert()) { Maybe<LayerRect> insideClipFloat = UntransformBy(ViewAs<ParentLayerToLayerMatrix4x4>(inverse), ParentLayerRect(*outsideClip), LayerRect::MaxIntRect()); if (insideClipFloat) { insideClipFloat->RoundOut(); LayerIntRect insideClipInt; if (insideClipFloat->ToIntRect(&insideClipInt)) { insideClip = Some(insideClipInt); } } } } Maybe<ParentLayerIntRect> ancestorClipForChildren; if (insideClip) { ancestorClipForChildren = Some(ViewAs<ParentLayerPixel>(*insideClip, PixelCastJustification::MovingDownToChildren)); } // Save the value of localOpaque, which currently stores the region obscured // by siblings (and uncles and such), before our descendants contribute to it. nsIntRegion obscured = localOpaque; // Recurse on our descendants, in front-to-back order. In this process: // - Occlusions are computed for them, and they contribute to localOpaque. // - They recalculate their visible regions, taking ancestorClipForChildren // into account, and accumulate them into descendantsVisibleRegion. LayerIntRegion descendantsVisibleRegion; bool hasPreserve3DChild = false; for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) { PostProcessLayers(child, localOpaque, descendantsVisibleRegion, ancestorClipForChildren); if (child->Extend3DContext()) { hasPreserve3DChild = true; } } // Recalculate our visible region. LayerIntRegion visible = composite->GetShadowVisibleRegion(); // If we have descendants, throw away the visible region stored on this // layer, and use the region accumulated by our descendants instead. if (aLayer->GetFirstChild() && !hasPreserve3DChild) { visible = descendantsVisibleRegion; } // Subtract any areas that we know to be opaque. if (!obscured.IsEmpty()) { visible.SubOut(LayerIntRegion::FromUnknownRegion(obscured)); } // Clip the visible region using the combined clip. if (insideClip) { visible.AndWith(*insideClip); } composite->SetShadowVisibleRegion(visible); // Transform the newly calculated visible region into our parent's space, // apply our clip to it (if any), and accumulate it into |aVisibleRegion| // for the caller to use. ParentLayerIntRegion visibleParentSpace = TransformBy( ViewAs<LayerToParentLayerMatrix4x4>(transform), visible); if (const Maybe<ParentLayerIntRect>& clipRect = composite->GetShadowClipRect()) { visibleParentSpace.AndWith(*clipRect); } aVisibleRegion.OrWith(ViewAs<LayerPixel>(visibleParentSpace, PixelCastJustification::MovingDownToChildren)); // If we have a simple transform, then we can add our opaque area into // aOpaqueRegion. if (integerTranslation && !aLayer->HasMaskLayers() && aLayer->IsOpaqueForVisibility()) { if (aLayer->IsOpaque()) { localOpaque.OrWith(composite->GetFullyRenderedRegion()); } localOpaque.MoveBy(*integerTranslation); if (layerClip) { localOpaque.AndWith(layerClip->ToUnknownRect()); } aOpaqueRegion.OrWith(localOpaque); } }
// ContainerRender is shared between RefLayer and ContainerLayer template<class ContainerT> void ContainerRender(ContainerT* aContainer, LayerManagerComposite* aManager, const nsIntRect& aClipRect) { /** * Setup our temporary surface for rendering the contents of this container. */ RefPtr<CompositingRenderTarget> surface; Compositor* compositor = aManager->GetCompositor(); RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget(); nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds(); float opacity = aContainer->GetEffectiveOpacity(); bool needsSurface = aContainer->UseIntermediateSurface(); bool surfaceCopyNeeded; aContainer->DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded); if (needsSurface) { SurfaceInitMode mode = INIT_MODE_CLEAR; gfx::IntRect surfaceRect = gfx::IntRect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height); // we're about to create a framebuffer backed by textures to use as an intermediate // surface. What to do if its size (as given by framebufferRect) would exceed the // maximum texture size supported by the GL? The present code chooses the compromise // of just clamping the framebuffer's size to the max supported size. // This gives us a lower resolution rendering of the intermediate surface (children layers). // See bug 827170 for a discussion. int32_t maxTextureSize = compositor->GetMaxTextureSize(); surfaceRect.width = std::min(maxTextureSize, surfaceRect.width); surfaceRect.height = std::min(maxTextureSize, surfaceRect.height); if (aContainer->GetEffectiveVisibleRegion().GetNumRects() == 1 && (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE)) { mode = INIT_MODE_NONE; } if (surfaceCopyNeeded) { 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(transform._41, transform._42); sourcePoint -= compositor->GetCurrentRenderTarget()->GetOrigin(); surface = compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint); } else { surface = compositor->CreateRenderTarget(surfaceRect, mode); } if (!surface) { return; } compositor->SetRenderTarget(surface); } else { surface = previousTarget; } nsAutoTArray<Layer*, 12> children; aContainer->SortChildrenBy3DZOrder(children); // If this is a scrollable container layer, and it's overscrolled, the layer's // contents are transformed in a way that would leave blank regions in the // composited area. If the layer has a background color, fill these areas // with the background color by drawing a rectangle of the background color // over the entire composited area before drawing the container contents. if (AsyncPanZoomController* apzc = aContainer->GetAsyncPanZoomController()) { // Make sure not to do this on a "scrollinfo" layer (one with an empty visible // region) because it's just a placeholder for APZ purposes. if (apzc->IsOverscrolled() && !aContainer->GetVisibleRegion().IsEmpty()) { gfxRGBA color = aContainer->GetBackgroundColor(); // If the background is completely transparent, there's no point in // drawing anything for it. Hopefully the layers behind, if any, will // provide suitable content for the overscroll effect. if (color.a != 0.0) { EffectChain effectChain(aContainer); effectChain.mPrimaryEffect = new EffectSolidColor(ToColor(color)); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); Compositor* compositor = aManager->GetCompositor(); compositor->DrawQuad(compositor->ClipRectInLayersCoordinates(clipRect), clipRect, effectChain, opacity, Matrix4x4()); } } } /** * Render this container's contents. */ for (uint32_t i = 0; i < children.Length(); i++) { LayerComposite* layerToRender = static_cast<LayerComposite*>(children.ElementAt(i)->ImplData()); if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty() && !layerToRender->GetLayer()->AsContainerLayer()) { continue; } nsIntRect clipRect = layerToRender->GetLayer()-> CalculateScissorRect(aClipRect, &aManager->GetWorldTransform()); if (clipRect.IsEmpty()) { continue; } nsIntRegion savedVisibleRegion; bool restoreVisibleRegion = false; if (i + 1 < children.Length() && layerToRender->GetLayer()->GetEffectiveTransform().IsIdentity()) { LayerComposite* nextLayer = static_cast<LayerComposite*>(children.ElementAt(i + 1)->ImplData()); nsIntRect nextLayerOpaqueRect; if (nextLayer && nextLayer->GetLayer()) { nextLayerOpaqueRect = GetOpaqueRect(nextLayer->GetLayer()); } if (!nextLayerOpaqueRect.IsEmpty()) { savedVisibleRegion = layerToRender->GetShadowVisibleRegion(); nsIntRegion visibleRegion; visibleRegion.Sub(savedVisibleRegion, nextLayerOpaqueRect); if (visibleRegion.IsEmpty()) { continue; } layerToRender->SetShadowVisibleRegion(visibleRegion); restoreVisibleRegion = true; } } if (layerToRender->HasLayerBeenComposited()) { // Composer2D will compose this layer so skip GPU composition // this time & reset composition flag for next composition phase layerToRender->SetLayerComposited(false); nsIntRect 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(nsIntRect(0, 0, 0, 0)); } } else { layerToRender->RenderLayer(clipRect); } if (restoreVisibleRegion) { // Restore the region in case it's not covered by opaque content next time layerToRender->SetShadowVisibleRegion(savedVisibleRegion); } if (gfxPrefs::LayersScrollGraph()) { DrawVelGraph(clipRect, aManager, layerToRender->GetLayer()); } if (gfxPrefs::UniformityInfo()) { PrintUniformityInfo(layerToRender->GetLayer()); } if (gfxPrefs::DrawLayerInfo()) { DrawLayerInfo(clipRect, aManager, layerToRender->GetLayer()); } // invariant: our GL context should be current here, I don't think we can // assert it though } if (needsSurface) { // Unbind the current surface and rebind the previous one. #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { RefPtr<gfx::DataSourceSurface> surf = surface->Dump(aManager->GetCompositor()); if (surf) { WriteSnapshotToDumpFile(aContainer, surf); } } #endif compositor->SetRenderTarget(previousTarget); EffectChain effectChain(aContainer); LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(aContainer->GetMaskLayer(), effectChain, !aContainer->GetTransform().CanDraw2D()); aContainer->AddBlendModeEffect(effectChain); effectChain.mPrimaryEffect = new EffectRenderTarget(surface); gfx::Rect rect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); aManager->GetCompositor()->DrawQuad(rect, clipRect, effectChain, opacity, aContainer->GetEffectiveTransform()); } if (aContainer->GetFrameMetrics().IsScrollable()) { const FrameMetrics& frame = aContainer->GetFrameMetrics(); LayerRect layerBounds = ParentLayerRect(frame.mCompositionBounds) * ParentLayerToLayerScale(1.0); gfx::Rect rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); aManager->GetCompositor()->DrawDiagnostics(DiagnosticFlags::CONTAINER, rect, clipRect, aContainer->GetEffectiveTransform()); } }
void LayerManagerComposite::PostProcessLayers(Layer* aLayer, nsIntRegion& aOpaqueRegion, LayerIntRegion& aVisibleRegion) { nsIntRegion localOpaque; Matrix transform2d; Maybe<nsIntPoint> integerTranslation; // If aLayer has a simple transform (only an integer translation) then we // can easily convert aOpaqueRegion into pre-transform coordinates and include // that region. if (aLayer->GetLocalTransform().Is2D(&transform2d)) { if (transform2d.IsIntegerTranslation()) { integerTranslation = Some(TruncatedToInt(transform2d.GetTranslation())); localOpaque = aOpaqueRegion; localOpaque.MoveBy(-*integerTranslation); } } // Save the value of localOpaque, which currently stores the region obscured // by siblings (and uncles and such), before our descendants contribute to it. nsIntRegion obscured = localOpaque; // Recurse on our descendants, in front-to-back order. In this process: // - Occlusions are computed for them, and they contribute to localOpaque. // - They recalculate their visible regions, and accumulate them into // descendantsVisibleRegion. LayerIntRegion descendantsVisibleRegion; for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) { PostProcessLayers(child, localOpaque, descendantsVisibleRegion); } // Recalculate our visible region. LayerComposite* composite = aLayer->AsLayerComposite(); LayerIntRegion visible = composite->GetShadowVisibleRegion(); // If we have descendants, throw away the visible region stored on this // layer, and use the region accumulated by our descendants instead. if (aLayer->GetFirstChild()) { visible = descendantsVisibleRegion; } // Subtract any areas that we know to be opaque. if (!obscured.IsEmpty()) { visible.SubOut(LayerIntRegion::FromUnknownRegion(obscured)); } composite->SetShadowVisibleRegion(visible); // Transform the newly calculated visible region into our parent's space, // apply our clip to it (if any), and accumulate it into |aVisibleRegion| // for the caller to use. ParentLayerIntRegion visibleParentSpace = TransformTo<ParentLayerPixel>( aLayer->GetLocalTransform(), visible); if (const Maybe<ParentLayerIntRect>& clipRect = composite->GetShadowClipRect()) { visibleParentSpace.AndWith(*clipRect); } aVisibleRegion.OrWith(ViewAs<LayerPixel>(visibleParentSpace, PixelCastJustification::MovingDownToChildren)); // If we have a simple transform, then we can add our opaque area into // aOpaqueRegion. if (integerTranslation && !aLayer->HasMaskLayers() && aLayer->IsOpaqueForVisibility()) { if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) { localOpaque.OrWith(composite->GetFullyRenderedRegion()); } localOpaque.MoveBy(*integerTranslation); const Maybe<ParentLayerIntRect>& clip = aLayer->GetEffectiveClipRect(); if (clip) { localOpaque.AndWith(clip->ToUnknownRect()); } aOpaqueRegion.OrWith(localOpaque); } }