| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/android/compositor/layer/overlay_panel_layer.h" |
| |
| #include "cc/resources/scoped_ui_resource.h" |
| #include "cc/slim/layer.h" |
| #include "cc/slim/nine_patch_layer.h" |
| #include "cc/slim/solid_color_layer.h" |
| #include "cc/slim/ui_resource_layer.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "ui/android/resources/nine_patch_resource.h" |
| #include "ui/android/resources/resource_manager.h" |
| #include "ui/base/l10n/l10n_util_android.h" |
| #include "ui/gfx/color_utils.h" |
| |
| namespace android { |
| |
| scoped_refptr<cc::slim::Layer> OverlayPanelLayer::GetIconLayer() { |
| if (panel_icon_resource_id_ == kInvalidResourceID) |
| return nullptr; |
| ui::Resource* panel_icon_resource = resource_manager_->GetResource( |
| ui::ANDROID_RESOURCE_TYPE_STATIC, panel_icon_resource_id_); |
| DCHECK(panel_icon_resource); |
| |
| if (panel_icon_->parent() != layer_) { |
| layer_->AddChild(panel_icon_); |
| } |
| |
| panel_icon_->SetUIResourceId(panel_icon_resource->ui_resource()->id()); |
| panel_icon_->SetBounds(panel_icon_resource->size()); |
| |
| return panel_icon_; |
| } |
| |
| void OverlayPanelLayer::AddBarTextLayer( |
| scoped_refptr<cc::slim::Layer> text_layer) { |
| if (text_container_->parent() != layer_) |
| layer_->AddChild(text_container_); |
| if (text_layer->parent() != text_container_) |
| text_container_->AddChild(text_layer); |
| } |
| |
| void OverlayPanelLayer::SetResourceIds(int bar_text_resource_id, |
| int panel_shadow_resource_id, |
| int rounded_bar_top_resource_id, |
| int bar_shadow_resource_id, |
| int panel_icon_resource_id, |
| int drag_handlebar_resource_id, |
| int open_tab_icon_resource_id, |
| int close_icon_resource_id) { |
| bar_text_resource_id_ = bar_text_resource_id; |
| panel_shadow_resource_id_ = panel_shadow_resource_id; |
| rounded_bar_top_resource_id_ = rounded_bar_top_resource_id; |
| bar_shadow_resource_id_ = bar_shadow_resource_id; |
| panel_icon_resource_id_ = panel_icon_resource_id; |
| drag_handlebar_resource_id_ = drag_handlebar_resource_id; |
| open_tab_icon_resource_id_ = open_tab_icon_resource_id; |
| close_icon_resource_id_ = close_icon_resource_id; |
| } |
| |
| void OverlayPanelLayer::SetProperties( |
| float dp_to_px, |
| const scoped_refptr<cc::slim::Layer>& content_layer, |
| float content_offset_y, |
| float panel_x, |
| float panel_y, |
| float panel_width, |
| float panel_height, |
| int bar_background_color, |
| float bar_margin_side, |
| float bar_margin_top, |
| float bar_margin_bottom, |
| float bar_height, |
| float bar_offset_y, |
| float bar_text_opacity, |
| bool bar_border_visible, |
| float bar_border_height, |
| int icon_tint, |
| int drag_handlebar_tint, |
| float icon_opacity, |
| int separator_line_color, |
| float in_bar_related_searches_height) { |
| // Round values to avoid pixel gap between layers. |
| bar_height = floor(bar_height); |
| |
| // --------------------------------------------------------------------------- |
| // Content setup, to center in space below drag handle (when present). |
| // When Related Searches are shown in the Bar they appear below the rest of |
| // this content. |
| // --------------------------------------------------------------------------- |
| float bar_top_y = bar_offset_y; |
| float bar_bottom = bar_top_y + bar_height; |
| |
| bool is_rtl = l10n_util::IsLayoutRtl(); |
| |
| int content_top_y = bar_top_y; |
| int content_height = bar_height - in_bar_related_searches_height; |
| int rounded_top_height = 0; |
| gfx::Size rounded_bar_top_size; |
| gfx::PointF rounded_bar_top_position; |
| |
| ui::NinePatchResource* rounded_bar_top_resource = nullptr; |
| content_top_y += bar_margin_top; |
| content_height -= bar_margin_top; |
| content_height -= bar_margin_bottom; |
| |
| rounded_bar_top_resource = |
| ui::NinePatchResource::From(resource_manager_->GetStaticResourceWithTint( |
| rounded_bar_top_resource_id_, bar_background_color)); |
| |
| rounded_bar_top_size = gfx::Size(rounded_bar_top_resource->size().width(), |
| rounded_bar_top_resource->size().height()); |
| |
| // TODO(donnd): fix correctly. |
| const int vertical_fudge_factor = 2; // Create an overlap to avoid a seam. |
| rounded_top_height = rounded_bar_top_resource->size().height(); |
| |
| rounded_bar_top_position = |
| gfx::PointF(-rounded_bar_top_resource->padding().x(), |
| bar_top_y + vertical_fudge_factor); |
| |
| // --------------------------------------------------------------------------- |
| // Panel Shadow |
| // --------------------------------------------------------------------------- |
| if (panel_shadow_resource_id_ != kInvalidResourceID) { |
| if (panel_shadow_->parent() != layer_) { |
| layer_->InsertChild(panel_shadow_, 0); |
| } |
| ui::NinePatchResource* panel_shadow_resource = |
| ui::NinePatchResource::From(resource_manager_->GetResource( |
| ui::ANDROID_RESOURCE_TYPE_STATIC, panel_shadow_resource_id_)); |
| DCHECK(panel_shadow_resource); |
| |
| gfx::Size shadow_res_size = panel_shadow_resource->size(); |
| panel_shadow_->SetUIResourceId(panel_shadow_resource->ui_resource()->id()); |
| panel_shadow_->SetAperture(panel_shadow_resource->aperture()); |
| |
| DCHECK(rounded_bar_top_resource); |
| |
| int shadow_thickness = shadow_res_size.height() - rounded_top_height; |
| |
| gfx::Size shadow_bounds(panel_width + (shadow_thickness * 2), |
| panel_height + shadow_thickness); |
| panel_shadow_->SetBounds(shadow_bounds); |
| panel_shadow_->SetBorder(panel_shadow_resource->Border(shadow_bounds)); |
| gfx::PointF shadow_position(-shadow_thickness, |
| bar_top_y - shadow_thickness); |
| panel_shadow_->SetPosition(shadow_position); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Rounded Bar Top |
| // --------------------------------------------------------------------------- |
| |
| DCHECK(rounded_bar_top_resource_id_ != kInvalidResourceID); |
| rounded_bar_top_->SetIsDrawable(true); |
| |
| DCHECK(rounded_bar_top_resource); |
| |
| gfx::Size bounds(panel_width, rounded_bar_top_resource->size().height()); |
| |
| rounded_bar_top_->SetUIResourceId( |
| rounded_bar_top_resource->ui_resource()->id()); |
| rounded_bar_top_->SetBounds(bounds); |
| rounded_bar_top_->SetAperture(rounded_bar_top_resource->aperture()); |
| rounded_bar_top_->SetBorder(rounded_bar_top_resource->Border(bounds)); |
| rounded_bar_top_->SetPosition(rounded_bar_top_position); |
| rounded_bar_top_->SetOpacity(1.0f); |
| |
| // --------------------------------------------------------------------------- |
| // Bar Background |
| // --------------------------------------------------------------------------- |
| // If we have a rounded_bar_top then it draws the top part of the bar |
| // background. |
| gfx::Size background_size(panel_width, bar_height - rounded_top_height); |
| bar_background_->SetBounds(background_size); |
| bar_background_->SetPosition( |
| gfx::PointF(0.f, bar_top_y + rounded_top_height)); |
| // TODO(crbug.com/40219248): Remove FromColor and make all SkColor4f. |
| bar_background_->SetBackgroundColor( |
| SkColor4f::FromColor(bar_background_color)); |
| |
| // --------------------------------------------------------------------------- |
| // Bar Text |
| // --------------------------------------------------------------------------- |
| ui::Resource* bar_text_resource = resource_manager_->GetResource( |
| ui::ANDROID_RESOURCE_TYPE_DYNAMIC, bar_text_resource_id_); |
| |
| if (bar_text_resource) { |
| // Centers the text vertically in the section of the Search Bar below the |
| // drag handle. |
| float bar_padding_top = content_top_y + content_height / 2 - |
| bar_text_resource->size().height() / 2; |
| bar_text_->SetUIResourceId(bar_text_resource->ui_resource()->id()); |
| bar_text_->SetBounds(bar_text_resource->size()); |
| bar_text_->SetPosition(gfx::PointF(0.f, bar_padding_top)); |
| bar_text_->SetOpacity(bar_text_opacity); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Panel Icon |
| // --------------------------------------------------------------------------- |
| scoped_refptr<cc::slim::Layer> icon_layer = GetIconLayer(); |
| if (icon_layer) { |
| // If the icon is not the default width, add or remove padding so it appears |
| // centered. |
| float icon_padding = (kDefaultIconWidthDp * dp_to_px - |
| icon_layer->bounds().width()) / 2.0f; |
| |
| // Positions the Icon at the start of the bar. |
| float icon_x; |
| if (is_rtl) { |
| icon_x = panel_width - icon_layer->bounds().width() - |
| (bar_margin_side + icon_padding); |
| } else { |
| icon_x = bar_margin_side + icon_padding; |
| } |
| |
| // Centers the Icon vertically in the bar. |
| float icon_y = |
| content_top_y + content_height / 2 - icon_layer->bounds().height() / 2; |
| |
| icon_layer->SetPosition(gfx::PointF(icon_x, icon_y)); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Drag Handlebar |
| // --------------------------------------------------------------------------- |
| if (drag_handlebar_resource_id_ != kInvalidResourceID) { |
| if (drag_handlebar_->parent() != layer_) |
| layer_->AddChild(drag_handlebar_); |
| |
| ui::Resource* drag_handlebar_resource = |
| resource_manager_->GetStaticResourceWithTint( |
| drag_handlebar_resource_id_, drag_handlebar_tint); |
| drag_handlebar_->SetUIResourceId( |
| drag_handlebar_resource->ui_resource()->id()); |
| drag_handlebar_->SetBounds(drag_handlebar_resource->size()); |
| float drag_handlebar_left = |
| panel_width / 2 - drag_handlebar_resource->size().width() / 2; |
| float drag_handlebar_top = bar_top_y + bar_margin_top - |
| drag_handlebar_resource->size().height() / 2; |
| drag_handlebar_->SetPosition( |
| gfx::PointF(drag_handlebar_left, drag_handlebar_top)); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Close Icon |
| // --------------------------------------------------------------------------- |
| int close_icon_width = 0; |
| float close_icon_left = 0.f; |
| // Positions the icon at the end of the bar. |
| if (is_rtl) { |
| close_icon_left = bar_margin_side; |
| } else { |
| close_icon_left = panel_width - bar_margin_side; |
| } |
| if (close_icon_resource_id_ != kInvalidResourceID) { |
| // Grab the Close Icon resource. |
| ui::Resource* close_icon_resource = |
| resource_manager_->GetStaticResourceWithTint(close_icon_resource_id_, |
| icon_tint); |
| |
| // Positions the icon at the end of the bar. |
| close_icon_width = close_icon_resource->size().width(); |
| if (!is_rtl) { |
| close_icon_left = close_icon_left - close_icon_width; |
| } |
| |
| // Centers the Close Icon vertically in the bar. |
| float close_icon_top = content_top_y + content_height / 2 - |
| close_icon_resource->size().height() / 2; |
| close_icon_->SetUIResourceId(close_icon_resource->ui_resource()->id()); |
| close_icon_->SetBounds(close_icon_resource->size()); |
| close_icon_->SetPosition(gfx::PointF(close_icon_left, close_icon_top)); |
| close_icon_->SetOpacity(icon_opacity); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Open Tab icon |
| // --------------------------------------------------------------------------- |
| if (open_tab_icon_resource_id_ != kInvalidResourceID) { |
| ui::Resource* open_tab_icon_resource = |
| resource_manager_->GetStaticResourceWithTint(open_tab_icon_resource_id_, |
| icon_tint); |
| // Positions the icon at the end of the bar. |
| float open_tab_top = content_top_y + content_height / 2 - |
| open_tab_icon_resource->size().height() / 2; |
| float open_tab_left; |
| float spacing_between_icons = 2 * bar_margin_side; |
| float margin_from_close_icon = close_icon_width + spacing_between_icons; |
| if (is_rtl) { |
| open_tab_left = close_icon_resource_id_ == kInvalidResourceID |
| ? close_icon_left |
| : close_icon_left + margin_from_close_icon; |
| } else { |
| open_tab_left = close_icon_left - margin_from_close_icon; |
| } |
| |
| open_tab_icon_->SetUIResourceId( |
| open_tab_icon_resource->ui_resource()->id()); |
| open_tab_icon_->SetBounds(open_tab_icon_resource->size()); |
| open_tab_icon_->SetPosition(gfx::PointF(open_tab_left, open_tab_top)); |
| open_tab_icon_->SetOpacity(icon_opacity); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Overlay Web Content |
| // --------------------------------------------------------------------------- |
| content_container_->SetPosition( |
| gfx::PointF(0.f, content_offset_y)); |
| content_container_->SetBounds(gfx::Size(panel_width, panel_height)); |
| content_container_->SetBackgroundColor( |
| SkColor4f::FromColor(bar_background_color)); |
| if (content_layer) { |
| if (content_layer->parent() != content_container_) |
| content_container_->AddChild(content_layer); |
| } else { |
| content_container_->RemoveAllChildren(); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Bar Shadow |
| // --------------------------------------------------------------------------- |
| ui::Resource* bar_shadow_resource = resource_manager_->GetResource( |
| ui::ANDROID_RESOURCE_TYPE_STATIC, bar_shadow_resource_id_); |
| |
| if (bar_shadow_resource) { |
| if (bar_shadow_->parent() != layer_) |
| layer_->AddChild(bar_shadow_); |
| |
| int shadow_height = bar_shadow_resource->size().height(); |
| gfx::Size shadow_size(panel_width, shadow_height); |
| |
| bar_shadow_->SetUIResourceId(bar_shadow_resource->ui_resource()->id()); |
| bar_shadow_->SetBounds(shadow_size); |
| bar_shadow_->SetPosition(gfx::PointF(0.f, bar_bottom)); |
| bar_shadow_->SetOpacity(1.0f); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Panel |
| // --------------------------------------------------------------------------- |
| layer_->SetPosition(gfx::PointF(panel_x, panel_y)); |
| |
| // --------------------------------------------------------------------------- |
| // Bar border |
| // --------------------------------------------------------------------------- |
| if (bar_border_visible) { |
| gfx::Size bar_border_size(panel_width, |
| bar_border_height); |
| float border_y = bar_bottom - bar_border_height; |
| bar_border_->SetBounds(bar_border_size); |
| bar_border_->SetPosition( |
| gfx::PointF(0.f, border_y)); |
| bar_border_->SetBackgroundColor(SkColor4f::FromColor(separator_line_color)); |
| if (bar_border_->parent() != layer_) |
| layer_->AddChild(bar_border_); |
| } else if (bar_border_.get() && bar_border_->parent()) { |
| bar_border_->RemoveFromParent(); |
| } |
| } |
| |
| void OverlayPanelLayer::SetProgressBar(int progress_bar_background_resource_id, |
| int progress_bar_background_tint, |
| int progress_bar_resource_id, |
| int progress_bar_tint, |
| bool progress_bar_visible, |
| float progress_bar_position_y, |
| float progress_bar_height, |
| float progress_bar_opacity, |
| float progress_bar_completion, |
| float panel_width) { |
| bool should_render_progress_bar = |
| progress_bar_visible && progress_bar_opacity > 0.f; |
| |
| if (should_render_progress_bar) { |
| ui::NinePatchResource* progress_bar_background_resource = |
| ui::NinePatchResource::From( |
| resource_manager_->GetStaticResourceWithTint( |
| progress_bar_background_resource_id, |
| progress_bar_background_tint)); |
| ui::NinePatchResource* progress_bar_resource = ui::NinePatchResource::From( |
| resource_manager_->GetStaticResourceWithTint(progress_bar_resource_id, |
| progress_bar_tint)); |
| |
| DCHECK(progress_bar_background_resource); |
| DCHECK(progress_bar_resource); |
| |
| // Progress Bar Background |
| if (progress_bar_background_->parent() != layer_) |
| layer_->AddChild(progress_bar_background_); |
| |
| float progress_bar_y = progress_bar_position_y - progress_bar_height; |
| gfx::Size progress_bar_background_size(panel_width, progress_bar_height); |
| |
| progress_bar_background_->SetUIResourceId( |
| progress_bar_background_resource->ui_resource()->id()); |
| progress_bar_background_->SetBorder( |
| progress_bar_background_resource->Border(progress_bar_background_size)); |
| progress_bar_background_->SetAperture( |
| progress_bar_background_resource->aperture()); |
| progress_bar_background_->SetBounds(progress_bar_background_size); |
| progress_bar_background_->SetPosition(gfx::PointF(0.f, progress_bar_y)); |
| progress_bar_background_->SetOpacity(progress_bar_opacity); |
| |
| // Progress Bar |
| if (progress_bar_->parent() != layer_) |
| layer_->AddChild(progress_bar_); |
| |
| float progress_bar_width = floor(panel_width * progress_bar_completion); |
| gfx::Size progress_bar_size(progress_bar_width, progress_bar_height); |
| progress_bar_->SetUIResourceId(progress_bar_resource->ui_resource()->id()); |
| progress_bar_->SetBorder(progress_bar_resource->Border(progress_bar_size)); |
| progress_bar_->SetAperture(progress_bar_resource->aperture()); |
| progress_bar_->SetBounds(progress_bar_size); |
| progress_bar_->SetPosition(gfx::PointF(0.f, progress_bar_y)); |
| progress_bar_->SetOpacity(progress_bar_opacity); |
| } else { |
| // Removes Progress Bar and its Background from the Layer Tree. |
| if (progress_bar_background_.get() && progress_bar_background_->parent()) |
| progress_bar_background_->RemoveFromParent(); |
| |
| if (progress_bar_.get() && progress_bar_->parent()) |
| progress_bar_->RemoveFromParent(); |
| } |
| } |
| |
| OverlayPanelLayer::OverlayPanelLayer(ui::ResourceManager* resource_manager) |
| : resource_manager_(resource_manager), |
| layer_(cc::slim::Layer::Create()), |
| panel_shadow_(cc::slim::NinePatchLayer::Create()), |
| rounded_bar_top_(cc::slim::NinePatchLayer::Create()), |
| bar_background_(cc::slim::SolidColorLayer::Create()), |
| bar_text_(cc::slim::UIResourceLayer::Create()), |
| bar_shadow_(cc::slim::UIResourceLayer::Create()), |
| panel_icon_(cc::slim::UIResourceLayer::Create()), |
| drag_handlebar_(cc::slim::UIResourceLayer::Create()), |
| open_tab_icon_(cc::slim::UIResourceLayer::Create()), |
| close_icon_(cc::slim::UIResourceLayer::Create()), |
| content_container_(cc::slim::SolidColorLayer::Create()), |
| text_container_(cc::slim::Layer::Create()), |
| bar_border_(cc::slim::SolidColorLayer::Create()), |
| progress_bar_(cc::slim::NinePatchLayer::Create()), |
| progress_bar_background_(cc::slim::NinePatchLayer::Create()) { |
| // Background colors for each widget are set in SetProperties, where variable |
| // colors are available. |
| layer_->SetMasksToBounds(false); |
| layer_->SetIsDrawable(true); |
| |
| // Panel Shadow -- the shadow around all sides of the panel. |
| panel_shadow_->SetIsDrawable(true); |
| panel_shadow_->SetFillCenter(false); |
| |
| // Rounded Bar Top |
| // Puts the layer near the bottom -- we'll decide if it's actually drawable |
| // later. |
| rounded_bar_top_->SetIsDrawable(false); |
| layer_->AddChild(rounded_bar_top_); |
| |
| // Bar Background |
| bar_background_->SetIsDrawable(true); |
| layer_->AddChild(bar_background_); |
| |
| // Bar Text |
| bar_text_->SetIsDrawable(true); |
| AddBarTextLayer(bar_text_); |
| |
| // Panel Icon |
| panel_icon_->SetIsDrawable(true); |
| |
| // The container that any text in the bar will be added to. |
| text_container_->SetIsDrawable(true); |
| |
| // Drag Handlebar |
| drag_handlebar_->SetIsDrawable(true); |
| |
| // Open Tab Icon |
| open_tab_icon_->SetIsDrawable(true); |
| layer_->AddChild(open_tab_icon_); |
| |
| // Close Icon |
| close_icon_->SetIsDrawable(true); |
| layer_->AddChild(close_icon_); |
| |
| // Content Container |
| content_container_->SetIsDrawable(true); |
| layer_->AddChild(content_container_); |
| |
| // Bar Border |
| bar_border_->SetIsDrawable(true); |
| |
| // Bar Shadow |
| bar_shadow_->SetIsDrawable(true); |
| |
| // Progress Bar Background |
| progress_bar_background_->SetIsDrawable(true); |
| progress_bar_background_->SetFillCenter(true); |
| |
| // Progress Bar |
| progress_bar_->SetIsDrawable(true); |
| progress_bar_->SetFillCenter(true); |
| } |
| |
| OverlayPanelLayer::~OverlayPanelLayer() = default; |
| |
| scoped_refptr<cc::slim::Layer> OverlayPanelLayer::layer() { |
| return layer_; |
| } |
| |
| } // namespace android |