158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// found in the LICENSE file. 458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h" 658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/basictypes.h" 88bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/command_line.h" 958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/strings/utf_string_conversions.h" 10c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/ui/views/profiles/avatar_label.h" 11c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/ui/views/profiles/avatar_menu_button.h" 1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/ui/views/tab_icon_view.h" 1358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/ui/views/tabs/tab.h" 148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/common/chrome_switches.h" 15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/signin/core/common/profile_management_switches.h" 1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/gfx/image/image_skia.h" 1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/gfx/image/image_skia_rep.h" 1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/gfx/text_constants.h" 1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/views/controls/button/image_button.h" 2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/views/controls/button/menu_button.h" 2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/views/controls/label.h" 2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/views/test/views_test_base.h" 2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using views::Widget; 2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace { 2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)const int kWidth = 500; 2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class TestLayoutDelegate : public OpaqueBrowserFrameViewLayoutDelegate { 3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public: 3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) enum WindowState { 3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) STATE_NORMAL, 3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) STATE_MAXIMIZED, 3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) STATE_MINIMIZED, 3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) STATE_FULLSCREEN 3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) }; 3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) TestLayoutDelegate() 4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) : show_avatar_(false), 41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) show_caption_buttons_(true), 4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) window_state_(STATE_NORMAL) { 4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual ~TestLayoutDelegate() {} 4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) void SetWindowTitle(const base::string16& title) { 4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) window_title_ = title; 4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) void SetShouldShowAvatar(bool show_avatar) { 5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) show_avatar_ = show_avatar; 5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void SetShouldShowCaptionButtons(bool show_caption_buttons) { 56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) show_caption_buttons_ = show_caption_buttons; 57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) void SetWindowState(WindowState state) { 6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) window_state_ = state; 6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // OpaqueBrowserFrameViewLayoutDelegate overrides: 64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual bool ShouldShowWindowIcon() const OVERRIDE { 6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return !window_title_.empty(); 6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual bool ShouldShowWindowTitle() const OVERRIDE { 7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return !window_title_.empty(); 7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual base::string16 GetWindowTitle() const OVERRIDE { 7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return window_title_; 7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual int GetIconSize() const OVERRIDE { 7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // The value on linux_aura and non-aura windows. 7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return 17; 8058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual bool ShouldLeaveOffsetNearTopBorder() const OVERRIDE { 8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return !IsMaximized(); 8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual gfx::Size GetBrowserViewMinimumSize() const OVERRIDE { 8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Taken from a calculation in BrowserViewLayout. 8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return gfx::Size(168, 64); 8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) virtual bool ShouldShowCaptionButtons() const OVERRIDE { 92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return show_caption_buttons_; 93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual bool ShouldShowAvatar() const OVERRIDE { 9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return show_avatar_; 9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) virtual bool IsRegularOrGuestSession() const OVERRIDE { 1008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return true; 1018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 1028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual gfx::ImageSkia GetOTRAvatarIcon() const OVERRIDE { 10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // The calculations depend on the size of the OTR resource, and chromeos 10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // uses a different sized image, so hard code the size of the current 10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // windows/linux one. 10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::ImageSkiaRep rep(gfx::Size(40, 29), 1.0f); 10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) gfx::ImageSkia image(rep); 10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return image; 11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual bool IsMaximized() const OVERRIDE { 11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return window_state_ == STATE_MAXIMIZED; 11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual bool IsMinimized() const OVERRIDE { 11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return window_state_ == STATE_MINIMIZED; 11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual bool IsFullscreen() const OVERRIDE { 12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return window_state_ == STATE_FULLSCREEN; 12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual bool IsTabStripVisible() const OVERRIDE { 12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return window_title_.empty(); 12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual int GetTabStripHeight() const OVERRIDE { 12958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return IsTabStripVisible() ? Tab::GetMinimumUnselectedSize().height() : 0; 13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual gfx::Size GetTabstripPreferredSize() const OVERRIDE { 13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Measured from Tabstrip::GetPreferredSize(). 13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return IsTabStripVisible() ? gfx::Size(78, 29) : gfx::Size(0, 0); 13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) private: 13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::string16 window_title_; 13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) bool show_avatar_; 140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool show_caption_buttons_; 14158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) WindowState window_state_; 14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 14358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(TestLayoutDelegate); 14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}; 14558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 14658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} // namespace 14758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class OpaqueBrowserFrameViewLayoutTest : public views::ViewsTestBase { 14958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public: 15058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) OpaqueBrowserFrameViewLayoutTest() {} 15158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual ~OpaqueBrowserFrameViewLayoutTest() {} 15258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 15358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual void SetUp() OVERRIDE { 15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) views::ViewsTestBase::SetUp(); 15558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 15658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) delegate_.reset(new TestLayoutDelegate); 15758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) layout_manager_ = new OpaqueBrowserFrameViewLayout(delegate_.get()); 15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) layout_manager_->set_extra_caption_y(0); 15958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) layout_manager_->set_window_caption_spacing(0); 16058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) widget_ = new Widget; 16158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) widget_->Init(CreateParams(Widget::InitParams::TYPE_POPUP)); 16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) root_view_ = widget_->GetRootView(); 16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) root_view_->SetSize(gfx::Size(kWidth, kWidth)); 16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) root_view_->SetLayoutManager(layout_manager_); 16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Add the caption buttons. We use fake images because we're modeling the 16758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Windows assets here, while the linux version uses differently sized 16858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // assets. 16958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // 17058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // TODO(erg): In a follow up patch, separate these sizes out into virtual 17158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // accessors so we can test both the windows and linux behaviours once we 17258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // start modifying the code. 17358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) minimize_button_ = InitWindowCaptionButton( 17458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) VIEW_ID_MINIMIZE_BUTTON, gfx::Size(26, 18)); 17558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) maximize_button_ = InitWindowCaptionButton( 17658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) VIEW_ID_MAXIMIZE_BUTTON, gfx::Size(25, 18)); 17758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) restore_button_ = InitWindowCaptionButton( 17858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) VIEW_ID_RESTORE_BUTTON, gfx::Size(25, 18)); 17958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) close_button_ = InitWindowCaptionButton( 18058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) VIEW_ID_CLOSE_BUTTON, gfx::Size(43, 18)); 18158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 18258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 18358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual void TearDown() OVERRIDE { 18458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) widget_->CloseNow(); 18558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 18658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) views::ViewsTestBase::TearDown(); 18758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 18858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 18958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) protected: 19058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) views::ImageButton* InitWindowCaptionButton(ViewID view_id, 19158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const gfx::Size& size) { 19258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) views::ImageButton* button = new views::ImageButton(NULL); 19368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::ImageSkiaRep rep(size, 1.0f); 19458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) gfx::ImageSkia image(rep); 19558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) button->SetImage(views::CustomButton::STATE_NORMAL, &image); 19658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) button->set_id(view_id); 19758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) root_view_->AddChildView(button); 19858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return button; 19958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 20058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 20158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) void AddWindowTitleIcons() { 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) tab_icon_view_ = new TabIconView(NULL, NULL); 20358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tab_icon_view_->set_is_light(true); 20458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tab_icon_view_->set_id(VIEW_ID_WINDOW_ICON); 20558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) root_view_->AddChildView(tab_icon_view_); 20658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) window_title_ = new views::Label(delegate_->GetWindowTitle()); 20858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) window_title_->SetVisible(delegate_->ShouldShowWindowTitle()); 20958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) window_title_->SetEnabledColor(SK_ColorWHITE); 2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) window_title_->SetSubpixelRenderingEnabled(false); 21158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) window_title_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 21258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) window_title_->set_id(VIEW_ID_WINDOW_TITLE); 21358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) root_view_->AddChildView(window_title_); 21458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 21558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 21658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) void AddAvatarButton() { 2176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Disable the New Avatar Menu. 2186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) switches::DisableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess()); 2196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 220a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) menu_button_ = new AvatarMenuButton(NULL, false); 22158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) menu_button_->set_id(VIEW_ID_AVATAR_BUTTON); 22258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) delegate_->SetShouldShowAvatar(true); 22358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) root_view_->AddChildView(menu_button_); 22458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 22558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 226d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) void AddAvatarLabel() { 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) avatar_label_ = new AvatarLabel(NULL); 228d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) avatar_label_->set_id(VIEW_ID_AVATAR_LABEL); 229d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) root_view_->AddChildView(avatar_label_); 230d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 231d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // The avatar label should only be used together with the avatar button. 232d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) AddAvatarButton(); 233d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 234d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 2358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) void AddNewAvatarButton() { 2366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Enable the New Avatar Menu. 2376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) switches::EnableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess()); 2386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) new_avatar_button_ = 2406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) new views::MenuButton(NULL, base::string16(), NULL, false); 2416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) new_avatar_button_->set_id(VIEW_ID_NEW_AVATAR_BUTTON); 2426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) root_view_->AddChildView(new_avatar_button_); 2438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 2448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 24558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) void ExpectBasicWindowBounds() { 24658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("428,1 25x18", maximize_button_->bounds().ToString()); 24758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("402,1 26x18", minimize_button_->bounds().ToString()); 24858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("0,0 0x0", restore_button_->bounds().ToString()); 24958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("453,1 43x18", close_button_->bounds().ToString()); 25058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 25158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 25258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) Widget* widget_; 25358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) views::View* root_view_; 25458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) OpaqueBrowserFrameViewLayout* layout_manager_; 25558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) scoped_ptr<TestLayoutDelegate> delegate_; 25658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 25758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Widgets: 25858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) views::ImageButton* minimize_button_; 25958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) views::ImageButton* maximize_button_; 26058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) views::ImageButton* restore_button_; 26158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) views::ImageButton* close_button_; 26258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 26358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) TabIconView* tab_icon_view_; 26458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) views::Label* window_title_; 26558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AvatarLabel* avatar_label_; 267a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) AvatarMenuButton* menu_button_; 2688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) views::MenuButton* new_avatar_button_; 26958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 27058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(OpaqueBrowserFrameViewLayoutTest); 27158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}; 27258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 27358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)TEST_F(OpaqueBrowserFrameViewLayoutTest, BasicWindow) { 27458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Tests the layout of a default chrome window with no avatars, no window 27558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // titles, and a tabstrip. 27658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) root_view_->Layout(); 27758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 27858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ExpectBasicWindowBounds(); 27958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 28058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // After some visual inspection, it really does look like the tabstrip is 28158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // initally positioned out of our view. 28258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("-1,13 398x29", 28358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) layout_manager_->GetBoundsForTabStrip( 28458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) delegate_->GetTabstripPreferredSize(), kWidth).ToString()); 28558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("261x73", layout_manager_->GetMinimumSize(kWidth).ToString()); 28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 28758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // A normal window with no window icon still produces icon bounds for 28858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Windows, which has a hidden icon that a user can double click on to close 28958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // the window. 29058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("6,4 17x17", layout_manager_->IconBounds().ToString()); 29158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 29258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 29358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)TEST_F(OpaqueBrowserFrameViewLayoutTest, BasicWindowMaximized) { 29458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Tests the layout of a default chrome window with no avatars, no window 29558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // titles, and a tabstrip, but maximized this time. 29658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) delegate_->SetWindowState(TestLayoutDelegate::STATE_MAXIMIZED); 29758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) root_view_->Layout(); 29858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Note how the bounds start at the exact top of the window while maximized 30058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // while they start 1 pixel below when unmaximized. 30158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("0,0 0x0", maximize_button_->bounds().ToString()); 30258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("403,0 26x18", minimize_button_->bounds().ToString()); 30358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("429,0 25x18", restore_button_->bounds().ToString()); 30458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("454,0 46x18", close_button_->bounds().ToString()); 30558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 30658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("-5,-3 392x29", 30758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) layout_manager_->GetBoundsForTabStrip( 30858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) delegate_->GetTabstripPreferredSize(), kWidth).ToString()); 30958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("262x61", layout_manager_->GetMinimumSize(kWidth).ToString()); 31058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 31158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // In the maximized case, OpaqueBrowserFrameView::NonClientHitTest() uses 31258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // this rect, extended to the top left corner of the window. 31358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("2,0 17x17", layout_manager_->IconBounds().ToString()); 31458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 31558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(OpaqueBrowserFrameViewLayoutTest, MaximizedWithYOffset) { 3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Tests the layout of a basic chrome window with the caption buttons slightly 3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // offset from the top of the screen (as they are on Linux). 3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) layout_manager_->set_extra_caption_y(2); 3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delegate_->SetWindowState(TestLayoutDelegate::STATE_MAXIMIZED); 3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) root_view_->Layout(); 3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Note how the bounds start at the exact top of the window, DESPITE the 3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // caption Y offset of 2. This ensures that we obey Fitts' Law (the buttons 3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // are clickable on the top edge of the screen). However, the buttons are 2 3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // pixels taller, so the images appear to be offset by 2 pixels. 3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", maximize_button_->bounds().ToString()); 3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("403,0 26x20", minimize_button_->bounds().ToString()); 3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("429,0 25x20", restore_button_->bounds().ToString()); 3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("454,0 46x20", close_button_->bounds().ToString()); 3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("-5,-3 392x29", 3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) layout_manager_->GetBoundsForTabStrip( 3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delegate_->GetTabstripPreferredSize(), kWidth).ToString()); 3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("262x61", layout_manager_->GetMinimumSize(kWidth).ToString()); 3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // In the maximized case, OpaqueBrowserFrameView::NonClientHitTest() uses 3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // this rect, extended to the top left corner of the window. 3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("2,0 17x17", layout_manager_->IconBounds().ToString()); 3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 342a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(OpaqueBrowserFrameViewLayoutTest, WindowButtonsOnLeft) { 343a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Tests the layout of a chrome window with caption buttons on the left. 344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<views::FrameButton> leading_buttons; 345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<views::FrameButton> trailing_buttons; 346a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) leading_buttons.push_back(views::FRAME_BUTTON_CLOSE); 347a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) leading_buttons.push_back(views::FRAME_BUTTON_MINIMIZE); 348a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) leading_buttons.push_back(views::FRAME_BUTTON_MAXIMIZE); 349a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) layout_manager_->SetButtonOrdering(leading_buttons, trailing_buttons); 350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) root_view_->Layout(); 351a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 352a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("73,1 25x18", maximize_button_->bounds().ToString()); 353a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("47,1 26x18", minimize_button_->bounds().ToString()); 354a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", restore_button_->bounds().ToString()); 355a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("4,1 43x18", close_button_->bounds().ToString()); 356a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 357a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("93,13 398x29", 358a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) layout_manager_->GetBoundsForTabStrip( 359a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) delegate_->GetTabstripPreferredSize(), kWidth).ToString()); 360a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("261x73", layout_manager_->GetMinimumSize(kWidth).ToString()); 361a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 362a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // If the buttons are on the left, there should be no hidden icon for the user 363a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // to double click. 364a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", layout_manager_->IconBounds().ToString()); 365a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 366a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 367a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(OpaqueBrowserFrameViewLayoutTest, WithoutCaptionButtons) { 3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Tests the layout of a default chrome window with no caption buttons (which 3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // should force the tab strip to be condensed). 370a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) delegate_->SetShouldShowCaptionButtons(false); 371a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) root_view_->Layout(); 372a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 373a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", maximize_button_->bounds().ToString()); 374a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", minimize_button_->bounds().ToString()); 375a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", restore_button_->bounds().ToString()); 376a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", close_button_->bounds().ToString()); 377a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("-5,-3 500x29", 379a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) layout_manager_->GetBoundsForTabStrip( 380a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) delegate_->GetTabstripPreferredSize(), kWidth).ToString()); 3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("251x61", layout_manager_->GetMinimumSize(kWidth).ToString()); 382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 383a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // A normal window with no window icon still produces icon bounds for 384a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Windows, which has a hidden icon that a user can double click on to close 385a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // the window. 3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("2,0 17x17", layout_manager_->IconBounds().ToString()); 3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(OpaqueBrowserFrameViewLayoutTest, MaximizedWithoutCaptionButtons) { 3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Tests the layout of a maximized chrome window with no caption buttons. 3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delegate_->SetWindowState(TestLayoutDelegate::STATE_MAXIMIZED); 3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delegate_->SetShouldShowCaptionButtons(false); 3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) root_view_->Layout(); 3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", maximize_button_->bounds().ToString()); 3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", minimize_button_->bounds().ToString()); 3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", restore_button_->bounds().ToString()); 3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", close_button_->bounds().ToString()); 3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("-5,-3 500x29", 4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) layout_manager_->GetBoundsForTabStrip( 4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delegate_->GetTabstripPreferredSize(), kWidth).ToString()); 4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("251x61", layout_manager_->GetMinimumSize(kWidth).ToString()); 4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // In the maximized case, OpaqueBrowserFrameView::NonClientHitTest() uses 4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // this rect, extended to the top left corner of the window. 4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("2,0 17x17", layout_manager_->IconBounds().ToString()); 408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 41058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)TEST_F(OpaqueBrowserFrameViewLayoutTest, WithWindowTitleAndIcon) { 41158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Tests the layout of pop up windows. 4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delegate_->SetWindowTitle(base::ASCIIToUTF16("Window Title")); 41358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) AddWindowTitleIcons(); 41458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) root_view_->Layout(); 41558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 41658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // We should have the right hand side should match the BasicWindow case. 41758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ExpectBasicWindowBounds(); 41858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 41958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Check the location of the tab icon and window title. 42058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("6,3 17x17", tab_icon_view_->bounds().ToString()); 42158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("27,3 370x17", window_title_->bounds().ToString()); 42258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 42358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 42458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)TEST_F(OpaqueBrowserFrameViewLayoutTest, WindowWithAvatar) { 42558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Tests a normal tabstrip window with an avatar icon. 42658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) AddAvatarButton(); 42758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) root_view_->Layout(); 42858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 42958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ExpectBasicWindowBounds(); 43058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 43158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Check the location of the avatar 43258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("7,11 40x29", menu_button_->bounds().ToString()); 43358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("45,13 352x29", 43458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) layout_manager_->GetBoundsForTabStrip( 43558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) delegate_->GetTabstripPreferredSize(), kWidth).ToString()); 43658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) EXPECT_EQ("261x73", layout_manager_->GetMinimumSize(kWidth).ToString()); 43758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 438d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 439a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(OpaqueBrowserFrameViewLayoutTest, WindowWithAvatarWithButtonsOnLeft) { 440a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Tests the layout of a chrome window with an avatar icon and caption buttons 441a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // on the left. The avatar icon should therefore be on the right. 4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // AddAvatarLabel() also adds the avatar button. 4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AddAvatarLabel(); 444a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<views::FrameButton> leading_buttons; 445a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<views::FrameButton> trailing_buttons; 446a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) leading_buttons.push_back(views::FRAME_BUTTON_CLOSE); 447a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) leading_buttons.push_back(views::FRAME_BUTTON_MINIMIZE); 448a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) leading_buttons.push_back(views::FRAME_BUTTON_MAXIMIZE); 449a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) layout_manager_->SetButtonOrdering(leading_buttons, trailing_buttons); 450a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) root_view_->Layout(); 451a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 452a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("73,1 25x18", maximize_button_->bounds().ToString()); 453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("47,1 26x18", minimize_button_->bounds().ToString()); 454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", restore_button_->bounds().ToString()); 455a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("4,1 43x18", close_button_->bounds().ToString()); 456a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 457a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Check the location of the avatar 458a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("454,11 40x29", menu_button_->bounds().ToString()); 4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Check the tab strip bounds. 4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gfx::Rect tab_strip_bounds = layout_manager_->GetBoundsForTabStrip( 4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delegate_->GetTabstripPreferredSize(), kWidth); 4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_GT(tab_strip_bounds.x(), maximize_button_->bounds().x()); 4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_GT(maximize_button_->bounds().right(), tab_strip_bounds.x()); 4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(13, tab_strip_bounds.y()); 4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(29, tab_strip_bounds.height()); 4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_GT(avatar_label_->bounds().x(), tab_strip_bounds.right()); 468a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("261x73", layout_manager_->GetMinimumSize(kWidth).ToString()); 469a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Check the relative location of the avatar label to the avatar. The right 4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // end of the avatar label should be slightly to the right of the right end of 4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // the avatar icon. 4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_GT(avatar_label_->bounds().right(), menu_button_->bounds().right()); 4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_GT(menu_button_->bounds().x(), avatar_label_->bounds().x()); 4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_GT(menu_button_->bounds().bottom(), 4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) avatar_label_->bounds().bottom()); 4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_GT(avatar_label_->bounds().y(), menu_button_->bounds().y()); 4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 479a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // This means that the menu will pop out facing the left (if it were to face 480a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // the right, it would go outside the window frame and be clipped). 481a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_TRUE(menu_button_->button_on_right()); 482a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 483a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // If the buttons are on the left, there should be no hidden icon for the user 484a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // to double click. 485a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", layout_manager_->IconBounds().ToString()); 486a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 487a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 488a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(OpaqueBrowserFrameViewLayoutTest, 489a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) WindowWithAvatarWithoutCaptionButtonsOnLeft) { 490a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Tests the layout of a chrome window with an avatar icon and no caption 491a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // buttons. However, the caption buttons *would* be on the left if they 492a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // weren't hidden, and therefore, the avatar icon should be on the right. 4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The lack of caption buttons should force the tab strip to be condensed. 494a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) AddAvatarButton(); 495a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<views::FrameButton> leading_buttons; 496a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<views::FrameButton> trailing_buttons; 497a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) leading_buttons.push_back(views::FRAME_BUTTON_CLOSE); 498a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) leading_buttons.push_back(views::FRAME_BUTTON_MINIMIZE); 499a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) leading_buttons.push_back(views::FRAME_BUTTON_MAXIMIZE); 500a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) layout_manager_->SetButtonOrdering(leading_buttons, trailing_buttons); 501a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) delegate_->SetShouldShowCaptionButtons(false); 502a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) root_view_->Layout(); 503a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 504a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", maximize_button_->bounds().ToString()); 505a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", minimize_button_->bounds().ToString()); 506a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", restore_button_->bounds().ToString()); 507a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("0,0 0x0", close_button_->bounds().ToString()); 508a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 509a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Check the location of the avatar 5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("458,0 40x24", menu_button_->bounds().ToString()); 5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("-5,-3 458x29", 512a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) layout_manager_->GetBoundsForTabStrip( 513a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) delegate_->GetTabstripPreferredSize(), kWidth).ToString()); 5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("251x61", layout_manager_->GetMinimumSize(kWidth).ToString()); 515a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 516a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // A normal window with no window icon still produces icon bounds for 517a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Windows, which has a hidden icon that a user can double click on to close 518a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // the window. 5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("2,0 17x17", layout_manager_->IconBounds().ToString()); 520a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 5218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 5228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)TEST_F(OpaqueBrowserFrameViewLayoutTest, WindowWithNewAvatar) { 5238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Tests a normal tabstrip window with the new style avatar icon. 5248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) AddNewAvatarButton(); 5258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) root_view_->Layout(); 5268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 5278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ExpectBasicWindowBounds(); 5288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 5296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Check the location of the avatar button. 5306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) EXPECT_EQ("385,1 12x18", new_avatar_button_->bounds().ToString()); 5311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // The new tab button is 39px wide and slides completely under the new 5321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // avatar button, thus increasing the tabstrip by that amount. 5331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci EXPECT_EQ("-1,13 420x29", 5348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) layout_manager_->GetBoundsForTabStrip( 5358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) delegate_->GetTabstripPreferredSize(), kWidth).ToString()); 5368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) EXPECT_EQ("261x73", layout_manager_->GetMinimumSize(kWidth).ToString()); 5378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 5388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(OpaqueBrowserFrameViewLayoutTest, WindowWithAvatarLabelAndButtonOnLeft) { 540d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) AddAvatarLabel(); 541d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) root_view_->Layout(); 542d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 543d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ExpectBasicWindowBounds(); 544d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Check the location of the avatar label relative to the avatar button if 5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // both are displayed on the left side. 547d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // The label height and width depends on the font size and the text displayed. 548d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // This may possibly change, so we don't test it here. 549d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) EXPECT_EQ(menu_button_->bounds().x() - 2, avatar_label_->bounds().x()); 550d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) EXPECT_EQ( 551d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) menu_button_->bounds().bottom() - 3 - avatar_label_->bounds().height(), 552d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) avatar_label_->bounds().y()); 553d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 554