1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/android/compositor/layer/content_layer.h"
7 #include "base/lazy_instance.h"
8 #include "cc/layers/layer.h"
9 #include "cc/layers/layer_lists.h"
10 #include "chrome/browser/android/compositor/layer/thumbnail_layer.h"
11 #include "chrome/browser/android/compositor/tab_content_manager.h"
12 #include "content/public/browser/android/compositor.h"
13 #include "ui/gfx/geometry/size.h"
19 scoped_refptr
<ContentLayer
> ContentLayer::Create(
20 TabContentManager
* tab_content_manager
) {
21 return make_scoped_refptr(new ContentLayer(tab_content_manager
));
24 static void SetOpacityOnLeaf(scoped_refptr
<cc::Layer
> layer
, float alpha
) {
25 const cc::LayerList
& children
= layer
->children();
26 if (children
.size() > 0) {
27 layer
->SetOpacity(1.0f
);
28 for (uint i
= 0; i
< children
.size(); ++i
)
29 SetOpacityOnLeaf(children
[i
], alpha
);
31 layer
->SetOpacity(alpha
);
35 static bool DoesLeafDrawContents(scoped_refptr
<cc::Layer
> layer
) {
39 // TODO: Remove the need for this logic. We can't really guess from
40 // an opaque layer type whether it has valid live contents, or for example
41 // just a background color placeholder. Need to get this from somewhere else
42 // like ContentViewCore or RWHV.
43 if (layer
->DrawsContent() && !layer
->hide_layer_and_subtree() &&
44 !layer
->background_color()) {
48 const cc::LayerList
& children
= layer
->children();
49 for (unsigned i
= 0; i
< children
.size(); i
++) {
50 if (DoesLeafDrawContents(children
[i
]))
56 static gfx::Size
GetLeafBounds(scoped_refptr
<cc::Layer
> layer
) {
57 if (layer
->children().size() > 0)
58 return GetLeafBounds(layer
->children()[0]);
59 return layer
->bounds();
62 void ContentLayer::SetProperties(int id
,
63 bool can_use_live_layer
,
64 bool can_use_ntp_fallback
,
65 float static_to_view_blend
,
66 bool should_override_content_alpha
,
67 float content_alpha_override
,
70 const gfx::Rect
& desired_bounds
,
71 const gfx::Size
& content_size
) {
72 scoped_refptr
<cc::Layer
> content_layer
=
73 tab_content_manager_
->GetLiveLayer(id
);
74 ClipContentLayer(content_layer
, desired_bounds
, content_size
);
75 bool content_layer_draws
= DoesLeafDrawContents(content_layer
);
77 scoped_refptr
<ThumbnailLayer
> static_layer
=
78 tab_content_manager_
->GetStaticLayer(
79 id
, !(can_use_live_layer
&& content_layer_draws
));
81 ClipStaticLayer(static_layer
, desired_bounds
);
83 // Reset the attachment logic if the number of children doesn't match the
84 // boolean flags. At some point while a tab is in the background one or more
85 // layers may be removed from this tree.
86 // Note that this needs to be checked *after* we access TabContentManager, as
87 // that class might remove layers internally, messing up our own tracking.
88 unsigned int expected_layers
= 0;
89 expected_layers
+= content_attached_
? 1 : 0;
90 expected_layers
+= static_attached_
? 1 : 0;
91 if (layer_
->children().size() != expected_layers
) {
92 content_attached_
= false;
93 static_attached_
= false;
94 const cc::LayerList
& layer_children
= layer_
->children();
95 for (unsigned i
= 0; i
< layer_children
.size(); i
++)
96 layer_children
[i
]->RemoveFromParent();
99 gfx::Size
content_bounds(0, 0);
100 if (!content_layer
.get() || !can_use_live_layer
) {
101 SetContentLayer(nullptr);
102 SetStaticLayer(static_layer
);
103 if (static_layer
.get())
104 content_bounds
= static_layer
->layer()->bounds();
106 content_bounds
.set_width(content_size
.width());
108 SetContentLayer(content_layer
);
109 content_bounds
= content_layer
->bounds();
111 if (static_to_view_blend
== 0.0f
&& !content_layer_draws
)
112 static_to_view_blend
= 1.0f
;
114 if (static_to_view_blend
!= 0.0f
&& static_layer
.get()) {
115 static_layer
->layer()->SetOpacity(static_to_view_blend
);
116 SetStaticLayer(static_layer
);
117 if (content_bounds
.GetArea() == 0 || !content_layer_draws
)
118 content_bounds
= static_layer
->layer()->bounds();
120 SetStaticLayer(nullptr);
124 if (should_override_content_alpha
) {
125 for (unsigned int i
= 0; i
< layer_
->children().size(); ++i
)
126 SetOpacityOnLeaf(layer_
->children()[i
], content_alpha_override
);
129 if (!content_layer_draws
&& !static_attached_
)
130 content_bounds
= gfx::Size(0, 0);
132 layer_
->SetBounds(content_bounds
);
134 // Only worry about saturation on the static layer.
135 if (static_layer
.get()) {
136 static_filter_operations_
.Clear();
137 if (saturation
< 1.0f
) {
138 static_filter_operations_
.Append(
139 cc::FilterOperation::CreateSaturateFilter(saturation
));
141 static_layer
->layer()->SetFilters(static_filter_operations_
);
144 // Only worry about brightness on the content layer.
145 if (content_layer
.get()) {
146 content_filter_operations_
.Clear();
147 if (brightness
< 1.0f
) {
148 content_filter_operations_
.Append(
149 cc::FilterOperation::CreateBrightnessFilter(brightness
));
151 content_layer
->SetFilters(content_filter_operations_
);
155 gfx::Size
ContentLayer::GetContentSize() {
156 if (content_attached_
&& DoesLeafDrawContents(layer()->children()[0]))
157 return layer_
->children()[0]->bounds();
158 return gfx::Size(0, 0);
161 scoped_refptr
<cc::Layer
> ContentLayer::layer() {
165 ContentLayer::ContentLayer(TabContentManager
* tab_content_manager
)
166 : layer_(cc::Layer::Create(content::Compositor::LayerSettings())),
167 content_attached_(false),
168 static_attached_(false),
169 tab_content_manager_(tab_content_manager
) {
172 ContentLayer::~ContentLayer() {
175 void ContentLayer::SetContentLayer(scoped_refptr
<cc::Layer
> layer
) {
177 // content_attached_, expect at least 1 child.
178 DCHECK(!content_attached_
|| layer_
->children().size() > 0);
181 if (content_attached_
)
182 layer_
->child_at(0)->RemoveFromParent();
183 content_attached_
= false;
187 bool new_layer
= false;
188 if (content_attached_
&& layer_
->child_at(0)->id() != layer
->id()) {
189 layer_
->ReplaceChild(layer_
->child_at(0), layer
);
191 } else if (!content_attached_
) {
192 layer_
->InsertChild(layer
, 0);
196 // If this is a new layer, reset it's opacity.
198 SetOpacityOnLeaf(layer
, 1.0f
);
200 content_attached_
= true;
203 void ContentLayer::SetStaticLayer(
204 scoped_refptr
<ThumbnailLayer
> new_static_layer
) {
205 // Make sure child access will be valid.
206 // !content_attached_ AND !static_attached_, expect 0 children.
207 // content_attached_ XOR static_attached_, expect 1 child.
208 // content_attached_ AND static_attached_, expect 2 children.
209 DCHECK((!content_attached_
&& !static_attached_
) ||
210 (content_attached_
!= static_attached_
&&
211 layer_
->children().size() >= 1) ||
212 (content_attached_
&& static_attached_
&&
213 layer_
->children().size() >= 2));
215 if (!new_static_layer
.get()) {
216 if (static_layer_
.get()) {
217 static_layer_
->layer()->RemoveFromParent();
218 static_layer_
= nullptr;
220 static_attached_
= false;
223 static_layer_
= new_static_layer
;
224 static_layer_
->AddSelfToParentOrReplaceAt(layer_
, content_attached_
? 1 : 0);
225 static_layer_
->layer()->SetIsDrawable(true);
226 static_attached_
= true;
229 void ContentLayer::ClipContentLayer(scoped_refptr
<cc::Layer
> content_layer
,
231 gfx::Size content_size
) {
232 if (!content_layer
.get())
235 gfx::Size
bounds(GetLeafBounds(content_layer
));
236 content_layer
->SetMasksToBounds(true);
237 gfx::Size
clamped_bounds(bounds
);
238 clamped_bounds
.SetToMin(clipping
.size());
239 content_layer
->SetBounds(clamped_bounds
);
241 if (content_layer
->children().size() > 0) {
243 std::min(content_size
.width() - bounds
.width() - clipping
.x(), 0),
244 std::min(content_size
.height() - bounds
.height() - clipping
.y(), 0));
245 content_layer
->children()[0]->SetPosition(offset
);
249 void ContentLayer::ClipStaticLayer(scoped_refptr
<ThumbnailLayer
> static_layer
,
250 gfx::Rect clipping
) {
251 if (!static_layer
.get())
253 static_layer
->Clip(clipping
);
256 } // namespace android
257 } // namespace chrome