bool Layer::MayResample() { Matrix transform2d; return !GetEffectiveTransform().Is2D(&transform2d) || ThebesMatrix(transform2d).HasNonIntegerTranslation() || AncestorLayerMayChangeTransform(this); }
bool BasicContainerLayer::ChildrenPartitionVisibleRegion(const gfx::IntRect& aInRect) { Matrix transform; if (!GetEffectiveTransform().CanDraw2D(&transform) || ThebesMatrix(transform).HasNonIntegerTranslation()) return false; nsIntPoint offset(int32_t(transform._31), int32_t(transform._32)); gfx::IntRect rect = aInRect.Intersect(GetEffectiveVisibleRegion().GetBounds() + offset); nsIntRegion covered; for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) { if (ToData(l)->IsHidden()) continue; Matrix childTransform; if (!l->GetEffectiveTransform().CanDraw2D(&childTransform) || ThebesMatrix(childTransform).HasNonIntegerTranslation() || l->GetEffectiveOpacity() != 1.0) return false; nsIntRegion childRegion = l->GetEffectiveVisibleRegion(); childRegion.MoveBy(int32_t(childTransform._31), int32_t(childTransform._32)); childRegion.And(childRegion, rect); if (l->GetClipRect()) { childRegion.And(childRegion, ParentLayerIntRect::ToUntyped(*l->GetClipRect()) + offset); } nsIntRegion intersection; intersection.And(covered, childRegion); if (!intersection.IsEmpty()) return false; covered.Or(covered, childRegion); } return covered.Contains(rect); }
static void IncrementScaleRestyleCountIfNeeded(nsIFrame* aFrame, LayerActivity* aActivity) { const nsStyleDisplay* display = aFrame->StyleDisplay(); if (!display->mSpecifiedTransform) { // The transform was removed. aActivity->mPreviousTransformScale = Nothing(); IncrementMutationCount(&aActivity->mScaleRestyleCount); return; } // Compute the new scale due to the CSS transform property. nsPresContext* presContext = aFrame->PresContext(); RuleNodeCacheConditions dummy; nsStyleTransformMatrix::TransformReferenceBox refBox(aFrame); Matrix4x4 transform = nsStyleTransformMatrix::ReadTransforms(display->mSpecifiedTransform->mHead, aFrame->StyleContext(), presContext, dummy, refBox, presContext->AppUnitsPerCSSPixel()); Matrix transform2D; if (!transform.Is2D(&transform2D)) { // We don't attempt to handle 3D transforms; just assume the scale changed. aActivity->mPreviousTransformScale = Nothing(); IncrementMutationCount(&aActivity->mScaleRestyleCount); return; } gfxSize scale = ThebesMatrix(transform2D).ScaleFactors(true); if (aActivity->mPreviousTransformScale == Some(scale)) { return; // Nothing changed. } aActivity->mPreviousTransformScale = Some(scale); IncrementMutationCount(&aActivity->mScaleRestyleCount); }
void ContainerLayerD3D9::RenderLayer() { nsRefPtr<IDirect3DSurface9> previousRenderTarget; nsRefPtr<IDirect3DTexture9> renderTexture; float previousRenderTargetOffset[4]; float renderTargetOffset[] = { 0, 0, 0, 0 }; float oldViewMatrix[4][4]; RECT containerD3D9ClipRect; device()->GetScissorRect(&containerD3D9ClipRect); // Convert scissor to an nsIntRect. RECT's are exclusive on the bottom and // right values. nsIntRect oldScissor(containerD3D9ClipRect.left, containerD3D9ClipRect.top, containerD3D9ClipRect.right - containerD3D9ClipRect.left, containerD3D9ClipRect.bottom - containerD3D9ClipRect.top); ReadbackProcessor readback; readback.BuildUpdates(this); nsIntRect visibleRect = GetEffectiveVisibleRegion().GetBounds(); bool useIntermediate = UseIntermediateSurface(); mSupportsComponentAlphaChildren = false; if (useIntermediate) { nsRefPtr<IDirect3DSurface9> renderSurface; if (!mD3DManager->CompositingDisabled()) { device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget)); HRESULT hr = device()->CreateTexture(visibleRect.width, visibleRect.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, getter_AddRefs(renderTexture), nullptr); if (FAILED(hr)) { ReportFailure(NS_LITERAL_CSTRING("ContainerLayerD3D9::ContainerRender(): Failed to create texture"), hr); return; } nsRefPtr<IDirect3DSurface9> renderSurface; renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface)); device()->SetRenderTarget(0, renderSurface); } if (mVisibleRegion.GetNumRects() == 1 && (GetContentFlags() & CONTENT_OPAQUE)) { // don't need a background, we're going to paint all opaque stuff mSupportsComponentAlphaChildren = true; } else { Matrix4x4 transform3D = GetEffectiveTransform(); Matrix 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. HRESULT hr = E_FAIL; if (HasOpaqueAncestorLayer(this) && transform3D.Is2D(&transform) && !ThebesMatrix(transform).HasNonIntegerTranslation()) { // Copy background up from below RECT dest = { 0, 0, visibleRect.width, visibleRect.height }; RECT src = dest; ::OffsetRect(&src, visibleRect.x + int32_t(transform._31), visibleRect.y + int32_t(transform._32)); if (!mD3DManager->CompositingDisabled()) { hr = device()-> StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE); } } if (hr == S_OK) { mSupportsComponentAlphaChildren = true; } else if (!mD3DManager->CompositingDisabled()) { device()-> Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0); } } device()-> GetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1); renderTargetOffset[0] = (float)visibleRect.x; renderTargetOffset[1] = (float)visibleRect.y; device()-> SetVertexShaderConstantF(CBvRenderTargetOffset, renderTargetOffset, 1); gfx3DMatrix viewMatrix; /* * Matrix to transform to viewport space ( <-1.0, 1.0> topleft, * <1.0, -1.0> bottomright) */ viewMatrix._11 = 2.0f / visibleRect.width; viewMatrix._22 = -2.0f / visibleRect.height; viewMatrix._41 = -1.0f; viewMatrix._42 = 1.0f; device()-> GetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4); device()-> SetVertexShaderConstantF(CBmProjection, &viewMatrix._11, 4); } else { mSupportsComponentAlphaChildren = (GetContentFlags() & CONTENT_OPAQUE) || (mParent && mParent->SupportsComponentAlphaChildren()); } nsAutoTArray<Layer*, 12> children; SortChildrenBy3DZOrder(children); /* * Render this container's contents. */ for (uint32_t i = 0; i < children.Length(); i++) { LayerD3D9* layerToRender = static_cast<LayerD3D9*>(children.ElementAt(i)->ImplData()); if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) { continue; } nsIntRect scissorRect = RenderTargetPixel::ToUntyped(layerToRender->GetLayer()->CalculateScissorRect(RenderTargetPixel::FromUntyped(oldScissor), nullptr)); if (scissorRect.IsEmpty()) { continue; } RECT d3drect; d3drect.left = scissorRect.x; d3drect.top = scissorRect.y; d3drect.right = scissorRect.x + scissorRect.width; d3drect.bottom = scissorRect.y + scissorRect.height; device()->SetScissorRect(&d3drect); if (layerToRender->GetLayer()->GetType() == TYPE_THEBES) { static_cast<ThebesLayerD3D9*>(layerToRender)->RenderThebesLayer(&readback); } else { layerToRender->RenderLayer(); } } if (useIntermediate && !mD3DManager->CompositingDisabled()) { device()->SetRenderTarget(0, previousRenderTarget); device()->SetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1); device()->SetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4); device()->SetVertexShaderConstantF(CBvLayerQuad, ShaderConstantRect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height), 1); SetShaderTransformAndOpacity(); mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER, GetMaskLayer(), GetTransform().CanDraw2D()); device()->SetTexture(0, renderTexture); device()->SetScissorRect(&containerD3D9ClipRect); device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); } else { device()->SetScissorRect(&containerD3D9ClipRect); } }
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 gfx::Matrix4x4& transform3D = aContainer->GetEffectiveTransform(); gfx::Matrix 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) && !ThebesMatrix(transform).HasNonIntegerTranslation()) { surfaceCopyNeeded = gfxPlatform::ComponentAlphaEnabled(); sourcePoint.x += transform._31; sourcePoint.y += transform._32; 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); if (layerToRender->GetClearFB()) { // Clear layer's visible rect on FrameBuffer with transparent pixels gfx::Rect aRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height); compositor->clearFBRect(&aRect); layerToRender->SetClearFB(false); } } else { layerToRender->RenderLayer(clipRect); } if (gfxPlatform::GetPrefLayersScrollGraph()) { DrawVelGraph(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()); WriteSnapshotToDumpFile(aContainer, surf); } #endif compositor->SetRenderTarget(previousTarget); EffectChain effectChain; LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(aContainer->GetMaskLayer(), effectChain, !aContainer->GetTransform().CanDraw2D()); 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 = 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, aContainer->GetEffectiveTransform()); } }