Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / panels / panel_frame_view.cc
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() {
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() {
505   return panel_view_->GetMinimumSize();
506 }
507
508 gfx::Size PanelFrameView::GetMaximumSize() {
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 }