diff -r 000000000000 -r 6474c204b198 gfx/layers/basic/BasicContainerLayer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/layers/basic/BasicContainerLayer.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 2; 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 "BasicContainerLayer.h" +#include // for int32_t +#include "BasicLayersImpl.h" // for ToData +#include "basic/BasicImplData.h" // for BasicImplData +#include "basic/BasicLayers.h" // for BasicLayerManager +#include "mozilla/gfx/BaseRect.h" // for BaseRect +#include "mozilla/mozalloc.h" // for operator new +#include "nsAutoPtr.h" // for nsRefPtr +#include "nsCOMPtr.h" // for already_AddRefed +#include "nsISupportsImpl.h" // for Layer::AddRef, etc +#include "nsPoint.h" // for nsIntPoint +#include "nsRect.h" // for nsIntRect +#include "nsRegion.h" // for nsIntRegion + +using namespace mozilla::gfx; + +namespace mozilla { +namespace layers { + +BasicContainerLayer::~BasicContainerLayer() +{ + while (mFirstChild) { + ContainerLayer::RemoveChild(mFirstChild); + } + + MOZ_COUNT_DTOR(BasicContainerLayer); +} + +void +BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) +{ + // We push groups for container layers if we need to, which always + // are aligned in device space, so it doesn't really matter how we snap + // containers. + Matrix residual; + Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface; + idealTransform.ProjectTo2D(); + + if (!idealTransform.CanDraw2D()) { + mEffectiveTransform = idealTransform; + ComputeEffectiveTransformsForChildren(Matrix4x4()); + ComputeEffectiveTransformForMaskLayer(Matrix4x4()); + mUseIntermediateSurface = true; + return; + } + + mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual); + // We always pass the ideal matrix down to our children, so there is no + // need to apply any compensation using the residual from SnapTransformTranslation. + ComputeEffectiveTransformsForChildren(idealTransform); + + ComputeEffectiveTransformForMaskLayer(aTransformToSurface); + + Layer* child = GetFirstChild(); + bool hasSingleBlendingChild = false; + if (!HasMultipleChildren() && child) { + hasSingleBlendingChild = child->GetMixBlendMode() != CompositionOp::OP_OVER; + } + + /* If we have a single childand it is not blending,, it can just inherit our opacity, + * otherwise we need a PushGroup and we need to mark ourselves as using + * an intermediate surface so our children don't inherit our opacity + * via GetEffectiveOpacity. + * Having a mask layer always forces our own push group + * Having a blend mode also always forces our own push group + */ + mUseIntermediateSurface = + GetMaskLayer() || + GetForceIsolatedGroup() || + (GetMixBlendMode() != CompositionOp::OP_OVER && HasMultipleChildren()) || + (GetEffectiveOpacity() != 1.0 && (HasMultipleChildren() || hasSingleBlendingChild)); +} + +bool +BasicContainerLayer::ChildrenPartitionVisibleRegion(const nsIntRect& aInRect) +{ + Matrix transform; + if (!GetEffectiveTransform().CanDraw2D(&transform) || + ThebesMatrix(transform).HasNonIntegerTranslation()) + return false; + + nsIntPoint offset(int32_t(transform._31), int32_t(transform._32)); + nsIntRect 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, *l->GetClipRect() + offset); + } + nsIntRegion intersection; + intersection.And(covered, childRegion); + if (!intersection.IsEmpty()) + return false; + covered.Or(covered, childRegion); + } + + return covered.Contains(rect); +} + +void +BasicContainerLayer::Validate(LayerManager::DrawThebesLayerCallback aCallback, + void* aCallbackData) +{ + for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) { + BasicImplData* data = ToData(l); + data->Validate(aCallback, aCallbackData); + if (l->GetMaskLayer()) { + data = ToData(l->GetMaskLayer()); + data->Validate(aCallback, aCallbackData); + } + } +} + +already_AddRefed +BasicLayerManager::CreateContainerLayer() +{ + NS_ASSERTION(InConstruction(), "Only allowed in construction phase"); + nsRefPtr layer = new BasicContainerLayer(this); + return layer.forget(); +} + +} +}