michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "BasicContainerLayer.h" michael@0: #include // for int32_t michael@0: #include "BasicLayersImpl.h" // for ToData michael@0: #include "basic/BasicImplData.h" // for BasicImplData michael@0: #include "basic/BasicLayers.h" // for BasicLayerManager michael@0: #include "mozilla/gfx/BaseRect.h" // for BaseRect michael@0: #include "mozilla/mozalloc.h" // for operator new michael@0: #include "nsAutoPtr.h" // for nsRefPtr michael@0: #include "nsCOMPtr.h" // for already_AddRefed michael@0: #include "nsISupportsImpl.h" // for Layer::AddRef, etc michael@0: #include "nsPoint.h" // for nsIntPoint michael@0: #include "nsRect.h" // for nsIntRect michael@0: #include "nsRegion.h" // for nsIntRegion michael@0: michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: BasicContainerLayer::~BasicContainerLayer() michael@0: { michael@0: while (mFirstChild) { michael@0: ContainerLayer::RemoveChild(mFirstChild); michael@0: } michael@0: michael@0: MOZ_COUNT_DTOR(BasicContainerLayer); michael@0: } michael@0: michael@0: void michael@0: BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) michael@0: { michael@0: // We push groups for container layers if we need to, which always michael@0: // are aligned in device space, so it doesn't really matter how we snap michael@0: // containers. michael@0: Matrix residual; michael@0: Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface; michael@0: idealTransform.ProjectTo2D(); michael@0: michael@0: if (!idealTransform.CanDraw2D()) { michael@0: mEffectiveTransform = idealTransform; michael@0: ComputeEffectiveTransformsForChildren(Matrix4x4()); michael@0: ComputeEffectiveTransformForMaskLayer(Matrix4x4()); michael@0: mUseIntermediateSurface = true; michael@0: return; michael@0: } michael@0: michael@0: mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual); michael@0: // We always pass the ideal matrix down to our children, so there is no michael@0: // need to apply any compensation using the residual from SnapTransformTranslation. michael@0: ComputeEffectiveTransformsForChildren(idealTransform); michael@0: michael@0: ComputeEffectiveTransformForMaskLayer(aTransformToSurface); michael@0: michael@0: Layer* child = GetFirstChild(); michael@0: bool hasSingleBlendingChild = false; michael@0: if (!HasMultipleChildren() && child) { michael@0: hasSingleBlendingChild = child->GetMixBlendMode() != CompositionOp::OP_OVER; michael@0: } michael@0: michael@0: /* If we have a single childand it is not blending,, it can just inherit our opacity, michael@0: * otherwise we need a PushGroup and we need to mark ourselves as using michael@0: * an intermediate surface so our children don't inherit our opacity michael@0: * via GetEffectiveOpacity. michael@0: * Having a mask layer always forces our own push group michael@0: * Having a blend mode also always forces our own push group michael@0: */ michael@0: mUseIntermediateSurface = michael@0: GetMaskLayer() || michael@0: GetForceIsolatedGroup() || michael@0: (GetMixBlendMode() != CompositionOp::OP_OVER && HasMultipleChildren()) || michael@0: (GetEffectiveOpacity() != 1.0 && (HasMultipleChildren() || hasSingleBlendingChild)); michael@0: } michael@0: michael@0: bool michael@0: BasicContainerLayer::ChildrenPartitionVisibleRegion(const nsIntRect& aInRect) michael@0: { michael@0: Matrix transform; michael@0: if (!GetEffectiveTransform().CanDraw2D(&transform) || michael@0: ThebesMatrix(transform).HasNonIntegerTranslation()) michael@0: return false; michael@0: michael@0: nsIntPoint offset(int32_t(transform._31), int32_t(transform._32)); michael@0: nsIntRect rect = aInRect.Intersect(GetEffectiveVisibleRegion().GetBounds() + offset); michael@0: nsIntRegion covered; michael@0: michael@0: for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) { michael@0: if (ToData(l)->IsHidden()) michael@0: continue; michael@0: michael@0: Matrix childTransform; michael@0: if (!l->GetEffectiveTransform().CanDraw2D(&childTransform) || michael@0: ThebesMatrix(childTransform).HasNonIntegerTranslation() || michael@0: l->GetEffectiveOpacity() != 1.0) michael@0: return false; michael@0: nsIntRegion childRegion = l->GetEffectiveVisibleRegion(); michael@0: childRegion.MoveBy(int32_t(childTransform._31), int32_t(childTransform._32)); michael@0: childRegion.And(childRegion, rect); michael@0: if (l->GetClipRect()) { michael@0: childRegion.And(childRegion, *l->GetClipRect() + offset); michael@0: } michael@0: nsIntRegion intersection; michael@0: intersection.And(covered, childRegion); michael@0: if (!intersection.IsEmpty()) michael@0: return false; michael@0: covered.Or(covered, childRegion); michael@0: } michael@0: michael@0: return covered.Contains(rect); michael@0: } michael@0: michael@0: void michael@0: BasicContainerLayer::Validate(LayerManager::DrawThebesLayerCallback aCallback, michael@0: void* aCallbackData) michael@0: { michael@0: for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) { michael@0: BasicImplData* data = ToData(l); michael@0: data->Validate(aCallback, aCallbackData); michael@0: if (l->GetMaskLayer()) { michael@0: data = ToData(l->GetMaskLayer()); michael@0: data->Validate(aCallback, aCallbackData); michael@0: } michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: BasicLayerManager::CreateContainerLayer() michael@0: { michael@0: NS_ASSERTION(InConstruction(), "Only allowed in construction phase"); michael@0: nsRefPtr layer = new BasicContainerLayer(this); michael@0: return layer.forget(); michael@0: } michael@0: michael@0: } michael@0: }