blob: 1e26ad9bf25469a1a6e9e8bda8c8b8d4252f4ab3 [file] [log] [blame]
// Copyright 2014 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/toolbar_layer.h"
#include "base/feature_list.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 "chrome/browser/android/compositor/resources/toolbar_resource.h"
#include "chrome/browser/flags/android/chrome_feature_list.h"
#include "chrome/browser/ui/ui_features.h"
#include "components/viz/common/features.h"
#include "components/viz/common/quads/offset_tag.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/gfx/geometry/rounded_corners_f.h"
namespace android {
// static
scoped_refptr<ToolbarLayer> ToolbarLayer::Create(
ui::ResourceManager* resource_manager) {
return base::WrapRefCounted(new ToolbarLayer(resource_manager));
}
scoped_refptr<cc::slim::Layer> ToolbarLayer::layer() {
return layer_;
}
void ToolbarLayer::PushResource(int toolbar_resource_id,
int toolbar_background_color,
bool anonymize,
int toolbar_textbox_background_color,
int url_bar_background_resource_id,
float x_offset,
float content_offset,
bool show_debug,
bool clip_shadow,
const viz::OffsetTag& offset_tag) {
ToolbarResource* resource =
ToolbarResource::From(resource_manager_->GetResource(
ui::ANDROID_RESOURCE_TYPE_DYNAMIC, toolbar_resource_id));
// Ensure the toolbar resource is available before making the layer visible.
layer_->SetHideLayerAndSubtree(!resource);
if (!resource)
return;
// This layer effectively draws over the space the resource takes for shadows.
// Set the bounds to the non-shadow size so that other things can properly
// line up.
gfx::Size toolbar_bounds =
gfx::Size(resource->size().width(),
resource->size().height() - resource->shadow_height());
layer_->SetBounds(toolbar_bounds);
toolbar_background_layer_->SetBounds(resource->toolbar_rect().size());
toolbar_background_layer_->SetPosition(
gfx::PointF(resource->toolbar_rect().origin()));
// TODO(crbug.com/40219248): Remove FromColor and make all SkColor4f.
toolbar_background_layer_->SetBackgroundColor(
SkColor4f::FromColor(toolbar_background_color));
bool url_bar_visible = resource->location_bar_content_rect().width() != 0;
url_bar_background_layer_->SetHideLayerAndSubtree(!url_bar_visible);
if (url_bar_visible) {
ui::NinePatchResource* url_bar_background_resource;
url_bar_background_resource = ui::NinePatchResource::From(
resource_manager_->GetStaticResourceWithTint(
url_bar_background_resource_id, toolbar_textbox_background_color));
gfx::Size draw_size(url_bar_background_resource->DrawSize(
resource->location_bar_content_rect().size()));
gfx::Rect border(url_bar_background_resource->Border(draw_size));
gfx::PointF position(url_bar_background_resource->DrawPosition(
resource->location_bar_content_rect().origin()));
url_bar_background_layer_->SetBounds(draw_size);
url_bar_background_layer_->SetPosition(position);
url_bar_background_layer_->SetBorder(border);
url_bar_background_layer_->SetAperture(
url_bar_background_resource->aperture());
url_bar_background_layer_->SetUIResourceId(
url_bar_background_resource->ui_resource()->id());
}
bitmap_layer_->SetUIResourceId(resource->ui_resource()->id());
bitmap_layer_->SetBounds(resource->size());
layer_->SetMasksToBounds(clip_shadow);
// The location bar background doubles as the anonymize layer -- it just
// needs to be drawn on top of the toolbar bitmap.
int background_layer_index = GetIndexOfLayer(toolbar_background_layer_);
scoped_refptr<cc::slim::Layer> parent = ToolbarParentLayer();
bool needs_move_to_front =
anonymize && parent->children().back() != url_bar_background_layer_;
bool needs_move_to_back =
!anonymize &&
parent->children()[background_layer_index] != url_bar_background_layer_;
// If the layer needs to move, remove and re-add it.
if (needs_move_to_front) {
parent->AddChild(url_bar_background_layer_);
} else if (needs_move_to_back) {
parent->InsertChild(url_bar_background_layer_, background_layer_index + 1);
}
debug_layer_->SetBounds(resource->size());
if (show_debug && !debug_layer_->parent())
layer_->AddChild(debug_layer_);
else if (!show_debug && debug_layer_->parent())
debug_layer_->RemoveFromParent();
// Position the toolbar at the bottom of the space available for top controls.
layer_->SetPosition(
gfx::PointF(x_offset, content_offset - layer_->bounds().height()));
if (features::IsAndroidAnimatedProgressBarInVizEnabled()) {
toolbar_layers_->SetOffsetTag(offset_tag);
} else {
layer_->SetOffsetTag(offset_tag);
}
}
int ToolbarLayer::GetIndexOfLayer(scoped_refptr<cc::slim::Layer> layer) {
scoped_refptr<cc::slim::Layer> parent = ToolbarParentLayer();
for (unsigned int i = 0; i < parent->children().size(); ++i) {
if (parent->children()[i] == layer) {
return i;
}
}
return -1;
}
scoped_refptr<cc::slim::Layer> ToolbarLayer::ToolbarParentLayer() {
if (features::IsAndroidAnimatedProgressBarInVizEnabled()) {
return toolbar_layers_;
} else {
return layer_;
}
}
void ToolbarLayer::UpdateProgressBar(int progress_bar_x,
int progress_bar_y,
int progress_bar_width,
int progress_bar_height,
int progress_bar_color,
int progress_bar_background_x,
int progress_bar_background_y,
int progress_bar_background_width,
int progress_bar_background_height,
int progress_bar_background_color,
int progress_bar_static_background_x,
int progress_bar_static_background_width,
int progress_bar_static_background_color,
float corner_radius,
bool progress_bar_visual_update_available,
bool visible,
const viz::OffsetTag& offset_tag) {
bool is_progress_bar_visible = SkColorGetA(progress_bar_background_color);
if (features::IsAndroidAnimatedProgressBarInVizEnabled() ||
features::IsAndroidAnimatedProgressBarInBrowserEnabled()) {
is_progress_bar_visible = visible;
if (features::IsAndroidAnimatedProgressBarInVizEnabled()) {
progress_bar_layers_->SetOffsetTag(offset_tag);
}
}
progress_bar_background_layer_->SetHideLayerAndSubtree(!is_progress_bar_visible);
progress_bar_layer_->SetHideLayerAndSubtree(!is_progress_bar_visible);
progress_bar_static_background_layer_->SetHideLayerAndSubtree(
!(is_progress_bar_visible && progress_bar_visual_update_available));
if (is_progress_bar_visible) {
if (features::IsAndroidAnimatedProgressBarInVizEnabled()) {
// Use corner_radius for gap between the foreground and background layer.
progress_bar_background_layer_->SetPosition(
gfx::PointF(corner_radius * 2, progress_bar_background_y));
} else {
progress_bar_background_layer_->SetPosition(
gfx::PointF(progress_bar_background_x, progress_bar_background_y));
}
progress_bar_background_layer_->SetBounds(
gfx::Size(progress_bar_background_width,
progress_bar_background_height));
// TODO(crbug.com/40219248): Remove FromColor and make all SkColor4f.
progress_bar_background_layer_->SetBackgroundColor(
SkColor4f::FromColor(progress_bar_background_color));
progress_bar_background_layer_->SetRoundedCorner(gfx::RoundedCornersF(corner_radius));
if (features::IsAndroidAnimatedProgressBarInVizEnabled()) {
// Position the foregound layer to show 0% progress.
progress_bar_layer_->SetPosition(
gfx::PointF(-progress_bar_width, progress_bar_y));
} else {
progress_bar_layer_->SetPosition(
gfx::PointF(progress_bar_x, progress_bar_y));
}
progress_bar_layer_->SetBounds(
gfx::Size(progress_bar_width, progress_bar_height));
// TODO(crbug.com/40219248): Remove FromColor and make all SkColor4f.
progress_bar_layer_->SetBackgroundColor(
SkColor4f::FromColor(progress_bar_color));
progress_bar_layer_->SetRoundedCorner(gfx::RoundedCornersF(corner_radius));
if (progress_bar_visual_update_available) {
progress_bar_static_background_layer_->SetPosition(gfx::PointF(
progress_bar_static_background_x, progress_bar_y));
progress_bar_static_background_layer_->SetBounds(gfx::Size(
progress_bar_static_background_width, progress_bar_height));
progress_bar_static_background_layer_->SetBackgroundColor(
SkColor4f::FromColor(progress_bar_static_background_color));
progress_bar_static_background_layer_->SetRoundedCorner(gfx::RoundedCornersF(corner_radius));
}
}
}
void ToolbarLayer::SetOpacity(float opacity) {
toolbar_background_layer_->SetOpacity(opacity);
url_bar_background_layer_->SetOpacity(opacity);
bitmap_layer_->SetOpacity(opacity);
progress_bar_layer_->SetOpacity(opacity);
progress_bar_background_layer_->SetOpacity(opacity);
progress_bar_static_background_layer_->SetOpacity(opacity);
}
ToolbarLayer::ToolbarLayer(ui::ResourceManager* resource_manager)
: resource_manager_(resource_manager),
layer_(cc::slim::Layer::Create()),
toolbar_layers_(cc::slim::Layer::Create()),
progress_bar_layers_(cc::slim::Layer::Create()),
toolbar_background_layer_(cc::slim::SolidColorLayer::Create()),
url_bar_background_layer_(cc::slim::NinePatchLayer::Create()),
bitmap_layer_(cc::slim::UIResourceLayer::Create()),
progress_bar_layer_(cc::slim::SolidColorLayer::Create()),
progress_bar_background_layer_(cc::slim::SolidColorLayer::Create()),
progress_bar_static_background_layer_(
cc::slim::SolidColorLayer::Create()),
debug_layer_(cc::slim::SolidColorLayer::Create()) {
if (features::IsAndroidAnimatedProgressBarInVizEnabled()) {
// Parents are drawn before children. Children added first are drawn first.
// Layers that are drawn later will cover all layers drawn before it.
toolbar_background_layer_->SetIsDrawable(true);
toolbar_layers_->AddChild(toolbar_background_layer_);
url_bar_background_layer_->SetIsDrawable(true);
url_bar_background_layer_->SetFillCenter(true);
toolbar_layers_->AddChild(url_bar_background_layer_);
bitmap_layer_->SetIsDrawable(true);
toolbar_layers_->AddChild(bitmap_layer_);
progress_bar_static_background_layer_->SetIsDrawable(true);
progress_bar_static_background_layer_->SetHideLayerAndSubtree(true);
toolbar_layers_->AddChild(progress_bar_static_background_layer_);
layer_->AddChild(toolbar_layers_);
progress_bar_layer_->SetIsDrawable(true);
progress_bar_layer_->SetHideLayerAndSubtree(true);
progress_bar_layers_->AddChild(progress_bar_layer_);
progress_bar_background_layer_->SetIsDrawable(true);
progress_bar_background_layer_->SetHideLayerAndSubtree(true);
progress_bar_layers_->AddChild(progress_bar_background_layer_);
layer_->AddChild(progress_bar_layers_);
} else {
toolbar_background_layer_->SetIsDrawable(true);
layer_->AddChild(toolbar_background_layer_);
url_bar_background_layer_->SetIsDrawable(true);
url_bar_background_layer_->SetFillCenter(true);
layer_->AddChild(url_bar_background_layer_);
bitmap_layer_->SetIsDrawable(true);
layer_->AddChild(bitmap_layer_);
progress_bar_static_background_layer_->SetIsDrawable(true);
progress_bar_static_background_layer_->SetHideLayerAndSubtree(true);
layer_->AddChild(progress_bar_static_background_layer_);
progress_bar_background_layer_->SetIsDrawable(true);
progress_bar_background_layer_->SetHideLayerAndSubtree(true);
layer_->AddChild(progress_bar_background_layer_);
progress_bar_layer_->SetIsDrawable(true);
progress_bar_layer_->SetHideLayerAndSubtree(true);
layer_->AddChild(progress_bar_layer_);
}
debug_layer_->SetIsDrawable(true);
debug_layer_->SetBackgroundColor(SkColors::kGreen);
debug_layer_->SetOpacity(0.5f);
}
ToolbarLayer::~ToolbarLayer() = default;
} // namespace android