| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // 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/decoration_title.h" |
| |
| #include <android/bitmap.h> |
| |
| #include "base/i18n/rtl.h" |
| #include "base/logging.h" |
| #include "cc/layers/layer.h" |
| #include "cc/layers/ui_resource_layer.h" |
| #include "cc/resources/scoped_ui_resource.h" |
| #include "content/public/browser/android/compositor.h" |
| #include "ui/android/resources/resource_manager.h" |
| #include "ui/base/l10n/l10n_util_android.h" |
| #include "ui/gfx/android/java_bitmap.h" |
| #include "ui/gfx/geometry/vector3d_f.h" |
| |
| namespace android { |
| |
| DecorationTitle::DecorationTitle(ui::ResourceManager* resource_manager, |
| int title_resource_id, |
| int favicon_resource_id, |
| int spinner_resource_id, |
| int spinner_incognito_resource_id, |
| int fade_width, |
| int favicon_start_padding, |
| int favicon_end_padding, |
| bool is_incognito, |
| bool is_rtl) |
| : layer_(cc::Layer::Create()), |
| layer_opaque_(cc::UIResourceLayer::Create()), |
| layer_fade_(cc::UIResourceLayer::Create()), |
| layer_favicon_(cc::UIResourceLayer::Create()), |
| title_resource_id_(title_resource_id), |
| favicon_resource_id_(favicon_resource_id), |
| spinner_resource_id_(spinner_resource_id), |
| spinner_incognito_resource_id_(spinner_incognito_resource_id), |
| fade_width_(fade_width), |
| spinner_rotation_(0), |
| favicon_start_padding_(favicon_start_padding), |
| favicon_end_padding_(favicon_end_padding), |
| is_incognito_(is_incognito), |
| is_rtl_(is_rtl), |
| is_loading_(false), |
| transform_(new gfx::Transform()), |
| resource_manager_(resource_manager) { |
| layer_->AddChild(layer_favicon_); |
| layer_->AddChild(layer_opaque_); |
| layer_->AddChild(layer_fade_); |
| } |
| |
| DecorationTitle::~DecorationTitle() { |
| layer_->RemoveFromParent(); |
| } |
| |
| void DecorationTitle::SetResourceManager( |
| ui::ResourceManager* resource_manager) { |
| resource_manager_ = resource_manager; |
| } |
| |
| void DecorationTitle::Update(int title_resource_id, |
| int favicon_resource_id, |
| int fade_width, |
| int favicon_start_padding, |
| int favicon_end_padding, |
| bool is_incognito, |
| bool is_rtl) { |
| title_resource_id_ = title_resource_id; |
| favicon_resource_id_ = favicon_resource_id; |
| is_incognito_ = is_incognito; |
| is_rtl_ = is_rtl; |
| favicon_start_padding_ = favicon_start_padding; |
| favicon_end_padding_ = favicon_end_padding; |
| fade_width_ = fade_width; |
| } |
| |
| void DecorationTitle::SetFaviconResourceId(int favicon_resource_id) { |
| favicon_resource_id_ = favicon_resource_id; |
| } |
| |
| void DecorationTitle::SetUIResourceIds() { |
| ui::Resource* title_resource = resource_manager_->GetResource( |
| ui::ANDROID_RESOURCE_TYPE_DYNAMIC_BITMAP, title_resource_id_); |
| if (title_resource) { |
| layer_opaque_->SetUIResourceId(title_resource->ui_resource()->id()); |
| layer_fade_->SetUIResourceId(title_resource->ui_resource()->id()); |
| title_size_ = title_resource->size(); |
| } |
| |
| if (!is_loading_) { |
| ui::Resource* favicon_resource = resource_manager_->GetResource( |
| ui::ANDROID_RESOURCE_TYPE_DYNAMIC_BITMAP, favicon_resource_id_); |
| if (favicon_resource) { |
| layer_favicon_->SetUIResourceId(favicon_resource->ui_resource()->id()); |
| favicon_size_ = favicon_resource->size(); |
| } else { |
| layer_favicon_->SetUIResourceId(0); |
| } |
| layer_favicon_->SetTransform(gfx::Transform()); |
| } else { |
| int resource_id = |
| is_incognito_ ? spinner_incognito_resource_id_ : spinner_resource_id_; |
| |
| ui::Resource* spinner_resource = resource_manager_->GetResource( |
| ui::ANDROID_RESOURCE_TYPE_STATIC, resource_id); |
| |
| if (spinner_resource) |
| layer_favicon_->SetUIResourceId(spinner_resource->ui_resource()->id()); |
| |
| // Rotate about the center of the layer. |
| layer_favicon_->SetTransformOrigin( |
| gfx::Point3F(favicon_size_.width() / 2, favicon_size_.height() / 2, 0)); |
| } |
| |
| size_ = gfx::Size(title_size_.width() + favicon_size_.width(), |
| title_size_.height()); |
| } |
| |
| void DecorationTitle::SetIsLoading(bool is_loading) { |
| if (is_loading != is_loading_) { |
| is_loading_ = is_loading; |
| SetUIResourceIds(); |
| } |
| } |
| |
| void DecorationTitle::SetSpinnerRotation(float rotation) { |
| if (!is_loading_) |
| return; |
| float diff = rotation - spinner_rotation_; |
| spinner_rotation_ = rotation; |
| if (diff != 0) { |
| transform_->RotateAboutZAxis(diff); |
| } |
| layer_favicon_->SetTransform(*transform_.get()); |
| } |
| |
| void DecorationTitle::setOpacity(float opacity) { |
| layer_opaque_->SetOpacity(opacity); |
| layer_favicon_->SetOpacity(opacity); |
| layer_fade_->SetOpacity(opacity); |
| } |
| |
| void DecorationTitle::setBounds(const gfx::Size& bounds) { |
| layer_->SetBounds(gfx::Size(bounds.width(), size_.height())); |
| |
| if (bounds.GetArea() == 0.f) { |
| layer_->SetHideLayerAndSubtree(true); |
| return; |
| } |
| layer_->SetHideLayerAndSubtree(false); |
| |
| // Current implementation assumes there is always enough space |
| // to draw favicon and title fade. |
| |
| // Note that favicon positon and title aligning depends on the system locale, |
| // l10n_util::IsLayoutRtl(), while title starting and fade out direction |
| // depends on the title text locale (DecorationTitle::is_rtl_). |
| |
| bool sys_rtl = l10n_util::IsLayoutRtl(); |
| int favicon_space = |
| favicon_size_.width() + favicon_start_padding_ + favicon_end_padding_; |
| int title_space = std::max(0, bounds.width() - favicon_space - fade_width_); |
| int fade_space = std::max(0, bounds.width() - favicon_space - title_space); |
| |
| if (title_size_.width() <= title_space + fade_space) |
| title_space += fade_space; |
| |
| if (title_size_.width() <= title_space) |
| fade_space = 0.f; |
| |
| float favicon_offset_y = (size_.height() - favicon_size_.height()) / 2.f; |
| float title_offset_y = (size_.height() - title_size_.height()) / 2.f; |
| |
| // Step 1. Place favicon. |
| int favicon_x = favicon_start_padding_; |
| if (sys_rtl) { |
| favicon_x = bounds.width() - favicon_size_.width() - favicon_start_padding_; |
| } |
| layer_favicon_->SetIsDrawable(true); |
| layer_favicon_->SetBounds(favicon_size_); |
| layer_favicon_->SetPosition(gfx::PointF(favicon_x, favicon_offset_y)); |
| |
| // Step 2. Place the opaque title component. |
| if (title_space > 0.f) { |
| // Calculate the title position and size, taking into account both |
| // system and title RTL. |
| int width = std::min(title_space, title_size_.width()); |
| int x_offset = sys_rtl ? title_space - width : favicon_space; |
| int x = x_offset + (is_rtl_ ? fade_space : 0); |
| |
| // Calculate the UV coordinates taking into account title RTL. |
| float width_percentage = (float)width / title_size_.width(); |
| float u1 = is_rtl_ ? 1.f - width_percentage : 0.f; |
| float u2 = is_rtl_ ? 1.f : width_percentage; |
| |
| layer_opaque_->SetIsDrawable(true); |
| layer_opaque_->SetBounds(gfx::Size(width, title_size_.height())); |
| layer_opaque_->SetPosition(gfx::PointF(x, title_offset_y)); |
| layer_opaque_->SetUV(gfx::PointF(u1, 0.f), gfx::PointF(u2, 1.f)); |
| } else { |
| layer_opaque_->SetIsDrawable(false); |
| } |
| |
| // Step 3. Place the fade title component. |
| if (fade_space > 0.f) { |
| // Calculate the title position and size, taking into account both |
| // system and title RTL. |
| int x_offset = sys_rtl ? 0 : favicon_space; |
| int x = x_offset + (is_rtl_ ? 0 : title_space); |
| float title_amt = (float)title_space / title_size_.width(); |
| float fade_amt = (float)fade_space / title_size_.width(); |
| |
| // Calculate UV coordinates taking into account title RTL. |
| float u1 = is_rtl_ ? 1.f - title_amt - fade_amt : title_amt; |
| float u2 = is_rtl_ ? 1.f - title_amt : title_amt + fade_amt; |
| |
| // Calculate vertex alpha taking into account title RTL. |
| float max_alpha = (float)fade_space / fade_width_; |
| float a1 = is_rtl_ ? 0.f : max_alpha; |
| float a2 = is_rtl_ ? max_alpha : 0.f; |
| |
| layer_fade_->SetIsDrawable(true); |
| layer_fade_->SetBounds(gfx::Size(fade_space, title_size_.height())); |
| layer_fade_->SetPosition(gfx::PointF(x, title_offset_y)); |
| layer_fade_->SetUV(gfx::PointF(u1, 0.f), gfx::PointF(u2, 1.f)); |
| layer_fade_->SetVertexOpacity(a1, a1, a2, a2); |
| } else { |
| layer_fade_->SetIsDrawable(false); |
| } |
| } |
| |
| scoped_refptr<cc::Layer> DecorationTitle::layer() { |
| DCHECK(layer_.get()); |
| return layer_; |
| } |
| |
| } // namespace android |