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