|
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 "nsAutoPtr.h" // for nsRefPtr |
|
14 #include "nsCOMPtr.h" // for already_AddRefed |
|
15 #include "nsISupportsImpl.h" // for Layer::AddRef, etc |
|
16 #include "nsPoint.h" // for nsIntPoint |
|
17 #include "nsRect.h" // for nsIntRect |
|
18 #include "nsRegion.h" // for nsIntRegion |
|
19 |
|
20 using namespace mozilla::gfx; |
|
21 |
|
22 namespace mozilla { |
|
23 namespace layers { |
|
24 |
|
25 BasicContainerLayer::~BasicContainerLayer() |
|
26 { |
|
27 while (mFirstChild) { |
|
28 ContainerLayer::RemoveChild(mFirstChild); |
|
29 } |
|
30 |
|
31 MOZ_COUNT_DTOR(BasicContainerLayer); |
|
32 } |
|
33 |
|
34 void |
|
35 BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) |
|
36 { |
|
37 // We push groups for container layers if we need to, which always |
|
38 // are aligned in device space, so it doesn't really matter how we snap |
|
39 // containers. |
|
40 Matrix residual; |
|
41 Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface; |
|
42 idealTransform.ProjectTo2D(); |
|
43 |
|
44 if (!idealTransform.CanDraw2D()) { |
|
45 mEffectiveTransform = idealTransform; |
|
46 ComputeEffectiveTransformsForChildren(Matrix4x4()); |
|
47 ComputeEffectiveTransformForMaskLayer(Matrix4x4()); |
|
48 mUseIntermediateSurface = true; |
|
49 return; |
|
50 } |
|
51 |
|
52 mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual); |
|
53 // We always pass the ideal matrix down to our children, so there is no |
|
54 // need to apply any compensation using the residual from SnapTransformTranslation. |
|
55 ComputeEffectiveTransformsForChildren(idealTransform); |
|
56 |
|
57 ComputeEffectiveTransformForMaskLayer(aTransformToSurface); |
|
58 |
|
59 Layer* child = GetFirstChild(); |
|
60 bool hasSingleBlendingChild = false; |
|
61 if (!HasMultipleChildren() && child) { |
|
62 hasSingleBlendingChild = child->GetMixBlendMode() != CompositionOp::OP_OVER; |
|
63 } |
|
64 |
|
65 /* If we have a single childand it is not blending,, it can just inherit our opacity, |
|
66 * otherwise we need a PushGroup and we need to mark ourselves as using |
|
67 * an intermediate surface so our children don't inherit our opacity |
|
68 * via GetEffectiveOpacity. |
|
69 * Having a mask layer always forces our own push group |
|
70 * Having a blend mode also always forces our own push group |
|
71 */ |
|
72 mUseIntermediateSurface = |
|
73 GetMaskLayer() || |
|
74 GetForceIsolatedGroup() || |
|
75 (GetMixBlendMode() != CompositionOp::OP_OVER && HasMultipleChildren()) || |
|
76 (GetEffectiveOpacity() != 1.0 && (HasMultipleChildren() || hasSingleBlendingChild)); |
|
77 } |
|
78 |
|
79 bool |
|
80 BasicContainerLayer::ChildrenPartitionVisibleRegion(const nsIntRect& aInRect) |
|
81 { |
|
82 Matrix transform; |
|
83 if (!GetEffectiveTransform().CanDraw2D(&transform) || |
|
84 ThebesMatrix(transform).HasNonIntegerTranslation()) |
|
85 return false; |
|
86 |
|
87 nsIntPoint offset(int32_t(transform._31), int32_t(transform._32)); |
|
88 nsIntRect rect = aInRect.Intersect(GetEffectiveVisibleRegion().GetBounds() + offset); |
|
89 nsIntRegion covered; |
|
90 |
|
91 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) { |
|
92 if (ToData(l)->IsHidden()) |
|
93 continue; |
|
94 |
|
95 Matrix childTransform; |
|
96 if (!l->GetEffectiveTransform().CanDraw2D(&childTransform) || |
|
97 ThebesMatrix(childTransform).HasNonIntegerTranslation() || |
|
98 l->GetEffectiveOpacity() != 1.0) |
|
99 return false; |
|
100 nsIntRegion childRegion = l->GetEffectiveVisibleRegion(); |
|
101 childRegion.MoveBy(int32_t(childTransform._31), int32_t(childTransform._32)); |
|
102 childRegion.And(childRegion, rect); |
|
103 if (l->GetClipRect()) { |
|
104 childRegion.And(childRegion, *l->GetClipRect() + offset); |
|
105 } |
|
106 nsIntRegion intersection; |
|
107 intersection.And(covered, childRegion); |
|
108 if (!intersection.IsEmpty()) |
|
109 return false; |
|
110 covered.Or(covered, childRegion); |
|
111 } |
|
112 |
|
113 return covered.Contains(rect); |
|
114 } |
|
115 |
|
116 void |
|
117 BasicContainerLayer::Validate(LayerManager::DrawThebesLayerCallback aCallback, |
|
118 void* aCallbackData) |
|
119 { |
|
120 for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) { |
|
121 BasicImplData* data = ToData(l); |
|
122 data->Validate(aCallback, aCallbackData); |
|
123 if (l->GetMaskLayer()) { |
|
124 data = ToData(l->GetMaskLayer()); |
|
125 data->Validate(aCallback, aCallbackData); |
|
126 } |
|
127 } |
|
128 } |
|
129 |
|
130 already_AddRefed<ContainerLayer> |
|
131 BasicLayerManager::CreateContainerLayer() |
|
132 { |
|
133 NS_ASSERTION(InConstruction(), "Only allowed in construction phase"); |
|
134 nsRefPtr<ContainerLayer> layer = new BasicContainerLayer(this); |
|
135 return layer.forget(); |
|
136 } |
|
137 |
|
138 } |
|
139 } |