Home | History | Annotate | Download | only in panels
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/views/panels/panel_frame_view.h"
      6 
      7 #include "chrome/browser/ui/panels/panel.h"
      8 #include "chrome/browser/ui/panels/panel_constants.h"
      9 #include "chrome/browser/ui/views/panels/panel_view.h"
     10 #include "chrome/browser/ui/views/tab_icon_view.h"
     11 #include "content/public/browser/web_contents.h"
     12 #include "grit/generated_resources.h"
     13 #include "grit/theme_resources.h"
     14 #include "grit/ui_resources.h"
     15 #include "ui/aura/window.h"
     16 #include "ui/base/hit_test.h"
     17 #include "ui/base/l10n/l10n_util.h"
     18 #include "ui/base/resource/resource_bundle.h"
     19 #include "ui/gfx/canvas.h"
     20 #include "ui/gfx/font_list.h"
     21 #include "ui/gfx/path.h"
     22 #include "ui/gfx/screen.h"
     23 #include "ui/views/controls/button/image_button.h"
     24 #include "ui/views/controls/label.h"
     25 #include "ui/views/widget/widget.h"
     26 #include "ui/views/widget/widget_delegate.h"
     27 
     28 #if defined(OS_WIN)
     29 #include "base/win/scoped_gdi_object.h"
     30 #include "ui/base/win/shell.h"
     31 #include "ui/gfx/path_win.h"
     32 #include "ui/views/win/hwnd_util.h"
     33 #endif
     34 
     35 namespace {
     36 
     37 // The thickness of the border when Aero is not enabled. In this case, the
     38 // shadow around the window will not be painted by the system and we need to
     39 // paint a frame in order to differentiate the client area from the background.
     40 const int kNonAeroBorderThickness = 1;
     41 
     42 // The height and width in pixels of the icon.
     43 const int kIconSize = 16;
     44 
     45 // The extra padding between the button and the top edge.
     46 const int kExtraPaddingBetweenButtonAndTop = 1;
     47 
     48 // Colors used to draw titlebar background under default theme.
     49 const SkColor kActiveBackgroundDefaultColor = SkColorSetRGB(0x3a, 0x3d, 0x3d);
     50 const SkColor kInactiveBackgroundDefaultColor = SkColorSetRGB(0x7a, 0x7c, 0x7c);
     51 const SkColor kAttentionBackgroundDefaultColor =
     52     SkColorSetRGB(0x53, 0xa9, 0x3f);
     53 
     54 // Color used to draw the minimized panel.
     55 const SkColor kMinimizeBackgroundDefaultColor = SkColorSetRGB(0xf5, 0xf4, 0xf0);
     56 
     57 // Color used to draw the title text under default theme.
     58 const SkColor kTitleTextDefaultColor = SkColorSetRGB(0xf9, 0xf9, 0xf9);
     59 
     60 gfx::ImageSkia* CreateImageForColor(SkColor color) {
     61   gfx::Canvas canvas(gfx::Size(1, 1), 1.0f, true);
     62   canvas.DrawColor(color);
     63   return new gfx::ImageSkia(canvas.ExtractImageRep());
     64 }
     65 
     66 #if defined(OS_WIN)
     67 const gfx::ImageSkia& GetTopLeftCornerImage(panel::CornerStyle corner_style) {
     68   static gfx::ImageSkia* rounded_image = NULL;
     69   static gfx::ImageSkia* non_rounded_image = NULL;
     70   if (!rounded_image) {
     71     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
     72     rounded_image = rb.GetImageSkiaNamed(IDR_WINDOW_TOP_LEFT_CORNER);
     73     non_rounded_image = rb.GetImageSkiaNamed(IDR_PANEL_TOP_LEFT_CORNER);
     74   }
     75   return (corner_style & panel::TOP_ROUNDED) ? *rounded_image
     76                                              : *non_rounded_image;
     77 }
     78 
     79 const gfx::ImageSkia& GetTopRightCornerImage(panel::CornerStyle corner_style) {
     80   static gfx::ImageSkia* rounded_image = NULL;
     81   static gfx::ImageSkia* non_rounded_image = NULL;
     82   if (!rounded_image) {
     83     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
     84     rounded_image = rb.GetImageSkiaNamed(IDR_WINDOW_TOP_RIGHT_CORNER);
     85     non_rounded_image = rb.GetImageSkiaNamed(IDR_PANEL_TOP_RIGHT_CORNER);
     86   }
     87   return (corner_style & panel::TOP_ROUNDED) ? *rounded_image
     88                                              : *non_rounded_image;
     89 }
     90 
     91 const gfx::ImageSkia& GetBottomLeftCornerImage(
     92     panel::CornerStyle corner_style) {
     93   static gfx::ImageSkia* rounded_image = NULL;
     94   static gfx::ImageSkia* non_rounded_image = NULL;
     95   if (!rounded_image) {
     96     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
     97     rounded_image = rb.GetImageSkiaNamed(IDR_WINDOW_BOTTOM_LEFT_CORNER);
     98     non_rounded_image = rb.GetImageSkiaNamed(IDR_PANEL_BOTTOM_LEFT_CORNER);
     99   }
    100   return (corner_style & panel::BOTTOM_ROUNDED) ? *rounded_image
    101                                                 : *non_rounded_image;
    102 }
    103 
    104 const gfx::ImageSkia& GetBottomRightCornerImage(
    105     panel::CornerStyle corner_style) {
    106   static gfx::ImageSkia* rounded_image = NULL;
    107   static gfx::ImageSkia* non_rounded_image = NULL;
    108   if (!rounded_image) {
    109     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    110     rounded_image = rb.GetImageSkiaNamed(IDR_WINDOW_BOTTOM_RIGHT_CORNER);
    111     non_rounded_image = rb.GetImageSkiaNamed(IDR_PANEL_BOTTOM_RIGHT_CORNER);
    112   }
    113   return (corner_style & panel::BOTTOM_ROUNDED) ? *rounded_image
    114                                                 : *non_rounded_image;
    115 }
    116 
    117 const gfx::ImageSkia& GetTopEdgeImage() {
    118   static gfx::ImageSkia* image = NULL;
    119   if (!image) {
    120     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    121     image = rb.GetImageSkiaNamed(IDR_WINDOW_TOP_CENTER);
    122   }
    123   return *image;
    124 }
    125 
    126 const gfx::ImageSkia& GetBottomEdgeImage() {
    127   static gfx::ImageSkia* image = NULL;
    128   if (!image) {
    129     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    130     image = rb.GetImageSkiaNamed(IDR_WINDOW_BOTTOM_CENTER);
    131   }
    132   return *image;
    133 }
    134 
    135 const gfx::ImageSkia& GetLeftEdgeImage() {
    136   static gfx::ImageSkia* image = NULL;
    137   if (!image) {
    138     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    139     image = rb.GetImageSkiaNamed(IDR_WINDOW_LEFT_SIDE);
    140   }
    141   return *image;
    142 }
    143 
    144 const gfx::ImageSkia& GetRightEdgeImage() {
    145   static gfx::ImageSkia* image = NULL;
    146   if (!image) {
    147     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    148     image = rb.GetImageSkiaNamed(IDR_WINDOW_RIGHT_SIDE);
    149   }
    150   return *image;
    151 }
    152 #endif  // defined(OS_WIN)
    153 
    154 const gfx::ImageSkia* GetActiveBackgroundDefaultImage() {
    155   static gfx::ImageSkia* image = NULL;
    156   if (!image)
    157     image = CreateImageForColor(kActiveBackgroundDefaultColor);
    158   return image;
    159 }
    160 
    161 const gfx::ImageSkia* GetInactiveBackgroundDefaultImage() {
    162   static gfx::ImageSkia* image = NULL;
    163   if (!image)
    164     image = CreateImageForColor(kInactiveBackgroundDefaultColor);
    165   return image;
    166 }
    167 
    168 const gfx::ImageSkia* GetAttentionBackgroundDefaultImage() {
    169   static gfx::ImageSkia* image = NULL;
    170   if (!image)
    171     image = CreateImageForColor(kAttentionBackgroundDefaultColor);
    172   return image;
    173 }
    174 
    175 const gfx::ImageSkia* GetMinimizeBackgroundDefaultImage() {
    176   static gfx::ImageSkia* image = NULL;
    177   if (!image)
    178     image = CreateImageForColor(kMinimizeBackgroundDefaultColor);
    179   return image;
    180 }
    181 
    182 int GetFrameEdgeHitTest(const gfx::Point& point,
    183                         const gfx::Size& frame_size,
    184                         int resize_area_size,
    185                         panel::Resizability resizability) {
    186   int x = point.x();
    187   int y = point.y();
    188   int width = frame_size.width();
    189   int height = frame_size.height();
    190   if (x < resize_area_size) {
    191     if (y < resize_area_size && (resizability & panel::RESIZABLE_TOP_LEFT)) {
    192       return HTTOPLEFT;
    193     } else if (y >= height - resize_area_size &&
    194               (resizability & panel::RESIZABLE_BOTTOM_LEFT)) {
    195       return HTBOTTOMLEFT;
    196     } else if (resizability & panel::RESIZABLE_LEFT) {
    197       return HTLEFT;
    198     }
    199   } else if (x >= width - resize_area_size) {
    200     if (y < resize_area_size && (resizability & panel::RESIZABLE_TOP_RIGHT)) {
    201       return HTTOPRIGHT;
    202     } else if (y >= height - resize_area_size &&
    203               (resizability & panel::RESIZABLE_BOTTOM_RIGHT)) {
    204       return HTBOTTOMRIGHT;
    205     } else if (resizability & panel::RESIZABLE_RIGHT) {
    206       return HTRIGHT;
    207     }
    208   }
    209 
    210   if (y < resize_area_size && (resizability & panel::RESIZABLE_TOP)) {
    211     return HTTOP;
    212   } else if (y >= height - resize_area_size &&
    213             (resizability & panel::RESIZABLE_BOTTOM)) {
    214     return HTBOTTOM;
    215   }
    216 
    217   return HTNOWHERE;
    218 }
    219 
    220 // Frameless is only supported when Aero is enabled and shadow effect is
    221 // present.
    222 bool ShouldRenderAsFrameless() {
    223 #if defined(OS_WIN)
    224   bool is_frameless = ui::win::IsAeroGlassEnabled();
    225   if (is_frameless) {
    226     BOOL shadow_enabled = FALSE;
    227     if (::SystemParametersInfo(SPI_GETDROPSHADOW, 0, &shadow_enabled, 0) &&
    228         !shadow_enabled)
    229       is_frameless = false;
    230   }
    231   return is_frameless;
    232 #else
    233   return false;
    234 #endif
    235 }
    236 
    237 }  // namespace
    238 
    239 // static
    240 const char PanelFrameView::kViewClassName[] = "PanelFrameView";
    241 
    242 PanelFrameView::PanelFrameView(PanelView* panel_view)
    243     : is_frameless_(ShouldRenderAsFrameless()),
    244       panel_view_(panel_view),
    245       close_button_(NULL),
    246       minimize_button_(NULL),
    247       restore_button_(NULL),
    248       title_icon_(NULL),
    249       title_label_(NULL),
    250       corner_style_(panel::ALL_ROUNDED) {
    251 }
    252 
    253 PanelFrameView::~PanelFrameView() {
    254 }
    255 
    256 void PanelFrameView::Init() {
    257   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    258 
    259   close_button_ = new views::ImageButton(this);
    260   close_button_->SetImage(views::CustomButton::STATE_NORMAL,
    261                           rb.GetImageSkiaNamed(IDR_PANEL_CLOSE));
    262   close_button_->SetImage(views::CustomButton::STATE_HOVERED,
    263                           rb.GetImageSkiaNamed(IDR_PANEL_CLOSE_H));
    264   close_button_->SetImage(views::CustomButton::STATE_PRESSED,
    265                           rb.GetImageSkiaNamed(IDR_PANEL_CLOSE_C));
    266   close_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
    267                                    views::ImageButton::ALIGN_MIDDLE);
    268   base::string16 tooltip_text =
    269       l10n_util::GetStringUTF16(IDS_PANEL_CLOSE_TOOLTIP);
    270   close_button_->SetTooltipText(tooltip_text);
    271   AddChildView(close_button_);
    272 
    273   minimize_button_ = new views::ImageButton(this);
    274   minimize_button_->SetImage(views::CustomButton::STATE_NORMAL,
    275                              rb.GetImageSkiaNamed(IDR_PANEL_MINIMIZE));
    276   minimize_button_->SetImage(views::CustomButton::STATE_HOVERED,
    277                              rb.GetImageSkiaNamed(IDR_PANEL_MINIMIZE_H));
    278   minimize_button_->SetImage(views::CustomButton::STATE_PRESSED,
    279                              rb.GetImageSkiaNamed(IDR_PANEL_MINIMIZE_C));
    280   tooltip_text = l10n_util::GetStringUTF16(IDS_PANEL_MINIMIZE_TOOLTIP);
    281   minimize_button_->SetTooltipText(tooltip_text);
    282   minimize_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
    283                                       views::ImageButton::ALIGN_MIDDLE);
    284   AddChildView(minimize_button_);
    285 
    286   restore_button_ = new views::ImageButton(this);
    287   restore_button_->SetImage(views::CustomButton::STATE_NORMAL,
    288                             rb.GetImageSkiaNamed(IDR_PANEL_RESTORE));
    289   restore_button_->SetImage(views::CustomButton::STATE_HOVERED,
    290                             rb.GetImageSkiaNamed(IDR_PANEL_RESTORE_H));
    291   restore_button_->SetImage(views::CustomButton::STATE_PRESSED,
    292                             rb.GetImageSkiaNamed(IDR_PANEL_RESTORE_C));
    293   restore_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
    294                                      views::ImageButton::ALIGN_MIDDLE);
    295   tooltip_text = l10n_util::GetStringUTF16(IDS_PANEL_RESTORE_TOOLTIP);
    296   restore_button_->SetTooltipText(tooltip_text);
    297   restore_button_->SetVisible(false);  // only visible when panel is minimized
    298   AddChildView(restore_button_);
    299 
    300   title_icon_ = new TabIconView(this, NULL);
    301   title_icon_->set_is_light(true);
    302   AddChildView(title_icon_);
    303   title_icon_->Update();
    304 
    305   title_label_ = new views::Label(
    306       panel_view_->panel()->GetWindowTitle(),
    307       rb.GetFontList(ui::ResourceBundle::BoldFont));
    308   title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    309   title_label_->SetAutoColorReadabilityEnabled(false);
    310   AddChildView(title_label_);
    311 
    312   // Compute the thickness of the client area that needs to be counted towards
    313   // mouse resizing.
    314   // TODO(tdanderson): Remove this if possible (crbug.com/344924).
    315   int thickness_for_mouse_resizing =
    316       PanelView::kResizeInsideBoundsSize - BorderThickness();
    317   aura::Window* window = panel_view_->GetNativePanelWindow();
    318   window->set_hit_test_bounds_override_inner(
    319       gfx::Insets(thickness_for_mouse_resizing, thickness_for_mouse_resizing,
    320                   thickness_for_mouse_resizing, thickness_for_mouse_resizing));
    321 }
    322 
    323 void PanelFrameView::UpdateTitle() {
    324   UpdateWindowTitle();
    325 }
    326 
    327 void PanelFrameView::UpdateIcon() {
    328   UpdateWindowIcon();
    329 }
    330 
    331 void PanelFrameView::UpdateThrobber() {
    332   title_icon_->Update();
    333 }
    334 
    335 void PanelFrameView::UpdateTitlebarMinimizeRestoreButtonVisibility() {
    336   Panel* panel = panel_view_->panel();
    337   minimize_button_->SetVisible(panel->CanShowMinimizeButton());
    338   restore_button_->SetVisible(panel->CanShowRestoreButton());
    339 
    340   // Reset the button states in case that the hover states are not cleared when
    341   // mouse is clicked but not moved.
    342   minimize_button_->SetState(views::CustomButton::STATE_NORMAL);
    343   restore_button_->SetState(views::CustomButton::STATE_NORMAL);
    344 }
    345 
    346 void PanelFrameView::SetWindowCornerStyle(panel::CornerStyle corner_style) {
    347   corner_style_ = corner_style;
    348 
    349 #if defined(OS_WIN)
    350   // Changing the window region is going to force a paint. Only change the
    351   // window region if the region really differs.
    352   HWND native_window = views::HWNDForWidget(panel_view_->window());
    353   base::win::ScopedRegion current_region(::CreateRectRgn(0, 0, 0, 0));
    354   int current_region_result = ::GetWindowRgn(native_window, current_region);
    355 
    356   gfx::Path window_mask;
    357   GetWindowMask(size(), &window_mask);
    358   base::win::ScopedRegion new_region(gfx::CreateHRGNFromSkPath(window_mask));
    359 
    360   if (current_region_result == ERROR ||
    361       !::EqualRgn(current_region, new_region)) {
    362     // SetWindowRgn takes ownership of the new_region.
    363     ::SetWindowRgn(native_window, new_region.release(), TRUE);
    364   }
    365 #endif
    366 }
    367 
    368 gfx::Rect PanelFrameView::GetBoundsForClientView() const {
    369   // The origin of client-area bounds starts after left border and titlebar and
    370   // spans until hitting the right and bottom borders.
    371   //    +------------------------------+
    372   //    |         Top Titlebar         |
    373   //    |-+--------------------------+-|
    374   //    |L|                          |R|
    375   //    |e|                          |i|
    376   //    |f|                          |g|
    377   //    |t|                          |h|
    378   //    | |         Client           |t|
    379   //    | |                          | |
    380   //    |B|          Area            |B|
    381   //    |o|                          |o|
    382   //    |r|                          |r|
    383   //    |d|                          |d|
    384   //    |e|                          |e|
    385   //    |r|                          |r|
    386   //    | +--------------------------+ |
    387   //    |        Bottom Border         |
    388   //    +------------------------------+
    389   int titlebar_height = TitlebarHeight();
    390   int border_thickness = BorderThickness();
    391   return gfx::Rect(border_thickness,
    392                    titlebar_height,
    393                    std::max(0, width() - border_thickness * 2),
    394                    std::max(0, height() - titlebar_height - border_thickness));
    395 }
    396 
    397 gfx::Rect PanelFrameView::GetWindowBoundsForClientBounds(
    398       const gfx::Rect& client_bounds) const {
    399   int titlebar_height = TitlebarHeight();
    400   int border_thickness = BorderThickness();
    401   // The window bounds include both client area and non-client area (titlebar
    402   // and left, right and bottom borders).
    403   return gfx::Rect(client_bounds.x() - border_thickness,
    404                    client_bounds.y() - titlebar_height,
    405                    client_bounds.width() + border_thickness * 2,
    406                    client_bounds.height() + titlebar_height + border_thickness);
    407 }
    408 
    409 int PanelFrameView::NonClientHitTest(const gfx::Point& point) {
    410   panel::Resizability resizability = panel_view_->panel()->CanResizeByMouse();
    411 
    412   // Check the frame first, as we allow a small area overlapping the contents
    413   // to be used for resize handles.
    414   int frame_component = GetFrameEdgeHitTest(
    415       point, size(), PanelView::kResizeInsideBoundsSize, resizability);
    416 
    417   if (frame_component != HTNOWHERE)
    418     return frame_component;
    419 
    420   int client_component =
    421       panel_view_->window()->client_view()->NonClientHitTest(point);
    422   if (client_component != HTNOWHERE)
    423     return client_component;
    424 
    425   if (close_button_ && close_button_->visible() &&
    426       close_button_->GetMirroredBounds().Contains(point))
    427     return HTCLOSE;
    428 
    429   if (minimize_button_ && minimize_button_->visible() &&
    430       minimize_button_->GetMirroredBounds().Contains(point))
    431     return HTMINBUTTON;
    432 
    433   if (restore_button_ && restore_button_->visible() &&
    434       restore_button_->GetMirroredBounds().Contains(point))
    435     return HTMAXBUTTON;
    436 
    437   return HTNOWHERE;
    438 }
    439 
    440 void PanelFrameView::GetWindowMask(const gfx::Size& size,
    441                                    gfx::Path* window_mask) {
    442   int width = size.width();
    443   int height = size.height();
    444 
    445   if (corner_style_ & panel::TOP_ROUNDED) {
    446     window_mask->moveTo(0, 3);
    447     window_mask->lineTo(1, 2);
    448     window_mask->lineTo(1, 1);
    449     window_mask->lineTo(2, 1);
    450     window_mask->lineTo(3, 0);
    451     window_mask->lineTo(SkIntToScalar(width - 3), 0);
    452     window_mask->lineTo(SkIntToScalar(width - 2), 1);
    453     window_mask->lineTo(SkIntToScalar(width - 1), 1);
    454     window_mask->lineTo(SkIntToScalar(width - 1), 2);
    455     window_mask->lineTo(SkIntToScalar(width - 1), 3);
    456   } else {
    457     window_mask->moveTo(0, 0);
    458     window_mask->lineTo(width, 0);
    459   }
    460 
    461   if (corner_style_ & panel::BOTTOM_ROUNDED) {
    462     window_mask->lineTo(SkIntToScalar(width - 1), SkIntToScalar(height - 4));
    463     window_mask->lineTo(SkIntToScalar(width - 2), SkIntToScalar(height - 3));
    464     window_mask->lineTo(SkIntToScalar(width - 2), SkIntToScalar(height - 2));
    465     window_mask->lineTo(SkIntToScalar(width - 3), SkIntToScalar(height - 2));
    466     window_mask->lineTo(SkIntToScalar(width - 4), SkIntToScalar(height - 1));
    467     window_mask->lineTo(3, SkIntToScalar(height - 1));
    468     window_mask->lineTo(2, SkIntToScalar(height - 2));
    469     window_mask->lineTo(1, SkIntToScalar(height - 2));
    470     window_mask->lineTo(1, SkIntToScalar(height - 3));
    471     window_mask->lineTo(0, SkIntToScalar(height - 4));
    472   } else {
    473     window_mask->lineTo(SkIntToScalar(width), SkIntToScalar(height));
    474     window_mask->lineTo(0, SkIntToScalar(height));
    475   }
    476 
    477   window_mask->close();
    478 }
    479 
    480 void PanelFrameView::ResetWindowControls() {
    481   // The controls aren't affected by this constraint.
    482 }
    483 
    484 void PanelFrameView::UpdateWindowIcon() {
    485   title_icon_->SchedulePaint();
    486 }
    487 
    488 void PanelFrameView::UpdateWindowTitle() {
    489   title_label_->SetText(panel_view_->panel()->GetWindowTitle());
    490 }
    491 
    492 gfx::Size PanelFrameView::GetPreferredSize() const {
    493   gfx::Size pref_size =
    494       panel_view_->window()->client_view()->GetPreferredSize();
    495   gfx::Rect bounds(0, 0, pref_size.width(), pref_size.height());
    496   return panel_view_->window()->non_client_view()->
    497       GetWindowBoundsForClientBounds(bounds).size();
    498 }
    499 
    500 const char* PanelFrameView::GetClassName() const {
    501   return kViewClassName;
    502 }
    503 
    504 gfx::Size PanelFrameView::GetMinimumSize() const {
    505   return panel_view_->GetMinimumSize();
    506 }
    507 
    508 gfx::Size PanelFrameView::GetMaximumSize() const {
    509   return panel_view_->GetMaximumSize();
    510 }
    511 
    512 void PanelFrameView::Layout() {
    513   is_frameless_ = ShouldRenderAsFrameless();
    514 
    515   // Layout the close button.
    516   int right = width();
    517   close_button_->SetBounds(
    518       width() - panel::kTitlebarRightPadding - panel::kPanelButtonSize,
    519       (TitlebarHeight() - panel::kPanelButtonSize) / 2 +
    520           kExtraPaddingBetweenButtonAndTop,
    521       panel::kPanelButtonSize,
    522       panel::kPanelButtonSize);
    523   right = close_button_->x();
    524 
    525   // Layout the minimize and restore button. Both occupy the same space,
    526   // but at most one is visible at any time.
    527   minimize_button_->SetBounds(
    528       right - panel::kButtonPadding - panel::kPanelButtonSize,
    529       (TitlebarHeight() - panel::kPanelButtonSize) / 2 +
    530           kExtraPaddingBetweenButtonAndTop,
    531       panel::kPanelButtonSize,
    532       panel::kPanelButtonSize);
    533   restore_button_->SetBoundsRect(minimize_button_->bounds());
    534   right = minimize_button_->x();
    535 
    536   // Layout the icon.
    537   int icon_y = (TitlebarHeight() - kIconSize) / 2;
    538   title_icon_->SetBounds(
    539       panel::kTitlebarLeftPadding,
    540       icon_y,
    541       kIconSize,
    542       kIconSize);
    543 
    544   // Layout the title.
    545   int title_x = title_icon_->bounds().right() + panel::kIconAndTitlePadding;
    546   int title_height = title_label_->font_list().GetHeight();
    547   title_label_->SetBounds(
    548       title_x,
    549       icon_y + ((kIconSize - title_height - 1) / 2),
    550       std::max(0, right - panel::kTitleAndButtonPadding - title_x),
    551       title_height);
    552 }
    553 
    554 void PanelFrameView::OnPaint(gfx::Canvas* canvas) {
    555   UpdateControlStyles(GetPaintState());
    556   PaintFrameBackground(canvas);
    557   PaintFrameEdge(canvas);
    558 }
    559 
    560 bool PanelFrameView::OnMousePressed(const ui::MouseEvent& event) {
    561   if (event.IsOnlyLeftMouseButton()) {
    562     // |event.location| is in the view's coordinate system. Convert it to the
    563     // screen coordinate system.
    564     gfx::Point mouse_location = event.location();
    565     views::View::ConvertPointToScreen(this, &mouse_location);
    566 
    567     // If the mouse location falls within the resizing area of the titlebar,
    568     // do not handle the event so that the system resizing logic could kick in.
    569     if (!panel_view_->IsWithinResizingArea(mouse_location) &&
    570         panel_view_->OnTitlebarMousePressed(mouse_location))
    571       return true;
    572   }
    573   return NonClientFrameView::OnMousePressed(event);
    574 }
    575 
    576 bool PanelFrameView::OnMouseDragged(const ui::MouseEvent& event) {
    577 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
    578   // Converting the mouse location to screen coordinates returns an incorrect
    579   // location while the panel is moving. See crbug.com/353393 for more details.
    580   // TODO(pkotwicz): Fix conversion to screen coordinates
    581   gfx::Screen* screen = gfx::Screen::GetNativeScreen();
    582   gfx::Point mouse_location = screen->GetCursorScreenPoint();
    583 #else
    584   // |event.location| is in the view's coordinate system. Convert it to the
    585   // screen coordinate system.
    586   gfx::Point mouse_location = event.location();
    587   views::View::ConvertPointToScreen(this, &mouse_location);
    588 #endif
    589 
    590   if (panel_view_->OnTitlebarMouseDragged(mouse_location))
    591     return true;
    592   return NonClientFrameView::OnMouseDragged(event);
    593 }
    594 
    595 void PanelFrameView::OnMouseReleased(const ui::MouseEvent& event) {
    596   if (panel_view_->OnTitlebarMouseReleased(
    597           event.IsControlDown() ? panel::APPLY_TO_ALL : panel::NO_MODIFIER))
    598     return;
    599   NonClientFrameView::OnMouseReleased(event);
    600 }
    601 
    602 void PanelFrameView::OnMouseCaptureLost() {
    603   if (panel_view_->OnTitlebarMouseCaptureLost())
    604     return;
    605   NonClientFrameView::OnMouseCaptureLost();
    606 }
    607 
    608 void PanelFrameView::ButtonPressed(views::Button* sender,
    609                                    const ui::Event& event) {
    610   if (sender == close_button_) {
    611     panel_view_->ClosePanel();
    612   } else {
    613     panel::ClickModifier modifier =
    614         event.IsControlDown() ? panel::APPLY_TO_ALL : panel::NO_MODIFIER;
    615     if (sender == minimize_button_)
    616       panel_view_->panel()->OnMinimizeButtonClicked(modifier);
    617     else if (sender == restore_button_)
    618       panel_view_->panel()->OnRestoreButtonClicked(modifier);
    619   }
    620 }
    621 
    622 bool PanelFrameView::ShouldTabIconViewAnimate() const {
    623   // This function is queried during the creation of the window as the
    624   // TabIconView we host is initialized, so we need to NULL check the selected
    625   // WebContents because in this condition there is not yet a selected tab.
    626   content::WebContents* contents = panel_view_->panel()->GetWebContents();
    627   return contents ? contents->IsLoading() : false;
    628 }
    629 
    630 gfx::ImageSkia PanelFrameView::GetFaviconForTabIconView() {
    631   return panel_view_->window()->widget_delegate()->GetWindowIcon();
    632 }
    633 
    634 gfx::Size PanelFrameView::NonClientAreaSize() const {
    635   if (is_frameless_)
    636     return gfx::Size(0, TitlebarHeight());
    637   // When the frame is present, the width of non-client area consists of
    638   // left and right borders, while the height consists of the top area
    639   // (titlebar) and the bottom border.
    640   return gfx::Size(2 * kNonAeroBorderThickness,
    641                    TitlebarHeight() + kNonAeroBorderThickness);
    642 }
    643 
    644 int PanelFrameView::TitlebarHeight() const {
    645   return panel::kTitlebarHeight;
    646 }
    647 
    648 int PanelFrameView::BorderThickness() const {
    649   return is_frameless_ ? 0 : kNonAeroBorderThickness;
    650 }
    651 
    652 PanelFrameView::PaintState PanelFrameView::GetPaintState() const {
    653   if (panel_view_->panel()->IsDrawingAttention())
    654     return PAINT_FOR_ATTENTION;
    655   if (bounds().height() <= panel::kMinimizedPanelHeight)
    656     return PAINT_AS_MINIMIZED;
    657   if (panel_view_->IsPanelActive() &&
    658            !panel_view_->force_to_paint_as_inactive())
    659     return PAINT_AS_ACTIVE;
    660   return PAINT_AS_INACTIVE;
    661 }
    662 
    663 SkColor PanelFrameView::GetTitleColor(PaintState paint_state) const {
    664   return kTitleTextDefaultColor;
    665 }
    666 
    667 const gfx::ImageSkia* PanelFrameView::GetFrameBackground(
    668     PaintState paint_state) const {
    669   switch (paint_state) {
    670     case PAINT_AS_INACTIVE:
    671       return GetInactiveBackgroundDefaultImage();
    672     case PAINT_AS_ACTIVE:
    673       return GetActiveBackgroundDefaultImage();
    674     case PAINT_AS_MINIMIZED:
    675       return GetMinimizeBackgroundDefaultImage();
    676     case PAINT_FOR_ATTENTION:
    677       return GetAttentionBackgroundDefaultImage();
    678     default:
    679       NOTREACHED();
    680       return GetInactiveBackgroundDefaultImage();
    681   }
    682 }
    683 
    684 void PanelFrameView::UpdateControlStyles(PaintState paint_state) {
    685   title_label_->SetEnabledColor(GetTitleColor(paint_state));
    686 }
    687 
    688 void PanelFrameView::PaintFrameBackground(gfx::Canvas* canvas) {
    689   // We only need to paint the title-bar since no resizing border is shown.
    690   // Instead, we allow part of the inner content area be used to trigger the
    691   // mouse resizing.
    692   int titlebar_height = TitlebarHeight();
    693   const gfx::ImageSkia* image = GetFrameBackground(GetPaintState());
    694   canvas->TileImageInt(*image, 0, 0, width(), titlebar_height);
    695 
    696   if (is_frameless_)
    697     return;
    698 
    699   // Left border, below title-bar.
    700   canvas->TileImageInt(*image, 0, titlebar_height, kNonAeroBorderThickness,
    701       height() - titlebar_height);
    702 
    703   // Right border, below title-bar.
    704   canvas->TileImageInt(*image, width() - kNonAeroBorderThickness,
    705       titlebar_height, kNonAeroBorderThickness, height() - titlebar_height);
    706 
    707   // Bottom border.
    708   canvas->TileImageInt(*image, 0, height() - kNonAeroBorderThickness, width(),
    709       kNonAeroBorderThickness);
    710 }
    711 
    712 void PanelFrameView::PaintFrameEdge(gfx::Canvas* canvas) {
    713 #if defined(OS_WIN)
    714   // Border is not needed when panel is not shown as minimized.
    715   if (GetPaintState() != PAINT_AS_MINIMIZED)
    716     return;
    717 
    718   const gfx::ImageSkia& top_left_image = GetTopLeftCornerImage(corner_style_);
    719   const gfx::ImageSkia& top_right_image = GetTopRightCornerImage(corner_style_);
    720   const gfx::ImageSkia& bottom_left_image =
    721       GetBottomLeftCornerImage(corner_style_);
    722   const gfx::ImageSkia& bottom_right_image =
    723       GetBottomRightCornerImage(corner_style_);
    724   const gfx::ImageSkia& top_image = GetTopEdgeImage();
    725   const gfx::ImageSkia& bottom_image = GetBottomEdgeImage();
    726   const gfx::ImageSkia& left_image = GetLeftEdgeImage();
    727   const gfx::ImageSkia& right_image = GetRightEdgeImage();
    728 
    729   // Draw the top border.
    730   canvas->DrawImageInt(top_left_image, 0, 0);
    731   canvas->TileImageInt(top_image,
    732                        top_left_image.width(),
    733                        0,
    734                        width() - top_right_image.width(),
    735                        top_image.height());
    736   canvas->DrawImageInt(top_right_image, width() - top_right_image.width(), 0);
    737 
    738   // Draw the right border.
    739   canvas->TileImageInt(right_image,
    740                        width() - right_image.width(),
    741                        top_right_image.height(),
    742                        right_image.width(),
    743                        height() - top_right_image.height() -
    744                            bottom_right_image.height());
    745 
    746   // Draw the bottom border.
    747   canvas->DrawImageInt(bottom_right_image,
    748                        width() - bottom_right_image.width(),
    749                        height() - bottom_right_image.height());
    750   canvas->TileImageInt(bottom_image,
    751                        bottom_left_image.width(),
    752                        height() - bottom_image.height(),
    753                        width() - bottom_left_image.width() -
    754                            bottom_right_image.width(),
    755                        bottom_image.height());
    756   canvas->DrawImageInt(bottom_left_image,
    757                        0,
    758                        height() - bottom_left_image.height());
    759 
    760   // Draw the left border.
    761   canvas->TileImageInt(left_image,
    762                        0,
    763                        top_left_image.height(),
    764                        left_image.width(),
    765                        height() - top_left_image.height() -
    766                            bottom_left_image.height());
    767 #endif
    768 }
    769