Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / android / compositor / layer / tab_layer.cc
blob245a52daa172de1835bf48c74eb226a3cd0de402
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/tab_layer.h"
7 #include "base/i18n/rtl.h"
8 #include "cc/layers/layer.h"
9 #include "cc/layers/layer_lists.h"
10 #include "cc/layers/nine_patch_layer.h"
11 #include "cc/layers/solid_color_layer.h"
12 #include "cc/layers/ui_resource_layer.h"
13 #include "chrome/browser/android/compositor/decoration_title.h"
14 #include "chrome/browser/android/compositor/layer/content_layer.h"
15 #include "chrome/browser/android/compositor/layer/toolbar_layer.h"
16 #include "chrome/browser/android/compositor/layer_title_cache.h"
17 #include "chrome/browser/android/compositor/tab_content_manager.h"
18 #include "content/public/browser/android/compositor.h"
19 #include "ui/android/resources/resource_manager.h"
20 #include "ui/android/resources/ui_resource_android.h"
21 #include "ui/base/l10n/l10n_util_android.h"
22 #include "ui/gfx/geometry/insets_f.h"
23 #include "ui/gfx/geometry/point_f.h"
24 #include "ui/gfx/geometry/rect_f.h"
25 #include "ui/gfx/geometry/safe_integer_conversions.h"
26 #include "ui/gfx/geometry/size.h"
27 #include "ui/gfx/transform.h"
29 namespace chrome {
30 namespace android {
32 // static
33 scoped_refptr<TabLayer> TabLayer::Create(
34 bool incognito,
35 ui::ResourceManager* resource_manager,
36 LayerTitleCache* layer_title_cache,
37 TabContentManager* tab_content_manager) {
38 return make_scoped_refptr(new TabLayer(
39 incognito, resource_manager, layer_title_cache, tab_content_manager));
42 static gfx::Rect ComputePaddingPosition(const gfx::Size& bounds,
43 const gfx::Size& desired_bounds) {
44 gfx::Rect padding_rect;
45 if (bounds.width() == 0 || bounds.height() == 0) {
46 padding_rect.set_size(desired_bounds);
47 } else if (bounds.width() < desired_bounds.width()) {
48 padding_rect.set_x(bounds.width());
49 padding_rect.set_width(desired_bounds.width() - bounds.width());
50 padding_rect.set_height(std::min(bounds.height(), desired_bounds.height()));
51 } else if (bounds.height() < desired_bounds.height()) {
52 padding_rect.set_y(bounds.height());
53 padding_rect.set_width(std::min(bounds.width(), desired_bounds.width()));
54 padding_rect.set_height(desired_bounds.height() - bounds.height());
56 return padding_rect;
59 void TabLayer::SetProperties(int id,
60 bool can_use_live_layer,
61 bool can_use_ntp_fallback,
62 int toolbar_resource_id,
63 int close_button_resource_id,
64 int shadow_resource_id,
65 int contour_resource_id,
66 int back_logo_resource_id,
67 int border_resource_id,
68 int default_background_color,
69 int back_logo_color,
70 bool is_portrait,
71 float x,
72 float y,
73 float width,
74 float height,
75 float shadow_x,
76 float shadow_y,
77 float shadow_width,
78 float shadow_height,
79 float pivot_x,
80 float pivot_y,
81 float rotation_x,
82 float rotation_y,
83 float alpha,
84 float border_alpha,
85 float contour_alpha,
86 float shadow_alpha,
87 float close_alpha,
88 float border_scale,
89 float saturation,
90 float brightness,
91 float close_btn_width,
92 float static_to_view_blend,
93 float content_width,
94 float content_height,
95 float view_width,
96 float view_height,
97 bool show_toolbar,
98 bool anonymize_toolbar,
99 int toolbar_textbox_background_color,
100 float toolbar_alpha,
101 float toolbar_y_offset,
102 float side_border_scale,
103 bool attach_content,
104 bool inset_border) {
105 if (alpha <= 0) {
106 layer_->SetHideLayerAndSubtree(true);
107 return;
110 layer_->SetHideLayerAndSubtree(false);
112 // Grab required resources
113 ui::ResourceManager::Resource* border_resource =
114 resource_manager_->GetResource(ui::ANDROID_RESOURCE_TYPE_STATIC,
115 border_resource_id);
116 ui::ResourceManager::Resource* shadow_resource =
117 resource_manager_->GetResource(ui::ANDROID_RESOURCE_TYPE_STATIC,
118 shadow_resource_id);
119 ui::ResourceManager::Resource* contour_resource =
120 resource_manager_->GetResource(ui::ANDROID_RESOURCE_TYPE_STATIC,
121 contour_resource_id);
122 ui::ResourceManager::Resource* toolbar_resource =
123 resource_manager_->GetResource(ui::ANDROID_RESOURCE_TYPE_DYNAMIC,
124 toolbar_resource_id);
125 ui::ResourceManager::Resource* close_btn_resource =
126 resource_manager_->GetResource(ui::ANDROID_RESOURCE_TYPE_STATIC,
127 close_button_resource_id);
128 ui::ResourceManager::Resource* back_logo_resource = nullptr;
130 DecorationTitle* title_layer = nullptr;
132 //----------------------------------------------------------------------------
133 // Handle Border Scaling (Upscale/Downscale everything until final scaling)
134 //----------------------------------------------------------------------------
135 width /= border_scale;
136 height /= border_scale;
137 shadow_x /= border_scale;
138 shadow_y /= border_scale;
139 shadow_width /= border_scale;
140 shadow_height /= border_scale;
142 //----------------------------------------------------------------------------
143 // Precalculate Helper Values
144 //----------------------------------------------------------------------------
145 const gfx::RectF border_padding(border_resource->padding);
146 const gfx::RectF shadow_padding(shadow_resource->padding);
147 const gfx::RectF contour_padding(contour_resource->padding);
149 // If we're in portrait and we're RTL, the close button is on the left.
150 // Similarly if we're in landscape and we're in LTR, the close button is on
151 // the left.
152 const bool close_button_on_left = is_portrait == l10n_util::IsLayoutRtl();
153 const bool back_visible = cos(rotation_x * SK_MScalarPI / 180.0f) < 0 ||
154 cos(rotation_y * SK_MScalarPI / 180.0f) < 0;
156 const float content_scale = width / content_width;
157 gfx::RectF content_area(0.f, 0.f, content_width, content_height);
158 gfx::RectF scaled_local_content_area(shadow_x, shadow_y, shadow_width,
159 shadow_height);
160 gfx::RectF descaled_local_content_area(
161 scaled_local_content_area.x() / content_scale,
162 scaled_local_content_area.y() / content_scale,
163 scaled_local_content_area.width() / content_scale,
164 scaled_local_content_area.height() / content_scale);
166 const gfx::Size shadow_padding_size(
167 shadow_resource->size.width() - shadow_padding.width(),
168 shadow_resource->size.height() - shadow_padding.height());
169 const gfx::Size border_padding_size(
170 border_resource->size.width() - border_padding.width(),
171 border_resource->size.height() - border_padding.height());
172 const gfx::Size contour_padding_size(
173 contour_resource->size.width() - contour_padding.width(),
174 contour_resource->size.height() - contour_padding.height());
176 const float close_btn_effective_width = close_btn_width * close_alpha;
178 float toolbar_impact_height = 0;
179 if (toolbar_resource) {
180 //--------------------------------------------------------------------------
181 // Update Resource Ids For Layers That Impact Layout
182 //--------------------------------------------------------------------------
184 // TODO(kkimlabs): Tab switcher doesn't show the progress bar.
185 toolbar_layer_->PushResource(toolbar_resource, anonymize_toolbar,
186 toolbar_textbox_background_color, false, 1.f);
187 toolbar_layer_->UpdateProgressBar(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
189 if (show_toolbar && !back_visible)
190 toolbar_impact_height = toolbar_resource->padding.height();
193 //----------------------------------------------------------------------------
194 // Compute Alpha and Visibility
195 //----------------------------------------------------------------------------
196 border_alpha *= alpha;
197 contour_alpha *= alpha;
198 shadow_alpha *= alpha;
199 close_alpha *= alpha;
200 toolbar_alpha *= alpha;
202 if (back_visible)
203 border_alpha = 0.f;
205 bool border_visible = border_alpha > 0.f;
206 bool contour_visible = border_alpha < contour_alpha && contour_alpha > 0.f;
207 bool shadow_visible = shadow_alpha > 0.f && border_alpha > 0.f;
209 //----------------------------------------------------------------------------
210 // Compute Layer Sizes
211 //----------------------------------------------------------------------------
212 gfx::Size shadow_size(width + shadow_padding_size.width() * side_border_scale,
213 height + shadow_padding_size.height());
214 gfx::Size border_size(width + border_padding_size.width() * side_border_scale,
215 height + border_padding_size.height());
216 gfx::Size contour_size(
217 width + contour_padding_size.width() * side_border_scale,
218 height + contour_padding_size.height());
219 gfx::Size close_button_size(close_btn_width, border_padding.y());
220 gfx::Size title_size(width - close_btn_effective_width, border_padding.y());
221 gfx::Size back_logo_size;
222 // TODO(clholgat): Figure out why the back logo is null sometimes.
223 if (back_visible) {
224 back_logo_resource =
225 resource_manager_->GetResource(ui::ANDROID_RESOURCE_TYPE_STATIC,
226 back_logo_resource_id);
227 if (back_logo_resource)
228 back_logo_size = back_logo_resource->size;
231 // Store this size at a point as it might go negative during the inset
232 // calculations.
233 gfx::Point desired_content_size_pt(
234 descaled_local_content_area.width(),
235 descaled_local_content_area.height() - toolbar_impact_height);
237 // Shrink the toolbar layer so we properly clip if it's offset.
238 gfx::Size toolbar_size(
239 toolbar_layer_->layer()->bounds().width(),
240 toolbar_layer_->layer()->bounds().height() - toolbar_y_offset);
242 //----------------------------------------------------------------------------
243 // Compute Layer Positions
244 //----------------------------------------------------------------------------
245 gfx::PointF shadow_position(-shadow_padding.x() * side_border_scale,
246 -shadow_padding.y());
247 gfx::PointF border_position(-border_padding.x() * side_border_scale,
248 -border_padding.y());
249 gfx::PointF contour_position(-contour_padding.x() * side_border_scale,
250 -contour_padding.y());
251 gfx::PointF toolbar_position(
252 0.f, toolbar_layer_->layer()->bounds().height() - toolbar_size.height());
253 gfx::PointF content_position(0.f, toolbar_impact_height);
254 gfx::PointF back_logo_position(
255 ((descaled_local_content_area.width() - back_logo_->bounds().width()) *
256 content_scale) /
257 2.0f,
258 ((descaled_local_content_area.height() - back_logo_->bounds().height()) *
259 content_scale) /
260 2.0f);
261 gfx::PointF close_button_position;
262 gfx::PointF title_position;
264 close_button_position.set_y(-border_padding.y());
265 title_position.set_y(-border_padding.y());
266 if (!close_button_on_left)
267 close_button_position.set_x(width - close_button_size.width());
268 else
269 title_position.set_x(close_btn_effective_width);
271 //----------------------------------------------------------------------------
272 // Center Specific Assets in the Rects
273 //----------------------------------------------------------------------------
274 close_button_position.Offset(
275 (close_button_size.width() - close_btn_resource->size.width()) / 2.f,
276 (close_button_size.height() - close_btn_resource->size.height()) / 2.f);
277 close_button_size.SetSize(close_btn_resource->size.width(),
278 close_btn_resource->size.height());
280 //----------------------------------------------------------------------------
281 // Handle Insetting the Top Border Component
282 //----------------------------------------------------------------------------
283 if (inset_border) {
284 float inset_diff = inset_border ? border_padding.y() : 0.f;
285 descaled_local_content_area.set_height(
286 descaled_local_content_area.height() - inset_diff);
287 scaled_local_content_area.set_height(scaled_local_content_area.height() -
288 inset_diff * content_scale);
289 shadow_size.set_height(shadow_size.height() - inset_diff);
290 border_size.set_height(border_size.height() - inset_diff);
291 contour_size.set_height(contour_size.height() - inset_diff);
292 shadow_position.set_y(shadow_position.y() + inset_diff);
293 border_position.set_y(border_position.y() + inset_diff);
294 contour_position.set_y(contour_position.y() + inset_diff);
295 close_button_position.set_y(close_button_position.y() + inset_diff);
296 title_position.set_y(title_position.y() + inset_diff);
298 // Scaled eventually, so have to descale the size difference first.
299 toolbar_position.set_y(toolbar_position.y() + inset_diff / content_scale);
300 content_position.set_y(content_position.y() + inset_diff / content_scale);
301 desired_content_size_pt.set_y(desired_content_size_pt.y() -
302 inset_diff / content_scale);
305 const bool inset_toolbar = !inset_border;
306 if (!inset_toolbar) {
307 float inset_diff = toolbar_impact_height;
308 toolbar_position.set_y(toolbar_position.y() - inset_diff);
309 content_position.set_y(content_position.y() - inset_diff);
310 desired_content_size_pt.set_y(desired_content_size_pt.y() + inset_diff);
313 // Finally build the sizes that might have calculations that go negative.
314 gfx::Size desired_content_size(desired_content_size_pt.x(),
315 desired_content_size_pt.y());
317 //----------------------------------------------------------------------------
318 // Calculate Content Visibility
319 //----------------------------------------------------------------------------
320 // Check if the rect we are drawing is larger than the content rect.
321 bool content_visible = desired_content_size.GetArea() > 0.f;
323 // TODO(dtrainor): Improve these calculations to prune these layers out.
324 bool title_visible = border_alpha > 0.f && !back_visible;
325 bool close_btn_visible = title_visible;
326 bool toolbar_visible = show_toolbar && toolbar_alpha > 0.f && !back_visible;
328 //----------------------------------------------------------------------------
329 // Fix jaggies
330 //----------------------------------------------------------------------------
331 border_position.Offset(0.5f, 0.5f);
332 shadow_position.Offset(0.5f, 0.5f);
333 contour_position.Offset(0.5f, 0.5f);
334 title_position.Offset(0.5f, 0.5f);
335 close_button_position.Offset(0.5f, 0.5f);
337 border_size.Enlarge(-1.f, -1.f);
338 shadow_size.Enlarge(-1.f, -1.f);
340 //----------------------------------------------------------------------------
341 // Update Resource Ids
342 //----------------------------------------------------------------------------
343 shadow_->SetUIResourceId(shadow_resource->ui_resource->id());
344 shadow_->SetBorder(shadow_resource->Border(shadow_size));
345 shadow_->SetAperture(shadow_resource->aperture);
347 contour_shadow_->SetUIResourceId(contour_resource->ui_resource->id());
348 contour_shadow_->SetBorder(contour_resource->Border(contour_size));
349 contour_shadow_->SetAperture(contour_resource->aperture);
351 front_border_->SetUIResourceId(border_resource->ui_resource->id());
352 front_border_->SetAperture(border_resource->aperture);
353 front_border_->SetBorder(border_resource->Border(
354 border_size,
355 gfx::InsetsF(1.f, side_border_scale, 1.f, side_border_scale)));
357 padding_->SetBackgroundColor(back_visible ? back_logo_color
358 : default_background_color);
360 if (title_visible && layer_title_cache_)
361 title_layer = layer_title_cache_->GetTitleLayer(id);
362 SetTitle(title_layer);
364 close_button_->SetUIResourceId(close_btn_resource->ui_resource->id());
366 if (!back_visible) {
367 gfx::Rect rounded_descaled_content_area(
368 round(descaled_local_content_area.x()),
369 round(descaled_local_content_area.y()),
370 round(desired_content_size.width()),
371 round(desired_content_size.height()));
373 content_->SetProperties(id, can_use_live_layer, can_use_ntp_fallback,
374 static_to_view_blend, true, alpha, saturation,
375 rounded_descaled_content_area,
376 gfx::Size(content_width, content_height));
377 } else if (back_logo_resource) {
378 back_logo_->SetUIResourceId(back_logo_resource->ui_resource->id());
381 //----------------------------------------------------------------------------
382 // Push Size, Position, Alpha and Transformations to Layers
383 //----------------------------------------------------------------------------
384 shadow_->SetHideLayerAndSubtree(!shadow_visible);
385 if (shadow_visible) {
386 shadow_->SetPosition(shadow_position);
387 shadow_->SetBounds(shadow_size);
388 shadow_->SetOpacity(shadow_alpha);
391 contour_shadow_->SetHideLayerAndSubtree(!contour_visible);
392 if (contour_visible) {
393 contour_shadow_->SetPosition(contour_position);
394 contour_shadow_->SetBounds(contour_size);
395 contour_shadow_->SetOpacity(contour_alpha);
398 front_border_->SetHideLayerAndSubtree(!border_visible);
399 if (border_visible) {
400 front_border_->SetPosition(border_position);
401 front_border_->SetBounds(border_size);
402 front_border_->SetOpacity(border_alpha);
405 toolbar_layer_->layer()->SetHideLayerAndSubtree(!toolbar_visible);
406 if (toolbar_visible) {
407 // toolbar_ Transform
408 gfx::Transform transform;
409 transform.Scale(content_scale, content_scale);
410 transform.Translate(toolbar_position.x(), toolbar_position.y());
411 toolbar_layer_->layer()->SetTransformOrigin(gfx::Point3F(0.f, 0.f, 0.f));
412 toolbar_layer_->layer()->SetTransform(transform);
413 toolbar_layer_->layer()->SetOpacity(toolbar_alpha);
415 toolbar_layer_->layer()->SetMasksToBounds(
416 toolbar_layer_->layer()->bounds() != toolbar_size);
417 toolbar_layer_->layer()->SetBounds(toolbar_size);
420 if (title_layer) {
421 gfx::PointF vertically_centered_position(
422 title_position.x(),
423 title_position.y() +
424 (title_size.height() - title_layer->size().height()) / 2.f);
426 title_->SetPosition(vertically_centered_position);
427 title_layer->setBounds(title_size);
428 title_layer->setOpacity(border_alpha);
431 close_button_->SetHideLayerAndSubtree(!close_btn_visible);
432 if (close_btn_visible) {
433 close_button_->SetPosition(close_button_position);
434 close_button_->SetBounds(close_button_size);
435 // Non-linear alpha looks better.
436 close_button_->SetOpacity(close_alpha * close_alpha * border_alpha);
439 if (content_visible && attach_content) {
441 // content_ and back_logo_ Transforms
442 gfx::Transform transform;
443 transform.Scale(content_scale, content_scale);
444 transform.Translate(content_position.x(), content_position.y());
445 transform.Translate(descaled_local_content_area.x(),
446 descaled_local_content_area.y());
448 content_->layer()->SetHideLayerAndSubtree(back_visible);
449 back_logo_->SetHideLayerAndSubtree(!back_visible);
451 if (!back_visible) {
452 content_->layer()->SetTransformOrigin(gfx::Point3F(0.f, 0.f, 0.f));
453 content_->layer()->SetTransform(transform);
454 } else {
455 back_logo_->SetPosition(back_logo_position);
456 back_logo_->SetBounds(back_logo_size);
457 back_logo_->SetTransformOrigin(gfx::Point3F(0.f, 0.f, 0.f));
458 back_logo_->SetTransform(transform);
459 // TODO: Set back logo alpha on leaf.
464 // padding_ Transform
465 gfx::Size content_bounds;
466 if (!back_visible)
467 content_bounds = content_->layer()->bounds();
469 gfx::Rect padding_rect(
470 ComputePaddingPosition(content_bounds, desired_content_size));
471 padding_->SetHideLayerAndSubtree(padding_rect.IsEmpty());
472 padding_->SetBounds(padding_rect.size());
473 padding_->SetOpacity(alpha);
475 gfx::Transform transform;
476 transform.Scale(content_scale, content_scale);
477 transform.Translate(padding_rect.x() + content_position.x(),
478 padding_rect.y() + content_position.y());
479 transform.Translate(descaled_local_content_area.x(),
480 descaled_local_content_area.y());
481 padding_->SetTransformOrigin(gfx::Point3F(0.f, 0.f, 0.f));
482 padding_->SetTransform(transform);
484 } else {
485 back_logo_->SetHideLayerAndSubtree(true);
486 padding_->SetHideLayerAndSubtree(true);
487 content_->layer()->SetHideLayerAndSubtree(true);
491 // Global Transform
492 gfx::PointF pivot_origin(pivot_y, pivot_x);
494 gfx::Transform transform;
496 if (rotation_x != 0 || rotation_y != 0) {
497 // Apply screen perspective if there are rotations.
498 transform.Translate(content_width / 2, content_height / 2);
499 transform.ApplyPerspectiveDepth(
500 content_width > content_height ? content_width : content_height);
501 transform.Translate(-content_width / 2, -content_height / 2);
503 // Translate to correct position on the screen
504 transform.Translate(x, y);
506 // Apply pivot rotations
507 transform.Translate(pivot_origin.x(), pivot_origin.y());
508 transform.RotateAboutYAxis(rotation_y);
509 transform.RotateAboutXAxis(-rotation_x);
510 transform.Translate(-pivot_origin.x(), -pivot_origin.y());
511 } else {
512 // Translate to correct position on the screen
513 transform.Translate(x, y);
515 transform.Scale(border_scale, border_scale);
516 layer_->SetTransform(transform);
519 // Only applies the brightness filter if the value has changed and is less
520 // than 1.
521 if (brightness != brightness_) {
522 brightness_ = brightness;
523 cc::FilterOperations filters;
524 if (brightness_ < 1.f)
525 filters.Append(cc::FilterOperation::CreateBrightnessFilter(brightness_));
526 layer_->SetFilters(filters);
530 scoped_refptr<cc::Layer> TabLayer::layer() {
531 return layer_;
534 TabLayer::TabLayer(bool incognito,
535 ui::ResourceManager* resource_manager,
536 LayerTitleCache* layer_title_cache,
537 TabContentManager* tab_content_manager)
538 : incognito_(incognito),
539 resource_manager_(resource_manager),
540 layer_title_cache_(layer_title_cache),
541 layer_(cc::Layer::Create(content::Compositor::LayerSettings())),
542 toolbar_layer_(ToolbarLayer::Create()),
543 title_(cc::Layer::Create(content::Compositor::LayerSettings())),
544 content_(ContentLayer::Create(tab_content_manager)),
545 padding_(
546 cc::SolidColorLayer::Create(content::Compositor::LayerSettings())),
547 close_button_(
548 cc::UIResourceLayer::Create(content::Compositor::LayerSettings())),
549 front_border_(
550 cc::NinePatchLayer::Create(content::Compositor::LayerSettings())),
551 contour_shadow_(
552 cc::NinePatchLayer::Create(content::Compositor::LayerSettings())),
553 shadow_(cc::NinePatchLayer::Create(content::Compositor::LayerSettings())),
554 back_logo_(
555 cc::UIResourceLayer::Create(content::Compositor::LayerSettings())),
556 brightness_(1.f) {
557 layer_->AddChild(shadow_);
558 layer_->AddChild(contour_shadow_);
559 layer_->AddChild(padding_);
560 layer_->AddChild(content_->layer());
561 layer_->AddChild(back_logo_);
562 layer_->AddChild(front_border_);
563 layer_->AddChild(title_.get());
564 layer_->AddChild(close_button_);
565 layer_->AddChild(toolbar_layer_->layer());
567 contour_shadow_->SetIsDrawable(true);
568 padding_->SetIsDrawable(true);
569 front_border_->SetIsDrawable(true);
570 shadow_->SetIsDrawable(true);
571 close_button_->SetIsDrawable(true);
572 back_logo_->SetIsDrawable(true);
575 TabLayer::~TabLayer() {
578 void TabLayer::SetTitle(DecorationTitle* title) {
579 scoped_refptr<cc::Layer> layer = title ? title->layer() : nullptr;
581 if (!layer.get()) {
582 title_->RemoveAllChildren();
583 } else {
584 const cc::LayerList& children = title_->children();
585 if (children.size() == 0 || children[0]->id() != layer->id()) {
586 title_->RemoveAllChildren();
587 title_->AddChild(layer);
591 if (title)
592 title->SetUIResourceIds();
595 } // namespace android
596 } // namespace chrome