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 "cc/layers/layer.h"
8 #include "cc/layers/layer_lists.h"
9 #include "chrome/browser/android/compositor/layer/thumbnail_layer.h"
10 #include "chrome/browser/android/compositor/tab_content_manager.h"
11 #include "ui/gfx/geometry/size.h"
17 scoped_refptr
<ContentLayer
> ContentLayer::Create(
18 TabContentManager
* tab_content_manager
) {
19 return make_scoped_refptr(new ContentLayer(tab_content_manager
));
22 static void SetOpacityOnLeaf(scoped_refptr
<cc::Layer
> layer
, float alpha
) {
23 const cc::LayerList
& children
= layer
->children();
24 if (children
.size() > 0) {
25 layer
->SetOpacity(1.0f
);
26 for (uint i
= 0; i
< children
.size(); ++i
)
27 SetOpacityOnLeaf(children
[i
], alpha
);
29 layer
->SetOpacity(alpha
);
33 static bool DoesLeafDrawContents(scoped_refptr
<cc::Layer
> layer
) {
37 // TODO: Remove the need for this logic. We can't really guess from
38 // an opaque layer type whether it has valid live contents, or for example
39 // just a background color placeholder. Need to get this from somewhere else
40 // like ContentViewCore or RWHV.
41 if (layer
->DrawsContent() && !layer
->hide_layer_and_subtree() &&
42 !layer
->background_color()) {
46 const cc::LayerList
& children
= layer
->children();
47 for (unsigned i
= 0; i
< children
.size(); i
++) {
48 if (DoesLeafDrawContents(children
[i
]))
54 static gfx::Size
GetLeafBounds(scoped_refptr
<cc::Layer
> layer
) {
55 if (layer
->children().size() > 0)
56 return GetLeafBounds(layer
->children()[0]);
57 return layer
->bounds();
60 void ContentLayer::SetProperties(int id
,
61 bool can_use_live_layer
,
62 bool can_use_ntp_fallback
,
63 float static_to_view_blend
,
64 bool should_override_content_alpha
,
65 float content_alpha_override
,
67 const gfx::Rect
& desired_bounds
,
68 const gfx::Size
& content_size
) {
69 scoped_refptr
<cc::Layer
> content_layer
=
70 tab_content_manager_
->GetLiveLayer(id
);
71 ClipContentLayer(content_layer
, desired_bounds
, content_size
);
72 bool content_layer_draws
= DoesLeafDrawContents(content_layer
);
74 scoped_refptr
<ThumbnailLayer
> static_layer
=
75 tab_content_manager_
->GetStaticLayer(id
, !content_layer_draws
);
77 ClipStaticLayer(static_layer
, desired_bounds
);
79 // Reset the attachment logic if the number of children doesn't match the
80 // boolean flags. At some point while a tab is in the background one or more
81 // layers may be removed from this tree.
82 // Note that this needs to be checked *after* we access TabContentManager, as
83 // that class might remove layers internally, messing up our own tracking.
84 unsigned int expected_layers
= 0;
85 expected_layers
+= content_attached_
? 1 : 0;
86 expected_layers
+= static_attached_
? 1 : 0;
87 if (layer_
->children().size() != expected_layers
) {
88 content_attached_
= false;
89 static_attached_
= false;
90 const cc::LayerList
& layer_children
= layer_
->children();
91 for (unsigned i
= 0; i
< layer_children
.size(); i
++)
92 layer_children
[i
]->RemoveFromParent();
95 gfx::Size
content_bounds(0, 0);
96 if (!content_layer
.get() || !can_use_live_layer
) {
97 SetContentLayer(nullptr);
98 SetStaticLayer(static_layer
);
99 if (static_layer
.get())
100 content_bounds
= static_layer
->layer()->bounds();
102 content_bounds
.set_width(content_size
.width());
104 SetContentLayer(content_layer
);
105 content_bounds
= content_layer
->bounds();
107 if (static_to_view_blend
== 0.0f
&& !content_layer_draws
)
108 static_to_view_blend
= 1.0f
;
110 if (static_to_view_blend
!= 0.0f
&& static_layer
.get()) {
111 static_layer
->layer()->SetOpacity(static_to_view_blend
);
112 SetStaticLayer(static_layer
);
113 if (content_bounds
.GetArea() == 0 || !content_layer_draws
)
114 content_bounds
= static_layer
->layer()->bounds();
116 SetStaticLayer(nullptr);
120 if (should_override_content_alpha
) {
121 for (unsigned int i
= 0; i
< layer_
->children().size(); ++i
)
122 SetOpacityOnLeaf(layer_
->children()[i
], content_alpha_override
);
125 if (!content_layer_draws
&& !static_attached_
)
126 content_bounds
= gfx::Size(0, 0);
128 layer_
->SetBounds(content_bounds
);
130 // Only worry about saturation on the static layer
131 if (static_layer
.get()) {
132 if (saturation
!= saturation_
) {
133 saturation_
= saturation
;
134 cc::FilterOperations filters
;
135 if (saturation_
< 1.0f
)
136 filters
.Append(cc::FilterOperation::CreateSaturateFilter(saturation_
));
137 static_layer
->layer()->SetFilters(filters
);
142 gfx::Size
ContentLayer::GetContentSize() {
143 if (content_attached_
&& DoesLeafDrawContents(layer()->children()[0]))
144 return layer_
->children()[0]->bounds();
145 return gfx::Size(0, 0);
148 scoped_refptr
<cc::Layer
> ContentLayer::layer() {
152 ContentLayer::ContentLayer(TabContentManager
* tab_content_manager
)
153 : layer_(cc::Layer::Create()),
154 content_attached_(false),
155 static_attached_(false),
157 tab_content_manager_(tab_content_manager
) {
160 ContentLayer::~ContentLayer() {
163 void ContentLayer::SetContentLayer(scoped_refptr
<cc::Layer
> layer
) {
165 // content_attached_, expect at least 1 child.
166 DCHECK(!content_attached_
|| layer_
->children().size() > 0);
169 if (content_attached_
)
170 layer_
->child_at(0)->RemoveFromParent();
171 content_attached_
= false;
175 bool new_layer
= false;
176 if (content_attached_
&& layer_
->child_at(0)->id() != layer
->id()) {
177 layer_
->ReplaceChild(layer_
->child_at(0), layer
);
179 } else if (!content_attached_
) {
180 layer_
->InsertChild(layer
, 0);
184 // If this is a new layer, reset it's opacity.
186 SetOpacityOnLeaf(layer
, 1.0f
);
188 content_attached_
= true;
191 void ContentLayer::SetStaticLayer(
192 scoped_refptr
<ThumbnailLayer
> new_static_layer
) {
193 // Make sure child access will be valid.
194 // !content_attached_ AND !static_attached_, expect 0 children.
195 // content_attached_ XOR static_attached_, expect 1 child.
196 // content_attached_ AND static_attached_, expect 2 children.
197 DCHECK((!content_attached_
&& !static_attached_
) ||
198 (content_attached_
!= static_attached_
&&
199 layer_
->children().size() >= 1) ||
200 (content_attached_
&& static_attached_
&&
201 layer_
->children().size() >= 2));
203 if (!new_static_layer
.get()) {
204 if (static_layer_
.get()) {
205 static_layer_
->layer()->RemoveFromParent();
206 static_layer_
= nullptr;
208 static_attached_
= false;
211 static_layer_
= new_static_layer
;
212 static_layer_
->AddSelfToParentOrReplaceAt(layer_
, content_attached_
? 1 : 0);
214 static_layer_
->layer()->SetIsDrawable(true);
215 static_attached_
= true;
218 void ContentLayer::ClipContentLayer(scoped_refptr
<cc::Layer
> content_layer
,
220 gfx::Size content_size
) {
221 if (!content_layer
.get())
224 gfx::Size
bounds(GetLeafBounds(content_layer
));
225 content_layer
->SetMasksToBounds(true);
226 gfx::Size
clamped_bounds(bounds
);
227 clamped_bounds
.SetToMin(clipping
.size());
228 content_layer
->SetBounds(clamped_bounds
);
230 if (content_layer
->children().size() > 0) {
232 std::min(content_size
.width() - bounds
.width() - clipping
.x(), 0),
233 std::min(content_size
.height() - bounds
.height() - clipping
.y(), 0));
234 content_layer
->children()[0]->SetPosition(offset
);
238 void ContentLayer::ClipStaticLayer(scoped_refptr
<ThumbnailLayer
> static_layer
,
239 gfx::Rect clipping
) {
240 if (!static_layer
.get())
242 static_layer
->Clip(clipping
);
245 } // namespace android
246 } // namespace chrome