Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "BasicContainerLayer.h"
7 : #include <sys/types.h> // for int32_t
8 : #include "BasicLayersImpl.h" // for ToData
9 : #include "basic/BasicImplData.h" // for BasicImplData
10 : #include "basic/BasicLayers.h" // for BasicLayerManager
11 : #include "mozilla/gfx/BaseRect.h" // for BaseRect
12 : #include "mozilla/mozalloc.h" // for operator new
13 : #include "nsCOMPtr.h" // for already_AddRefed
14 : #include "nsISupportsImpl.h" // for Layer::AddRef, etc
15 : #include "nsPoint.h" // for nsIntPoint
16 : #include "nsRegion.h" // for nsIntRegion
17 : #include "ReadbackProcessor.h"
18 :
19 : using namespace mozilla::gfx;
20 :
21 : namespace mozilla {
22 : namespace layers {
23 :
24 144 : BasicContainerLayer::~BasicContainerLayer()
25 : {
26 48 : ContainerLayer::RemoveAllChildren();
27 48 : MOZ_COUNT_DTOR(BasicContainerLayer);
28 144 : }
29 :
30 : void
31 217 : BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface)
32 : {
33 : // We push groups for container layers if we need to, which always
34 : // are aligned in device space, so it doesn't really matter how we snap
35 : // containers.
36 217 : Matrix residual;
37 217 : Matrix4x4 transformToSurface = aTransformToSurface;
38 217 : bool participate3DCtx = Extend3DContext() || Is3DContextLeaf();
39 434 : if (!participate3DCtx &&
40 217 : GetContentFlags() & CONTENT_BACKFACE_HIDDEN) {
41 : // For backface-hidden layers
42 0 : transformToSurface.ProjectTo2D();
43 : }
44 217 : Matrix4x4 idealTransform = GetLocalTransform() * transformToSurface;
45 434 : if (!participate3DCtx &&
46 217 : !(GetContentFlags() & CONTENT_BACKFACE_HIDDEN)) {
47 : // For non-backface-hidden layers,
48 : // 3D components are required to handle CONTENT_BACKFACE_HIDDEN.
49 217 : idealTransform.ProjectTo2D();
50 : }
51 :
52 217 : if (!idealTransform.CanDraw2D()) {
53 0 : if (!Extend3DContext()) {
54 0 : mEffectiveTransform = idealTransform;
55 0 : ComputeEffectiveTransformsForChildren(Matrix4x4());
56 0 : ComputeEffectiveTransformForMaskLayers(Matrix4x4());
57 0 : mUseIntermediateSurface = true;
58 0 : return;
59 : }
60 :
61 0 : mEffectiveTransform = idealTransform;
62 0 : ComputeEffectiveTransformsForChildren(idealTransform);
63 0 : ComputeEffectiveTransformForMaskLayers(idealTransform);
64 0 : mUseIntermediateSurface = false;
65 0 : return;
66 : }
67 :
68 : // With 2D transform or extended 3D context.
69 :
70 217 : Layer* child = GetFirstChild();
71 217 : bool hasSingleBlendingChild = false;
72 217 : if (!HasMultipleChildren() && child) {
73 214 : hasSingleBlendingChild = child->GetMixBlendMode() != CompositionOp::OP_OVER;
74 : }
75 :
76 : /* If we have a single childand it is not blending,, it can just inherit our opacity,
77 : * otherwise we need a PushGroup and we need to mark ourselves as using
78 : * an intermediate surface so our children don't inherit our opacity
79 : * via GetEffectiveOpacity.
80 : * Having a mask layer always forces our own push group
81 : * Having a blend mode also always forces our own push group
82 : */
83 217 : mUseIntermediateSurface =
84 434 : GetMaskLayer() ||
85 434 : GetForceIsolatedGroup() ||
86 651 : (GetMixBlendMode() != CompositionOp::OP_OVER && HasMultipleChildren()) ||
87 378 : (GetEffectiveOpacity() != 1.0 && ((HasMultipleChildren() && !Extend3DContext()) || hasSingleBlendingChild));
88 :
89 : mEffectiveTransform =
90 217 : !mUseIntermediateSurface ?
91 : idealTransform :
92 0 : (!(GetContentFlags() & CONTENT_BACKFACE_HIDDEN) ?
93 217 : SnapTransformTranslation(idealTransform, &residual) :
94 434 : SnapTransformTranslation3D(idealTransform, &residual));
95 : Matrix4x4 childTransformToSurface =
96 217 : (!mUseIntermediateSurface ||
97 217 : (mUseIntermediateSurface && !Extend3DContext() /* 2D */)) ?
98 217 : idealTransform : Matrix4x4::From2D(residual);
99 217 : ComputeEffectiveTransformsForChildren(childTransformToSurface);
100 :
101 217 : ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
102 : }
103 :
104 : bool
105 0 : BasicContainerLayer::ChildrenPartitionVisibleRegion(const gfx::IntRect& aInRect)
106 : {
107 0 : Matrix transform;
108 0 : if (!GetEffectiveTransform().CanDraw2D(&transform) ||
109 0 : ThebesMatrix(transform).HasNonIntegerTranslation())
110 0 : return false;
111 :
112 0 : nsIntPoint offset(int32_t(transform._31), int32_t(transform._32));
113 0 : gfx::IntRect rect = aInRect.Intersect(GetLocalVisibleRegion().ToUnknownRegion().GetBounds() + offset);
114 0 : nsIntRegion covered;
115 :
116 0 : for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
117 0 : if (ToData(l)->IsHidden())
118 0 : continue;
119 :
120 0 : Matrix childTransform;
121 0 : if (!l->GetEffectiveTransform().CanDraw2D(&childTransform) ||
122 0 : ThebesMatrix(childTransform).HasNonIntegerTranslation() ||
123 0 : l->GetEffectiveOpacity() != 1.0)
124 0 : return false;
125 0 : nsIntRegion childRegion = l->GetLocalVisibleRegion().ToUnknownRegion();
126 0 : childRegion.MoveBy(int32_t(childTransform._31), int32_t(childTransform._32));
127 0 : childRegion.And(childRegion, rect);
128 0 : if (l->GetClipRect()) {
129 0 : childRegion.And(childRegion, l->GetClipRect()->ToUnknownRect() + offset);
130 : }
131 0 : nsIntRegion intersection;
132 0 : intersection.And(covered, childRegion);
133 0 : if (!intersection.IsEmpty())
134 0 : return false;
135 0 : covered.Or(covered, childRegion);
136 : }
137 :
138 0 : return covered.Contains(rect);
139 : }
140 :
141 : void
142 72 : BasicContainerLayer::Validate(LayerManager::DrawPaintedLayerCallback aCallback,
143 : void* aCallbackData,
144 : ReadbackProcessor* aReadback)
145 : {
146 144 : ReadbackProcessor readback;
147 72 : if (BasicManager()->IsRetained()) {
148 0 : readback.BuildUpdates(this);
149 : }
150 168 : for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
151 96 : BasicImplData* data = ToData(l);
152 96 : data->Validate(aCallback, aCallbackData, &readback);
153 96 : if (l->GetMaskLayer()) {
154 0 : data = ToData(l->GetMaskLayer());
155 0 : data->Validate(aCallback, aCallbackData, nullptr);
156 : }
157 : }
158 72 : }
159 :
160 : already_AddRefed<ContainerLayer>
161 54 : BasicLayerManager::CreateContainerLayer()
162 : {
163 54 : NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
164 108 : RefPtr<ContainerLayer> layer = new BasicContainerLayer(this);
165 108 : return layer.forget();
166 : }
167 :
168 : } // namespace layers
169 : } // namespace mozilla
|