Commit 38c60c13 authored by Christopher Lam's avatar Christopher Lam Committed by Commit Bot

[desktop-pwas] Render 'App name by example.com' string in window title.

This CL adds an extra string to the Desktop PWA window title that
denotes which app the window belongs to and the domain of the start URL.
The window title is painted such that the page title will elide first,
followed by the app name then the domain. Further work is required to
maintain this property for all languages.

Bug: 762401
Change-Id: Ibcc697b02fa643df9c2618ca0ef0249c6f887b64
Reviewed-on: https://chromium-review.googlesource.com/768601
Commit-Queue: calamity <calamity@chromium.org>
Reviewed-by: default avatarTrent Apted <tapted@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Cr-Commit-Position: refs/heads/master@{#517782}
parent 735b892f
...@@ -64,14 +64,6 @@ void TileRoundRect(gfx::Canvas* canvas, ...@@ -64,14 +64,6 @@ void TileRoundRect(gfx::Canvas* canvas,
canvas->DrawPath(path, flags); canvas->DrawPath(path, flags);
} }
// Returns the FontList to use for the title.
const gfx::FontList& GetTitleFontList() {
static const gfx::FontList* title_font_list =
new gfx::FontList(views::NativeWidgetAura::GetWindowTitleFontList());
ANNOTATE_LEAKING_OBJECT_PTR(title_font_list);
return *title_font_list;
}
} // namespace } // namespace
namespace ash { namespace ash {
...@@ -79,43 +71,38 @@ namespace ash { ...@@ -79,43 +71,38 @@ namespace ash {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// DefaultFrameHeader, public: // DefaultFrameHeader, public:
DefaultFrameHeader::DefaultFrameHeader(mojom::WindowStyle window_style) DefaultFrameHeader::DefaultFrameHeader(
views::Widget* frame,
views::View* header_view,
FrameCaptionButtonContainerView* caption_button_container,
FrameCaptionButton* back_button,
mojom::WindowStyle window_style)
: window_style_(window_style), : window_style_(window_style),
frame_(nullptr), frame_(frame),
view_(nullptr), view_(header_view),
back_button_(nullptr), back_button_(back_button),
left_header_view_(nullptr), left_header_view_(nullptr),
active_frame_color_(kDefaultFrameColor), active_frame_color_(kDefaultFrameColor),
inactive_frame_color_(kDefaultFrameColor), inactive_frame_color_(kDefaultFrameColor),
caption_button_container_(nullptr), caption_button_container_(caption_button_container),
painted_height_(0), painted_height_(0),
mode_(MODE_INACTIVE), mode_(MODE_INACTIVE),
initial_paint_(true), initial_paint_(true),
activation_animation_(new gfx::SlideAnimation(this)) {} activation_animation_(new gfx::SlideAnimation(this)) {
DefaultFrameHeader::~DefaultFrameHeader() {}
void DefaultFrameHeader::Init(
views::Widget* frame,
views::View* header_view,
FrameCaptionButtonContainerView* caption_button_container,
FrameCaptionButton* back_button) {
DCHECK(frame); DCHECK(frame);
DCHECK(header_view); DCHECK(header_view);
DCHECK(caption_button_container); DCHECK(caption_button_container);
frame_ = frame;
view_ = header_view;
caption_button_container_ = caption_button_container;
caption_button_container_->SetButtonSize( caption_button_container_->SetButtonSize(
GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON)); GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON));
UpdateAllButtonImages(); UpdateAllButtonImages();
UpdateBackButton(back_button);
} }
DefaultFrameHeader::~DefaultFrameHeader() = default;
int DefaultFrameHeader::GetMinimumHeaderWidth() const { int DefaultFrameHeader::GetMinimumHeaderWidth() const {
// Ensure we have enough space for the window icon and buttons. We allow // Ensure we have enough space for the window icon and buttons. We allow
// the title string to collapse to zero width. // the title string to collapse to zero width.
return GetTitleBounds().x() + return GetAvailableTitleBounds().x() +
caption_button_container_->GetMinimumSize().width(); caption_button_container_->GetMinimumSize().width();
} }
...@@ -220,7 +207,7 @@ void DefaultFrameHeader::SetHeaderHeightForPainting(int height) { ...@@ -220,7 +207,7 @@ void DefaultFrameHeader::SetHeaderHeightForPainting(int height) {
} }
void DefaultFrameHeader::SchedulePaintForTitle() { void DefaultFrameHeader::SchedulePaintForTitle() {
view_->SchedulePaintInRect(GetTitleBounds()); view_->SchedulePaintInRect(GetAvailableTitleBounds());
} }
void DefaultFrameHeader::SetPaintAsActive(bool paint_as_active) { void DefaultFrameHeader::SetPaintAsActive(bool paint_as_active) {
...@@ -253,6 +240,14 @@ bool DefaultFrameHeader::ShouldUseLightImages() const { ...@@ -253,6 +240,14 @@ bool DefaultFrameHeader::ShouldUseLightImages() const {
: active_frame_color_); : active_frame_color_);
} }
// static
const gfx::FontList& DefaultFrameHeader::GetTitleFontList() {
static const gfx::FontList* title_font_list =
new gfx::FontList(views::NativeWidgetAura::GetWindowTitleFontList());
ANNOTATE_LEAKING_OBJECT_PTR(title_font_list);
return *title_font_list;
}
void DefaultFrameHeader::UpdateLeftHeaderView(views::View* left_header_view) { void DefaultFrameHeader::UpdateLeftHeaderView(views::View* left_header_view) {
left_header_view_ = left_header_view; left_header_view_ = left_header_view;
} }
...@@ -301,11 +296,10 @@ void DefaultFrameHeader::PaintHighlightForInactiveRestoredWindow( ...@@ -301,11 +296,10 @@ void DefaultFrameHeader::PaintHighlightForInactiveRestoredWindow(
void DefaultFrameHeader::PaintTitleBar(gfx::Canvas* canvas) { void DefaultFrameHeader::PaintTitleBar(gfx::Canvas* canvas) {
// The window icon is painted by its own views::View. // The window icon is painted by its own views::View.
gfx::Rect title_bounds = GetTitleBounds(); gfx::Rect title_bounds = GetAvailableTitleBounds();
title_bounds.set_x(view_->GetMirroredXForRect(title_bounds)); title_bounds.set_x(view_->GetMirroredXForRect(title_bounds));
canvas->DrawStringRectWithFlags( canvas->DrawStringRect(frame_->widget_delegate()->GetWindowTitle(),
frame_->widget_delegate()->GetWindowTitle(), GetTitleFontList(), GetTitleFontList(), GetTitleColor(), title_bounds);
GetTitleColor(), title_bounds, gfx::Canvas::NO_SUBPIXEL_RENDERING);
} }
void DefaultFrameHeader::PaintHeaderContentSeparator(gfx::Canvas* canvas) { void DefaultFrameHeader::PaintHeaderContentSeparator(gfx::Canvas* canvas) {
...@@ -347,10 +341,10 @@ gfx::Rect DefaultFrameHeader::GetLocalBounds() const { ...@@ -347,10 +341,10 @@ gfx::Rect DefaultFrameHeader::GetLocalBounds() const {
return gfx::Rect(view_->width(), painted_height_); return gfx::Rect(view_->width(), painted_height_);
} }
gfx::Rect DefaultFrameHeader::GetTitleBounds() const { gfx::Rect DefaultFrameHeader::GetAvailableTitleBounds() const {
views::View* left_view = left_header_view_ ? left_header_view_ : back_button_; views::View* left_view = left_header_view_ ? left_header_view_ : back_button_;
return FrameHeaderUtil::GetTitleBounds(left_view, caption_button_container_, return FrameHeaderUtil::GetAvailableTitleBounds(
GetTitleFontList()); left_view, caption_button_container_, GetTitleFontList());
} }
bool DefaultFrameHeader::UsesCustomFrameColors() const { bool DefaultFrameHeader::UsesCustomFrameColors() const {
......
...@@ -17,9 +17,11 @@ ...@@ -17,9 +17,11 @@
#include "ui/gfx/animation/animation_delegate.h" #include "ui/gfx/animation/animation_delegate.h"
namespace gfx { namespace gfx {
class FontList;
class Rect; class Rect;
class SlideAnimation; class SlideAnimation;
} // namespace gfx } // namespace gfx
namespace views { namespace views {
class View; class View;
class Widget; class Widget;
...@@ -33,16 +35,15 @@ class FrameCaptionButtonContainerView; ...@@ -33,16 +35,15 @@ class FrameCaptionButtonContainerView;
class ASH_EXPORT DefaultFrameHeader : public FrameHeader, class ASH_EXPORT DefaultFrameHeader : public FrameHeader,
public gfx::AnimationDelegate { public gfx::AnimationDelegate {
public: public:
explicit DefaultFrameHeader( // DefaultFrameHeader does not take ownership of any of the parameters.
DefaultFrameHeader(
views::Widget* frame,
views::View* header_view,
FrameCaptionButtonContainerView* caption_button_container,
FrameCaptionButton* back_button,
mojom::WindowStyle window_style = mojom::WindowStyle::DEFAULT); mojom::WindowStyle window_style = mojom::WindowStyle::DEFAULT);
~DefaultFrameHeader() override; ~DefaultFrameHeader() override;
// DefaultFrameHeader does not take ownership of any of the parameters.
void Init(views::Widget* frame,
views::View* header_view,
FrameCaptionButtonContainerView* caption_button_container,
FrameCaptionButton* back_button);
// FrameHeader overrides: // FrameHeader overrides:
int GetMinimumHeaderWidth() const override; int GetMinimumHeaderWidth() const override;
void PaintHeader(gfx::Canvas* canvas, Mode mode) override; void PaintHeader(gfx::Canvas* canvas, Mode mode) override;
...@@ -73,6 +74,18 @@ class ASH_EXPORT DefaultFrameHeader : public FrameHeader, ...@@ -73,6 +74,18 @@ class ASH_EXPORT DefaultFrameHeader : public FrameHeader,
// background of the frame is dark. // background of the frame is dark.
bool ShouldUseLightImages() const; bool ShouldUseLightImages() const;
protected:
// Returns the FontList to use for the title.
static const gfx::FontList& GetTitleFontList();
// Paints the title bar, primarily the title string.
virtual void PaintTitleBar(gfx::Canvas* canvas);
// Returns the bounds for the title.
gfx::Rect GetAvailableTitleBounds() const;
views::View* view() { return view_; }
private: private:
FRIEND_TEST_ALL_PREFIXES(DefaultFrameHeaderTest, BackButtonAlignment); FRIEND_TEST_ALL_PREFIXES(DefaultFrameHeaderTest, BackButtonAlignment);
FRIEND_TEST_ALL_PREFIXES(DefaultFrameHeaderTest, TitleIconAlignment); FRIEND_TEST_ALL_PREFIXES(DefaultFrameHeaderTest, TitleIconAlignment);
...@@ -85,9 +98,6 @@ class ASH_EXPORT DefaultFrameHeader : public FrameHeader, ...@@ -85,9 +98,6 @@ class ASH_EXPORT DefaultFrameHeader : public FrameHeader,
// windows. // windows.
void PaintHighlightForInactiveRestoredWindow(gfx::Canvas* canvas); void PaintHighlightForInactiveRestoredWindow(gfx::Canvas* canvas);
// Paints the title bar, primarily the title string.
void PaintTitleBar(gfx::Canvas* canvas);
// Paints the header/content separator. // Paints the header/content separator.
void PaintHeaderContentSeparator(gfx::Canvas* canvas); void PaintHeaderContentSeparator(gfx::Canvas* canvas);
...@@ -102,9 +112,6 @@ class ASH_EXPORT DefaultFrameHeader : public FrameHeader, ...@@ -102,9 +112,6 @@ class ASH_EXPORT DefaultFrameHeader : public FrameHeader,
// same width as |view_|. // same width as |view_|.
gfx::Rect GetLocalBounds() const; gfx::Rect GetLocalBounds() const;
// Returns the bounds for the title.
gfx::Rect GetTitleBounds() const;
// Returns whether the frame uses custom frame coloring. // Returns whether the frame uses custom frame coloring.
bool UsesCustomFrameColors() const; bool UsesCustomFrameColors() const;
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/views/window/non_client_view.h" #include "ui/views/window/non_client_view.h"
using ash::FrameHeader;
using views::NonClientFrameView; using views::NonClientFrameView;
using views::Widget; using views::Widget;
...@@ -26,18 +25,17 @@ using DefaultFrameHeaderTest = AshTestBase; ...@@ -26,18 +25,17 @@ using DefaultFrameHeaderTest = AshTestBase;
TEST_F(DefaultFrameHeaderTest, TitleIconAlignment) { TEST_F(DefaultFrameHeaderTest, TitleIconAlignment) {
std::unique_ptr<Widget> w = CreateTestWidget( std::unique_ptr<Widget> w = CreateTestWidget(
nullptr, kShellWindowId_DefaultContainer, gfx::Rect(1, 2, 3, 4)); nullptr, kShellWindowId_DefaultContainer, gfx::Rect(1, 2, 3, 4));
ash::FrameCaptionButtonContainerView container(w.get()); FrameCaptionButtonContainerView container(w.get());
views::StaticSizedView window_icon(gfx::Size(16, 16)); views::StaticSizedView window_icon(gfx::Size(16, 16));
window_icon.SetBounds(0, 0, 16, 16); window_icon.SetBounds(0, 0, 16, 16);
w->SetBounds(gfx::Rect(0, 0, 500, 500)); w->SetBounds(gfx::Rect(0, 0, 500, 500));
w->Show(); w->Show();
DefaultFrameHeader frame_header; DefaultFrameHeader frame_header(w.get(), w->non_client_view()->frame_view(),
frame_header.Init(w.get(), w->non_client_view()->frame_view(), &container, &container, nullptr);
nullptr);
frame_header.UpdateLeftHeaderView(&window_icon); frame_header.UpdateLeftHeaderView(&window_icon);
frame_header.LayoutHeader(); frame_header.LayoutHeader();
gfx::Rect title_bounds = frame_header.GetTitleBounds(); gfx::Rect title_bounds = frame_header.GetAvailableTitleBounds();
EXPECT_EQ(window_icon.bounds().CenterPoint().y(), EXPECT_EQ(window_icon.bounds().CenterPoint().y(),
title_bounds.CenterPoint().y()); title_bounds.CenterPoint().y());
} }
...@@ -45,15 +43,14 @@ TEST_F(DefaultFrameHeaderTest, TitleIconAlignment) { ...@@ -45,15 +43,14 @@ TEST_F(DefaultFrameHeaderTest, TitleIconAlignment) {
TEST_F(DefaultFrameHeaderTest, BackButtonAlignment) { TEST_F(DefaultFrameHeaderTest, BackButtonAlignment) {
std::unique_ptr<Widget> w = CreateTestWidget( std::unique_ptr<Widget> w = CreateTestWidget(
nullptr, kShellWindowId_DefaultContainer, gfx::Rect(1, 2, 3, 4)); nullptr, kShellWindowId_DefaultContainer, gfx::Rect(1, 2, 3, 4));
ash::FrameCaptionButtonContainerView container(w.get()); FrameCaptionButtonContainerView container(w.get());
ash::FrameBackButton back; FrameBackButton back;
DefaultFrameHeader frame_header; DefaultFrameHeader frame_header(w.get(), w->non_client_view()->frame_view(),
frame_header.Init(w.get(), w->non_client_view()->frame_view(), &container, &container, nullptr);
nullptr);
frame_header.UpdateBackButton(&back); frame_header.UpdateBackButton(&back);
frame_header.LayoutHeader(); frame_header.LayoutHeader();
gfx::Rect title_bounds = frame_header.GetTitleBounds(); gfx::Rect title_bounds = frame_header.GetAvailableTitleBounds();
// The back button should be positioned at the left edge, and // The back button should be positioned at the left edge, and
// vertically centered. // vertically centered.
EXPECT_EQ(back.bounds().CenterPoint().y(), title_bounds.CenterPoint().y()); EXPECT_EQ(back.bounds().CenterPoint().y(), title_bounds.CenterPoint().y());
...@@ -64,15 +61,14 @@ TEST_F(DefaultFrameHeaderTest, BackButtonAlignment) { ...@@ -64,15 +61,14 @@ TEST_F(DefaultFrameHeaderTest, BackButtonAlignment) {
TEST_F(DefaultFrameHeaderTest, LightIcons) { TEST_F(DefaultFrameHeaderTest, LightIcons) {
std::unique_ptr<Widget> w = CreateTestWidget( std::unique_ptr<Widget> w = CreateTestWidget(
nullptr, kShellWindowId_DefaultContainer, gfx::Rect(1, 2, 3, 4)); nullptr, kShellWindowId_DefaultContainer, gfx::Rect(1, 2, 3, 4));
ash::FrameCaptionButtonContainerView container(w.get()); FrameCaptionButtonContainerView container(w.get());
views::StaticSizedView window_icon(gfx::Size(16, 16)); views::StaticSizedView window_icon(gfx::Size(16, 16));
window_icon.SetBounds(0, 0, 16, 16); window_icon.SetBounds(0, 0, 16, 16);
w->SetBounds(gfx::Rect(0, 0, 500, 500)); w->SetBounds(gfx::Rect(0, 0, 500, 500));
w->Show(); w->Show();
DefaultFrameHeader frame_header; DefaultFrameHeader frame_header(w.get(), w->non_client_view()->frame_view(),
frame_header.Init(w.get(), w->non_client_view()->frame_view(), &container, &container, nullptr);
nullptr);
// Check by default light icons are not used. // Check by default light icons are not used.
frame_header.mode_ = FrameHeader::MODE_ACTIVE; frame_header.mode_ = FrameHeader::MODE_ACTIVE;
......
...@@ -59,7 +59,7 @@ int FrameHeaderUtil::GetThemeBackgroundXInset() { ...@@ -59,7 +59,7 @@ int FrameHeaderUtil::GetThemeBackgroundXInset() {
} }
// static // static
gfx::Rect FrameHeaderUtil::GetTitleBounds( gfx::Rect FrameHeaderUtil::GetAvailableTitleBounds(
const views::View* left_view, const views::View* left_view,
const views::View* right_view, const views::View* right_view,
const gfx::FontList& title_font_list) { const gfx::FontList& title_font_list) {
......
...@@ -34,12 +34,13 @@ class ASH_EXPORT FrameHeaderUtil { ...@@ -34,12 +34,13 @@ class ASH_EXPORT FrameHeaderUtil {
// the window. // the window.
static int GetThemeBackgroundXInset(); static int GetThemeBackgroundXInset();
// Returns the bounds for the header's title given the views to the left and // Returns the available bounds for the header's title given the views to the
// right of the title, and the font used. // left and right of the title, and the font used. |left_view| should be null
// |left_view| should be NULL if there is no view to the left of the title. // if there is no view to the left of the title.
static gfx::Rect GetTitleBounds(const views::View* left_view, static gfx::Rect GetAvailableTitleBounds(
const views::View* right_view, const views::View* left_view,
const gfx::FontList& title_font_list); const views::View* right_view,
const gfx::FontList& title_font_list);
// Returns true if the header for |widget| can animate to new visuals when the // Returns true if the header for |widget| can animate to new visuals when the
// widget's activation changes. Returns false if the header should switch to // widget's activation changes. Returns false if the header should switch to
......
...@@ -21,7 +21,6 @@ namespace ash { ...@@ -21,7 +21,6 @@ namespace ash {
HeaderView::HeaderView(views::Widget* target_widget, HeaderView::HeaderView(views::Widget* target_widget,
mojom::WindowStyle window_style) mojom::WindowStyle window_style)
: target_widget_(target_widget), : target_widget_(target_widget),
frame_header_(std::make_unique<DefaultFrameHeader>(window_style)),
avatar_icon_(nullptr), avatar_icon_(nullptr),
caption_button_container_(nullptr), caption_button_container_(nullptr),
fullscreen_visible_fraction_(0), fullscreen_visible_fraction_(0),
...@@ -31,7 +30,8 @@ HeaderView::HeaderView(views::Widget* target_widget, ...@@ -31,7 +30,8 @@ HeaderView::HeaderView(views::Widget* target_widget,
caption_button_container_->UpdateSizeButtonVisibility(); caption_button_container_->UpdateSizeButtonVisibility();
AddChildView(caption_button_container_); AddChildView(caption_button_container_);
frame_header_->Init(target_widget_, this, caption_button_container_, nullptr); frame_header_ = std::make_unique<DefaultFrameHeader>(
target_widget_, this, caption_button_container_, nullptr, window_style);
Shell::Get()->tablet_mode_controller()->AddObserver(this); Shell::Get()->tablet_mode_controller()->AddObserver(this);
} }
......
...@@ -48,14 +48,13 @@ const char* PanelFrameView::GetClassName() const { ...@@ -48,14 +48,13 @@ const char* PanelFrameView::GetClassName() const {
} }
void PanelFrameView::InitFrameHeader() { void PanelFrameView::InitFrameHeader() {
frame_header_.reset(new DefaultFrameHeader);
GetWidgetWindow()->SetProperty(aura::client::kTopViewColor,
frame_header_->GetInactiveFrameColor());
caption_button_container_ = new FrameCaptionButtonContainerView(frame_); caption_button_container_ = new FrameCaptionButtonContainerView(frame_);
AddChildView(caption_button_container_); AddChildView(caption_button_container_);
frame_header_->Init(frame_, this, caption_button_container_, nullptr); frame_header_ = std::make_unique<DefaultFrameHeader>(
frame_, this, caption_button_container_, nullptr);
GetWidgetWindow()->SetProperty(aura::client::kTopViewColor,
frame_header_->GetInactiveFrameColor());
if (frame_->widget_delegate()->ShouldShowWindowIcon()) { if (frame_->widget_delegate()->ShouldShowWindowIcon()) {
window_icon_ = new views::ImageView(); window_icon_ = new views::ImageView();
......
...@@ -4571,6 +4571,10 @@ Keep your key file in a safe place. You will need it to create new versions of y ...@@ -4571,6 +4571,10 @@ Keep your key file in a safe place. You will need it to create new versions of y
</message> </message>
</if> </if>
<message name="IDS_HOSTED_APP_NAME_AND_DOMAIN" desc="The string that is always displayed in the window title in Hosted App app windows.">
<ph name="APP_NAME">$1<ex>GMail</ex></ph> by <ph name="SITE_ORIGIN">$2<ex>google.com</ex></ph>
</message>
<!-- Components --> <!-- Components -->
<message name="IDS_COMPONENTS_TITLE" desc="Title for the chrome://components page."> <message name="IDS_COMPONENTS_TITLE" desc="Title for the chrome://components page.">
Components Components
......
...@@ -1302,6 +1302,8 @@ split_static_library("ui") { ...@@ -1302,6 +1302,8 @@ split_static_library("ui") {
"views/frame/browser_frame_header_ash.h", "views/frame/browser_frame_header_ash.h",
"views/frame/browser_non_client_frame_view_ash.cc", "views/frame/browser_non_client_frame_view_ash.cc",
"views/frame/browser_non_client_frame_view_ash.h", "views/frame/browser_non_client_frame_view_ash.h",
"views/frame/hosted_app_frame_header_ash.cc",
"views/frame/hosted_app_frame_header_ash.h",
"views/frame/immersive_context_mus.cc", "views/frame/immersive_context_mus.cc",
"views/frame/immersive_context_mus.h", "views/frame/immersive_context_mus.h",
"views/frame/immersive_handler_factory_mus.cc", "views/frame/immersive_handler_factory_mus.cc",
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h" #include "extensions/common/extension.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "ui/gfx/favicon_size.h" #include "ui/gfx/favicon_size.h"
#include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -78,9 +79,7 @@ HostedAppBrowserController::HostedAppBrowserController(Browser* browser) ...@@ -78,9 +79,7 @@ HostedAppBrowserController::HostedAppBrowserController(Browser* browser)
HostedAppBrowserController::~HostedAppBrowserController() {} HostedAppBrowserController::~HostedAppBrowserController() {}
bool HostedAppBrowserController::ShouldShowLocationBar() const { bool HostedAppBrowserController::ShouldShowLocationBar() const {
const Extension* extension = const Extension* extension = GetExtension();
ExtensionRegistry::Get(browser_->profile())->GetExtensionById(
extension_id_, ExtensionRegistry::EVERYTHING);
const content::WebContents* web_contents = const content::WebContents* web_contents =
browser_->tab_strip_model()->GetActiveWebContents(); browser_->tab_strip_model()->GetActiveWebContents();
...@@ -154,11 +153,29 @@ base::Optional<SkColor> HostedAppBrowserController::GetThemeColor() const { ...@@ -154,11 +153,29 @@ base::Optional<SkColor> HostedAppBrowserController::GetThemeColor() const {
} }
base::string16 HostedAppBrowserController::GetTitle() const { base::string16 HostedAppBrowserController::GetTitle() const {
content::NavigationEntry* entry = browser_->tab_strip_model() content::WebContents* web_contents =
->GetActiveWebContents() browser_->tab_strip_model()->GetActiveWebContents();
->GetController() if (!web_contents)
.GetVisibleEntry(); return base::string16();
content::NavigationEntry* entry =
web_contents->GetController().GetVisibleEntry();
return entry ? entry->GetTitle() : base::string16(); return entry ? entry->GetTitle() : base::string16();
} }
const Extension* HostedAppBrowserController::GetExtension() const {
return ExtensionRegistry::Get(browser_->profile())
->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
}
std::string HostedAppBrowserController::GetAppShortName() const {
return GetExtension()->short_name();
}
std::string HostedAppBrowserController::GetDomainAndRegistry() const {
return net::registry_controlled_domains::GetDomainAndRegistry(
AppLaunchInfo::GetLaunchWebURL(GetExtension()),
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
}
} // namespace extensions } // namespace extensions
...@@ -19,6 +19,8 @@ class ImageSkia; ...@@ -19,6 +19,8 @@ class ImageSkia;
namespace extensions { namespace extensions {
class Extension;
// Class to encapsulate logic to control the browser UI for hosted apps. // Class to encapsulate logic to control the browser UI for hosted apps.
class HostedAppBrowserController { class HostedAppBrowserController {
public: public:
...@@ -52,7 +54,16 @@ class HostedAppBrowserController { ...@@ -52,7 +54,16 @@ class HostedAppBrowserController {
// Returns the title to be displayed in the window title bar. // Returns the title to be displayed in the window title bar.
base::string16 GetTitle() const; base::string16 GetTitle() const;
// Gets the short name of the app.
std::string GetAppShortName() const;
// Gets the domain and registry of the app start url (e.g example.com.au).
std::string GetDomainAndRegistry() const;
private: private:
// Gets the extension for this controller.
const Extension* GetExtension() const;
Browser* browser_; Browser* browser_;
const std::string extension_id_; const std::string extension_id_;
......
...@@ -311,6 +311,6 @@ gfx::Rect BrowserFrameHeaderAsh::GetPaintedBounds() const { ...@@ -311,6 +311,6 @@ gfx::Rect BrowserFrameHeaderAsh::GetPaintedBounds() const {
gfx::Rect BrowserFrameHeaderAsh::GetTitleBounds() const { gfx::Rect BrowserFrameHeaderAsh::GetTitleBounds() const {
views::View* left_view = window_icon_ ? window_icon_ : back_button_; views::View* left_view = window_icon_ ? window_icon_ : back_button_;
return ash::FrameHeaderUtil::GetTitleBounds( return ash::FrameHeaderUtil::GetAvailableTitleBounds(
left_view, caption_button_container_, BrowserFrame::GetTitleFontList()); left_view, caption_button_container_, BrowserFrame::GetTitleFontList());
} }
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "chrome/browser/ui/views/frame/browser_frame_header_ash.h" #include "chrome/browser/ui/views/frame/browser_frame_header_ash.h"
#include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/hosted_app_button_container.h" #include "chrome/browser/ui/views/frame/hosted_app_button_container.h"
#include "chrome/browser/ui/views/frame/hosted_app_frame_header_ash.h"
#include "chrome/browser/ui/views/frame/immersive_mode_controller.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
#include "chrome/browser/ui/views/profiles/profile_indicator_icon.h" #include "chrome/browser/ui/views/profiles/profile_indicator_icon.h"
#include "chrome/browser/ui/views/tab_icon_view.h" #include "chrome/browser/ui/views/tab_icon_view.h"
...@@ -108,43 +109,7 @@ void BrowserNonClientFrameViewAsh::Init() { ...@@ -108,43 +109,7 @@ void BrowserNonClientFrameViewAsh::Init() {
// TODO(oshima): Update the back button state. // TODO(oshima): Update the back button state.
} }
if (UsePackagedAppHeaderStyle()) { frame_header_ = CreateFrameHeader();
ash::DefaultFrameHeader* frame_header = new ash::DefaultFrameHeader;
frame_header_.reset(frame_header);
frame_header->Init(frame(), this, caption_button_container_, back_button_);
if (window_icon_)
frame_header->UpdateLeftHeaderView(window_icon_);
extensions::HostedAppBrowserController* app_controller =
browser->hosted_app_controller();
if (app_controller) {
// Hosted apps apply a theme color if specified by the extension.
base::Optional<SkColor> theme_color = app_controller->GetThemeColor();
if (theme_color) {
SkColor opaque_theme_color =
SkColorSetA(theme_color.value(), SK_AlphaOPAQUE);
frame_header->SetFrameColors(opaque_theme_color, opaque_theme_color);
}
if (extensions::HostedAppBrowserController::
IsForExperimentalHostedAppBrowser(browser)) {
SkColor text_color = frame_header->GetTitleColor();
hosted_app_button_container_ = new HostedAppButtonContainer(
browser_view(), text_color,
SkColorSetA(text_color,
255 * ash::kInactiveFrameButtonIconAlphaRatio));
caption_button_container_->AddChildViewAt(hosted_app_button_container_,
0);
}
} else if (!browser->is_app()) {
// For non app (i.e. WebUI) windows (e.g. Settings) use MD frame color.
frame_header->SetFrameColors(kMdWebUIFrameColor, kMdWebUIFrameColor);
}
} else {
BrowserFrameHeaderAsh* frame_header = new BrowserFrameHeaderAsh;
frame_header_.reset(frame_header);
frame_header->Init(frame(), browser_view(), this, window_icon_,
caption_button_container_, back_button_);
}
if (browser->is_app()) { if (browser->is_app()) {
frame()->GetNativeWindow()->SetProperty( frame()->GetNativeWindow()->SetProperty(
...@@ -529,3 +494,42 @@ void BrowserNonClientFrameViewAsh::OnOverviewModeChanged(bool in_overview) { ...@@ -529,3 +494,42 @@ void BrowserNonClientFrameViewAsh::OnOverviewModeChanged(bool in_overview) {
// Schedule a paint to show or hide the header. // Schedule a paint to show or hide the header.
SchedulePaint(); SchedulePaint();
} }
std::unique_ptr<ash::FrameHeader>
BrowserNonClientFrameViewAsh::CreateFrameHeader() {
Browser* browser = browser_view()->browser();
if (!UsePackagedAppHeaderStyle()) {
auto browser_frame_header = std::make_unique<BrowserFrameHeaderAsh>();
browser_frame_header->Init(frame(), browser_view(), this, window_icon_,
caption_button_container_, back_button_);
return browser_frame_header;
}
std::unique_ptr<ash::DefaultFrameHeader> default_frame_header = nullptr;
if (extensions::HostedAppBrowserController::IsForExperimentalHostedAppBrowser(
browser)) {
default_frame_header = std::make_unique<HostedAppFrameHeaderAsh>(
browser->hosted_app_controller(), frame(), this,
caption_button_container_, back_button_);
// Add the container for extra hosted app buttons (e.g app menu button).
SkColor text_color = default_frame_header->GetTitleColor();
hosted_app_button_container_ = new HostedAppButtonContainer(
browser_view(), text_color,
SkColorSetA(text_color, 255 * ash::kInactiveFrameButtonIconAlphaRatio));
caption_button_container_->AddChildViewAt(hosted_app_button_container_, 0);
} else {
default_frame_header = std::make_unique<ash::DefaultFrameHeader>(
frame(), this, caption_button_container_, back_button_);
if (!browser->is_app()) {
// For non app (i.e. WebUI) windows (e.g. Settings) use MD frame color.
default_frame_header->SetFrameColors(kMdWebUIFrameColor,
kMdWebUIFrameColor);
}
}
if (window_icon_)
default_frame_header->UpdateLeftHeaderView(window_icon_);
return default_frame_header;
}
...@@ -115,6 +115,9 @@ class BrowserNonClientFrameViewAsh : public BrowserNonClientFrameView, ...@@ -115,6 +115,9 @@ class BrowserNonClientFrameViewAsh : public BrowserNonClientFrameView,
// ends. // ends.
void OnOverviewModeChanged(bool in_overview); void OnOverviewModeChanged(bool in_overview);
// Creates the frame header for the browser window.
std::unique_ptr<ash::FrameHeader> CreateFrameHeader();
// View which contains the window controls. // View which contains the window controls.
ash::FrameCaptionButtonContainerView* caption_button_container_; ash::FrameCaptionButtonContainerView* caption_button_container_;
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include "ash/ash_constants.h" #include "ash/ash_constants.h"
#include "ash/frame/caption_buttons/frame_caption_button.h" #include "ash/frame/caption_buttons/frame_caption_button.h"
#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
#include "ash/frame/default_frame_header.h"
#include "ash/frame/frame_header.h" #include "ash/frame/frame_header.h"
#include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/ash_switches.h"
#include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
...@@ -35,6 +34,7 @@ ...@@ -35,6 +34,7 @@
#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
#include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/hosted_app_button_container.h" #include "chrome/browser/ui/views/frame/hosted_app_button_container.h"
#include "chrome/browser/ui/views/frame/hosted_app_frame_header_ash.h"
#include "chrome/browser/ui/views/frame/immersive_mode_controller.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
#include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
#include "chrome/browser/ui/views/profiles/profile_indicator_icon.h" #include "chrome/browser/ui/views/profiles/profile_indicator_icon.h"
...@@ -480,22 +480,45 @@ IN_PROC_BROWSER_TEST_F(HostedAppNonClientFrameViewAshTest, HostedAppFrame) { ...@@ -480,22 +480,45 @@ IN_PROC_BROWSER_TEST_F(HostedAppNonClientFrameViewAshTest, HostedAppFrame) {
static_cast<BrowserNonClientFrameViewAsh*>( static_cast<BrowserNonClientFrameViewAsh*>(
browser_view->frame()->GetFrameView()); browser_view->frame()->GetFrameView());
EXPECT_TRUE(frame_view->hosted_app_button_container_->visible()); HostedAppButtonContainer* button_container =
frame_view->hosted_app_button_container_;
EXPECT_TRUE(button_container->visible());
// Ensure the theme color is set. // Ensure the theme color is set.
auto* frame_header = auto* frame_header =
static_cast<ash::DefaultFrameHeader*>(frame_view->frame_header_.get()); static_cast<HostedAppFrameHeaderAsh*>(frame_view->frame_header_.get());
EXPECT_EQ(SK_ColorBLUE, frame_header->GetActiveFrameColor()); EXPECT_EQ(SK_ColorBLUE, frame_header->GetActiveFrameColor());
EXPECT_EQ(SK_ColorBLUE, frame_header->GetInactiveFrameColor()); EXPECT_EQ(SK_ColorBLUE, frame_header->GetInactiveFrameColor());
EXPECT_EQ(SK_ColorWHITE, button_container->active_icon_color_);
// Show the menu. // Show the menu.
HostedAppButtonContainer::AppMenuButton* menu_button = HostedAppButtonContainer::AppMenuButton* menu_button =
frame_view->hosted_app_button_container_->app_menu_button_; button_container->app_menu_button_;
ui::MouseEvent e(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::MouseEvent e(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
menu_button->OnMousePressed(e); menu_button->OnMousePressed(e);
EXPECT_TRUE(menu_button->menu()->IsShowing()); EXPECT_TRUE(menu_button->menu()->IsShowing());
// The app and domain should render next to the window title.
frame_header->LayoutRenderTexts(gfx::Rect(300, 30), 100, 100);
EXPECT_EQ(gfx::Rect(100, 30),
frame_header->title_render_text_->display_rect());
EXPECT_EQ(gfx::Rect(100, 0, 100, 30),
frame_header->app_and_domain_render_text_->display_rect());
// The title should prefer truncating the window title.
frame_header->LayoutRenderTexts(gfx::Rect(300, 30), 250, 100);
EXPECT_EQ(gfx::Rect(200, 30),
frame_header->title_render_text_->display_rect());
EXPECT_EQ(gfx::Rect(200, 0, 100, 30),
frame_header->app_and_domain_render_text_->display_rect());
// The app and domain should be clipped to the available title bounds.
frame_header->LayoutRenderTexts(gfx::Rect(60, 30), 250, 100);
EXPECT_EQ(gfx::Rect(0, 30), frame_header->title_render_text_->display_rect());
EXPECT_EQ(gfx::Rect(60, 30),
frame_header->app_and_domain_render_text_->display_rect());
} }
namespace { namespace {
......
// Copyright 2017 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/ui/views/frame/hosted_app_frame_header_ash.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
#include "chrome/grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/render_text.h"
#include "ui/views/view.h"
HostedAppFrameHeaderAsh::HostedAppFrameHeaderAsh(
extensions::HostedAppBrowserController* app_controller,
views::Widget* frame,
views::View* header_view,
ash::FrameCaptionButtonContainerView* caption_button_container,
ash::FrameCaptionButton* back_button)
: DefaultFrameHeader(frame,
header_view,
caption_button_container,
back_button),
app_controller_(app_controller),
app_name_(base::UTF8ToUTF16(app_controller->GetAppShortName())),
app_and_domain_(l10n_util::GetStringFUTF16(
IDS_HOSTED_APP_NAME_AND_DOMAIN,
app_name_,
base::UTF8ToUTF16(app_controller->GetDomainAndRegistry()))) {
// Hosted apps apply a theme color if specified by the extension.
base::Optional<SkColor> theme_color = app_controller->GetThemeColor();
if (theme_color) {
SkColor opaque_theme_color =
SkColorSetA(theme_color.value(), SK_AlphaOPAQUE);
SetFrameColors(opaque_theme_color, opaque_theme_color);
}
title_render_text_ = CreateRenderText();
app_and_domain_render_text_ = CreateRenderText();
app_and_domain_render_text_->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
}
HostedAppFrameHeaderAsh::~HostedAppFrameHeaderAsh() {}
std::unique_ptr<gfx::RenderText> HostedAppFrameHeaderAsh::CreateRenderText() {
std::unique_ptr<gfx::RenderText> render_text(
gfx::RenderText::CreateInstance());
render_text->SetFontList(GetTitleFontList());
render_text->SetCursorEnabled(false);
render_text->SetColor(GetTitleColor());
render_text->SetElideBehavior(gfx::FADE_TAIL);
return render_text;
}
void HostedAppFrameHeaderAsh::UpdateRenderTexts() {
// TODO(calamity): Investigate localization implications of using a separator
// like this.
constexpr char kSeparator[] = " | ";
// If the title matches the app name, don't render the title.
base::string16 title = app_controller_->GetTitle();
if (title == app_name_)
title = base::string16();
// Add a separator if the title isn't empty.
app_and_domain_render_text_->SetText(
title.empty() ? app_and_domain_
: base::ASCIIToUTF16(kSeparator) + app_and_domain_);
title_render_text_->SetText(title);
}
void HostedAppFrameHeaderAsh::LayoutRenderTexts(
const gfx::Rect& available_title_bounds,
int title_width,
int app_and_domain_width) {
// The title is either its own width if it fits, or the space remaining
// after rendering the app and domain (which may be negative, but gets clamped
// to 0).
gfx::Rect title_bounds = available_title_bounds;
title_bounds.set_width(
std::min(title_bounds.width() - app_and_domain_width, title_width));
title_bounds.set_x(view()->GetMirroredXForRect(title_bounds));
title_render_text_->SetDisplayRect(title_bounds);
// The app and domain are placed to the right of the title and clipped to the
// original title bounds. This string is given full width whenever possible.
gfx::Rect app_and_domain_bounds = available_title_bounds;
app_and_domain_bounds.set_x(title_bounds.right());
app_and_domain_bounds.set_width(app_and_domain_width);
app_and_domain_bounds.Intersect(available_title_bounds);
app_and_domain_bounds.set_x(
view()->GetMirroredXForRect(app_and_domain_bounds));
app_and_domain_render_text_->SetDisplayRect(app_and_domain_bounds);
}
void HostedAppFrameHeaderAsh::PaintTitleBar(gfx::Canvas* canvas) {
title_render_text_->Draw(canvas);
app_and_domain_render_text_->Draw(canvas);
}
// TODO(calamity): Make this elide behavior more sophisticated in handling other
// possible translations and languages (the domain should always render).
void HostedAppFrameHeaderAsh::LayoutHeader() {
DefaultFrameHeader::LayoutHeader();
// We only need to recalculate the strings when the window title changes, and
// that causes the NonClientView to Layout(), which calls into us here.
UpdateRenderTexts();
LayoutRenderTexts(GetAvailableTitleBounds(),
title_render_text_->GetStringSize().width(),
app_and_domain_render_text_->GetStringSize().width());
}
// Copyright 2017 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.
#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_HOSTED_APP_FRAME_HEADER_ASH_H_
#define CHROME_BROWSER_UI_VIEWS_FRAME_HOSTED_APP_FRAME_HEADER_ASH_H_
#include "ash/frame/default_frame_header.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
namespace gfx {
class Canvas;
class RenderText;
} // namespace gfx
namespace extensions {
class HostedAppBrowserController;
} // namespace extensions
// Helper class for managing the hosted app window header.
class HostedAppFrameHeaderAsh : public ash::DefaultFrameHeader {
public:
HostedAppFrameHeaderAsh(
extensions::HostedAppBrowserController* app_controller,
views::Widget* frame,
views::View* header_view,
ash::FrameCaptionButtonContainerView* caption_button_container,
ash::FrameCaptionButton* back_button);
~HostedAppFrameHeaderAsh() override;
private:
FRIEND_TEST_ALL_PREFIXES(HostedAppNonClientFrameViewAshTest, HostedAppFrame);
// Create a render text for this header.
std::unique_ptr<gfx::RenderText> CreateRenderText();
// Refresh the text inside the render texts.
void UpdateRenderTexts();
// Render the app and domain to the right of the window title, truncating the
// the window title first if the combination doesn't fit.
void LayoutRenderTexts(const gfx::Rect& available_title_bounds,
int title_width,
int app_and_domain_width);
// ash::DefaultFrameHeader:
void PaintTitleBar(gfx::Canvas* canvas) override;
void LayoutHeader() override;
extensions::HostedAppBrowserController* app_controller_; // Weak.
// The render text for the window title.
std::unique_ptr<gfx::RenderText> title_render_text_;
// The render text for the app and domain in the title bar.
std::unique_ptr<gfx::RenderText> app_and_domain_render_text_;
// The name of the app.
const base::string16 app_name_;
// The app and domain string to display in the title bar.
const base::string16 app_and_domain_;
DISALLOW_COPY_AND_ASSIGN(HostedAppFrameHeaderAsh);
};
#endif // CHROME_BROWSER_UI_VIEWS_FRAME_HOSTED_APP_FRAME_HEADER_ASH_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment