Home | History | Annotate | Download | only in views
      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/constrained_window_views.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/command_line.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "chrome/app/chrome_command_ids.h"
     12 #include "chrome/browser/platform_util.h"
     13 #include "chrome/browser/profiles/profile.h"
     14 #include "chrome/browser/themes/theme_properties.h"
     15 #include "chrome/browser/ui/browser_finder.h"
     16 #include "chrome/browser/ui/toolbar/toolbar_model.h"
     17 #include "chrome/browser/ui/views/frame/browser_view.h"
     18 #include "chrome/browser/ui/views/theme_image_mapper.h"
     19 #include "chrome/common/chrome_constants.h"
     20 #include "components/web_modal/web_contents_modal_dialog_host.h"
     21 #include "components/web_modal/web_contents_modal_dialog_manager.h"
     22 #include "content/public/browser/navigation_controller.h"
     23 #include "content/public/browser/web_contents.h"
     24 #include "content/public/browser/web_contents_view.h"
     25 #include "grit/chromium_strings.h"
     26 #include "grit/generated_resources.h"
     27 #include "grit/theme_resources.h"
     28 #include "grit/ui_resources.h"
     29 #include "net/base/net_util.h"
     30 #include "ui/aura/client/aura_constants.h"
     31 #include "ui/base/hit_test.h"
     32 #include "ui/base/resource/resource_bundle.h"
     33 #include "ui/base/ui_base_switches.h"
     34 #include "ui/gfx/canvas.h"
     35 #include "ui/gfx/font.h"
     36 #include "ui/gfx/path.h"
     37 #include "ui/gfx/rect.h"
     38 #include "ui/gfx/screen.h"
     39 #include "ui/views/border.h"
     40 #include "ui/views/color_constants.h"
     41 #include "ui/views/controls/button/image_button.h"
     42 #include "ui/views/focus/focus_manager.h"
     43 #include "ui/views/views_delegate.h"
     44 #include "ui/views/widget/widget.h"
     45 #include "ui/views/widget/widget_observer.h"
     46 #include "ui/views/window/client_view.h"
     47 #include "ui/views/window/dialog_client_view.h"
     48 #include "ui/views/window/dialog_delegate.h"
     49 #include "ui/views/window/frame_background.h"
     50 #include "ui/views/window/non_client_view.h"
     51 #include "ui/views/window/window_resources.h"
     52 #include "ui/views/window/window_shape.h"
     53 
     54 #if defined(OS_WIN) && !defined(USE_AURA)
     55 #include "ui/base/win/shell.h"
     56 #include "ui/views/widget/native_widget_win.h"
     57 #endif
     58 
     59 #if defined(USE_AURA)
     60 #include "ui/aura/window.h"
     61 #include "ui/views/corewm/shadow_types.h"
     62 #include "ui/views/corewm/visibility_controller.h"
     63 #include "ui/views/corewm/window_animations.h"
     64 #include "ui/views/corewm/window_modality_controller.h"
     65 #endif
     66 
     67 #if defined(USE_ASH)
     68 #include "ash/ash_constants.h"
     69 #include "ash/shell.h"
     70 #include "ash/wm/custom_frame_view_ash.h"
     71 #endif
     72 
     73 using base::TimeDelta;
     74 using web_modal::WebContentsModalDialogHost;
     75 using web_modal::WebContentsModalDialogHostObserver;
     76 
     77 namespace views {
     78 class ClientView;
     79 }
     80 
     81 namespace {
     82 // The name of a key to store on the window handle to associate
     83 // WebContentsModalDialogHostObserverViews with the Widget.
     84 const char* const kWebContentsModalDialogHostObserverViewsKey =
     85     "__WEB_CONTENTS_MODAL_DIALOG_HOST_OBSERVER_VIEWS__";
     86 
     87 // Applies positioning changes from the WebContentsModalDialogHost to the
     88 // Widget.
     89 class WebContentsModalDialogHostObserverViews
     90     : public views::WidgetObserver,
     91       public WebContentsModalDialogHostObserver {
     92  public:
     93   WebContentsModalDialogHostObserverViews(
     94       WebContentsModalDialogHost* host,
     95       views::Widget* target_widget,
     96       const char *const native_window_property)
     97       : host_(host),
     98         target_widget_(target_widget),
     99         native_window_property_(native_window_property) {
    100     DCHECK(host_);
    101     DCHECK(target_widget_);
    102     host_->AddObserver(this);
    103     target_widget_->AddObserver(this);
    104   }
    105 
    106   virtual ~WebContentsModalDialogHostObserverViews() {
    107     host_->RemoveObserver(this);
    108     target_widget_->RemoveObserver(this);
    109     target_widget_->SetNativeWindowProperty(native_window_property_,
    110                                             NULL);
    111   }
    112 
    113   // WidgetObserver overrides
    114   virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE {
    115     delete this;
    116   }
    117 
    118   // WebContentsModalDialogHostObserver overrides
    119   virtual void OnPositionRequiresUpdate() OVERRIDE {
    120     gfx::Size size = target_widget_->GetWindowBoundsInScreen().size();
    121     gfx::Point position = host_->GetDialogPosition(size);
    122     views::Border* border =
    123         target_widget_->non_client_view()->frame_view()->border();
    124     // Border may be null during widget initialization.
    125     if (border) {
    126       // Align the first row of pixels inside the border. This is the apparent
    127       // top of the dialog.
    128       position.set_y(position.y() - border->GetInsets().top());
    129     }
    130 
    131     if (target_widget_->is_top_level())
    132       position += views::Widget::GetWidgetForNativeView(host_->GetHostView())->
    133           GetClientAreaBoundsInScreen().OffsetFromOrigin();
    134 
    135     target_widget_->SetBounds(gfx::Rect(position, size));
    136   }
    137 
    138  private:
    139   WebContentsModalDialogHost* host_;
    140   views::Widget* target_widget_;
    141   const char* const native_window_property_;
    142 
    143   DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogHostObserverViews);
    144 };
    145 
    146 }  // namespace
    147 
    148 // An enumeration of image resources used by this window.
    149 enum {
    150   FRAME_PART_IMAGE_FIRST = 0,  // Must be first.
    151 
    152   // Window Frame Border.
    153   FRAME_BOTTOM_EDGE,
    154   FRAME_BOTTOM_LEFT_CORNER,
    155   FRAME_BOTTOM_RIGHT_CORNER,
    156   FRAME_LEFT_EDGE,
    157   FRAME_RIGHT_EDGE,
    158   FRAME_TOP_EDGE,
    159   FRAME_TOP_LEFT_CORNER,
    160   FRAME_TOP_RIGHT_CORNER,
    161 
    162   FRAME_PART_IMAGE_COUNT  // Must be last.
    163 };
    164 
    165 static const int kXPFramePartIDs[] = {
    166     0,
    167     IDR_WINDOW_BOTTOM_CENTER, IDR_WINDOW_BOTTOM_LEFT_CORNER,
    168     IDR_WINDOW_BOTTOM_RIGHT_CORNER, IDR_WINDOW_LEFT_SIDE,
    169     IDR_WINDOW_RIGHT_SIDE, IDR_WINDOW_TOP_CENTER,
    170     IDR_WINDOW_TOP_LEFT_CORNER, IDR_WINDOW_TOP_RIGHT_CORNER,
    171     0 };
    172 static const int kVistaFramePartIDs[] = {
    173     0,
    174     IDR_CONSTRAINED_BOTTOM_CENTER_V, IDR_CONSTRAINED_BOTTOM_LEFT_CORNER_V,
    175     IDR_CONSTRAINED_BOTTOM_RIGHT_CORNER_V, IDR_CONSTRAINED_LEFT_SIDE_V,
    176     IDR_CONSTRAINED_RIGHT_SIDE_V, IDR_CONSTRAINED_TOP_CENTER_V,
    177     IDR_CONSTRAINED_TOP_LEFT_CORNER_V, IDR_CONSTRAINED_TOP_RIGHT_CORNER_V,
    178     0 };
    179 
    180 class XPWindowResources : public views::WindowResources {
    181  public:
    182   XPWindowResources() {
    183     InitClass();
    184   }
    185   virtual ~XPWindowResources() {}
    186 
    187   virtual gfx::ImageSkia* GetPartImage(
    188       views::FramePartImage part_id) const OVERRIDE {
    189     return images_[part_id];
    190   }
    191 
    192  private:
    193   static void InitClass() {
    194     static bool initialized = false;
    195     if (!initialized) {
    196       ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    197       for (int i = 0; i < FRAME_PART_IMAGE_COUNT; ++i) {
    198         int id = kXPFramePartIDs[i];
    199         if (id != 0)
    200           images_[i] = rb.GetImageSkiaNamed(id);
    201       }
    202       initialized = true;
    203     }
    204   }
    205 
    206   static gfx::ImageSkia* images_[FRAME_PART_IMAGE_COUNT];
    207 
    208   DISALLOW_COPY_AND_ASSIGN(XPWindowResources);
    209 };
    210 
    211 class VistaWindowResources : public views::WindowResources {
    212  public:
    213   VistaWindowResources() {
    214     InitClass();
    215   }
    216   virtual ~VistaWindowResources() {}
    217 
    218   virtual gfx::ImageSkia* GetPartImage(
    219       views::FramePartImage part_id) const OVERRIDE {
    220     return images_[part_id];
    221   }
    222 
    223  private:
    224   static void InitClass() {
    225     static bool initialized = false;
    226     if (!initialized) {
    227       ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    228       for (int i = 0; i < FRAME_PART_IMAGE_COUNT; ++i) {
    229         int id = kVistaFramePartIDs[i];
    230         if (id != 0)
    231           images_[i] = rb.GetImageSkiaNamed(id);
    232       }
    233       initialized = true;
    234     }
    235   }
    236 
    237   static gfx::ImageSkia* images_[FRAME_PART_IMAGE_COUNT];
    238 
    239   DISALLOW_COPY_AND_ASSIGN(VistaWindowResources);
    240 };
    241 
    242 gfx::ImageSkia* XPWindowResources::images_[];
    243 gfx::ImageSkia* VistaWindowResources::images_[];
    244 
    245 class ConstrainedWindowFrameView : public views::NonClientFrameView,
    246                                    public views::ButtonListener {
    247  public:
    248   ConstrainedWindowFrameView(views::Widget* container,
    249                              bool browser_is_off_the_record);
    250   virtual ~ConstrainedWindowFrameView();
    251 
    252   virtual void UpdateWindowTitle() OVERRIDE;
    253 
    254   // Overridden from views::NonClientFrameView:
    255   virtual gfx::Rect GetBoundsForClientView() const OVERRIDE;
    256   virtual gfx::Rect GetWindowBoundsForClientBounds(
    257       const gfx::Rect& client_bounds) const OVERRIDE;
    258   virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE;
    259   virtual void GetWindowMask(const gfx::Size& size,
    260                              gfx::Path* window_mask) OVERRIDE;
    261   virtual void ResetWindowControls() OVERRIDE {}
    262   virtual void UpdateWindowIcon() OVERRIDE {}
    263 
    264   // Overridden from views::View:
    265   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
    266   virtual void Layout() OVERRIDE;
    267   virtual void OnThemeChanged() OVERRIDE;
    268 
    269   // Overridden from views::ButtonListener:
    270   virtual void ButtonPressed(views::Button* sender,
    271                              const ui::Event& event) OVERRIDE;
    272 
    273  private:
    274   // Returns the thickness of the entire nonclient left, right, and bottom
    275   // borders, including both the window frame and any client edge.
    276   int NonClientBorderThickness() const;
    277 
    278   // Returns the height of the entire nonclient top border, including the window
    279   // frame, any title area, and any connected client edge.
    280   int NonClientTopBorderHeight() const;
    281 
    282   // Returns the thickness of the nonclient portion of the 3D edge along the
    283   // bottom of the titlebar.
    284   int TitlebarBottomThickness() const;
    285 
    286   // Returns what the size of the titlebar icon would be if there was one.
    287   int IconSize() const;
    288 
    289   // Returns what the titlebar icon's bounds would be if there was one.
    290   gfx::Rect IconBounds() const;
    291 
    292   // Paints different parts of the window to the incoming canvas.
    293   void PaintFrameBorder(gfx::Canvas* canvas);
    294   void PaintTitleBar(gfx::Canvas* canvas);
    295   void PaintClientEdge(gfx::Canvas* canvas);
    296 
    297   // Layout various sub-components of this view.
    298   void LayoutWindowControls();
    299   void LayoutTitleBar();
    300 
    301   // Returns the bounds of the client area for the specified view size.
    302   gfx::Rect CalculateClientAreaBounds(int width, int height) const;
    303 
    304   SkColor GetTitleColor() const {
    305     return browser_is_off_the_record_
    306 #if defined(OS_WIN) && !defined(USE_AURA)
    307             || !ui::win::IsAeroGlassEnabled()
    308 #endif
    309             ? SK_ColorWHITE : SK_ColorBLACK;
    310   }
    311 
    312   // Loads the appropriate set of WindowResources for the frame view.
    313   void InitWindowResources();
    314 
    315   views::Widget* container_;
    316 
    317   bool browser_is_off_the_record_;
    318 
    319   scoped_ptr<views::WindowResources> resources_;
    320 
    321   gfx::Rect title_bounds_;
    322 
    323   views::ImageButton* close_button_;
    324 
    325   // The bounds of the ClientView.
    326   gfx::Rect client_view_bounds_;
    327 
    328   // Background painter for the frame.
    329   scoped_ptr<views::FrameBackground> frame_background_;
    330 
    331   static void InitClass();
    332 
    333   // The font to be used to render the titlebar text.
    334   static const gfx::Font* title_font_;
    335 
    336   DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowFrameView);
    337 };
    338 
    339 const gfx::Font* ConstrainedWindowFrameView::title_font_ = NULL;
    340 
    341 namespace {
    342 // The frame border is only visible in restored mode and is hardcoded to 4 px on
    343 // each side regardless of the system window border size.
    344 const int kFrameBorderThickness = 4;
    345 // Various edges of the frame border have a 1 px shadow along their edges; in a
    346 // few cases we shift elements based on this amount for visual appeal.
    347 const int kFrameShadowThickness = 1;
    348 // In the window corners, the resize areas don't actually expand bigger, but the
    349 // 16 px at the end of each edge triggers diagonal resizing.
    350 const int kResizeAreaCornerSize = 16;
    351 // The titlebar never shrinks too short to show the caption button plus some
    352 // padding below it.
    353 const int kCaptionButtonHeightWithPadding = 19;
    354 // The titlebar has a 2 px 3D edge along the top and bottom.
    355 const int kTitlebarTopAndBottomEdgeThickness = 2;
    356 // The icon would never shrink below 16 px on a side, if there was one.
    357 const int kIconMinimumSize = 16;
    358 // The title text starts 2 px from the right edge of the left frame border.
    359 const int kTitleLeftSpacing = 2;
    360 // There is a 5 px gap between the title text and the caption buttons.
    361 const int kTitleCaptionSpacing = 5;
    362 
    363 const SkColor kContentsBorderShadow = SkColorSetARGB(51, 0, 0, 0);
    364 
    365 }  // namespace
    366 
    367 ConstrainedWindowFrameView::ConstrainedWindowFrameView(
    368     views::Widget* container, bool browser_is_off_the_record)
    369     : NonClientFrameView(),
    370       container_(container),
    371       browser_is_off_the_record_(browser_is_off_the_record),
    372       close_button_(new views::ImageButton(this)),
    373       frame_background_(new views::FrameBackground()) {
    374   InitClass();
    375   InitWindowResources();
    376 
    377   // Constrained windows always use the custom frame - they just have a
    378   // different set of images.
    379   container->set_frame_type(views::Widget::FRAME_TYPE_FORCE_CUSTOM);
    380 
    381   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    382   close_button_->SetImage(views::CustomButton::STATE_NORMAL,
    383                           rb.GetImageSkiaNamed(IDR_CLOSE_SA));
    384   close_button_->SetImage(views::CustomButton::STATE_HOVERED,
    385                           rb.GetImageSkiaNamed(IDR_CLOSE_SA_H));
    386   close_button_->SetImage(views::CustomButton::STATE_PRESSED,
    387                           rb.GetImageSkiaNamed(IDR_CLOSE_SA_P));
    388   close_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
    389                                    views::ImageButton::ALIGN_MIDDLE);
    390   AddChildView(close_button_);
    391 }
    392 
    393 ConstrainedWindowFrameView::~ConstrainedWindowFrameView() {
    394 }
    395 
    396 void ConstrainedWindowFrameView::UpdateWindowTitle() {
    397   SchedulePaintInRect(title_bounds_);
    398 }
    399 
    400 gfx::Rect ConstrainedWindowFrameView::GetBoundsForClientView() const {
    401   return client_view_bounds_;
    402 }
    403 
    404 gfx::Rect ConstrainedWindowFrameView::GetWindowBoundsForClientBounds(
    405     const gfx::Rect& client_bounds) const {
    406   int top_height = NonClientTopBorderHeight();
    407   int border_thickness = NonClientBorderThickness();
    408   return gfx::Rect(std::max(0, client_bounds.x() - border_thickness),
    409                    std::max(0, client_bounds.y() - top_height),
    410                    client_bounds.width() + (2 * border_thickness),
    411                    client_bounds.height() + top_height + border_thickness);
    412 }
    413 
    414 int ConstrainedWindowFrameView::NonClientHitTest(const gfx::Point& point) {
    415   if (!bounds().Contains(point))
    416     return HTNOWHERE;
    417 
    418   int frame_component =
    419       container_->client_view()->NonClientHitTest(point);
    420 
    421   // See if we're in the sysmenu region.  (We check the ClientView first to be
    422   // consistent with OpaqueBrowserFrameView; it's not really necessary here.)
    423   gfx::Rect sysmenu_rect(IconBounds());
    424   sysmenu_rect.set_x(GetMirroredXForRect(sysmenu_rect));
    425   if (sysmenu_rect.Contains(point))
    426     return (frame_component == HTCLIENT) ? HTCLIENT : HTSYSMENU;
    427 
    428   if (frame_component != HTNOWHERE)
    429     return frame_component;
    430 
    431   // Then see if the point is within any of the window controls.
    432   if (close_button_->GetMirroredBounds().Contains(point))
    433     return HTCLOSE;
    434 
    435   int window_component = GetHTComponentForFrame(point, kFrameBorderThickness,
    436       NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize,
    437       container_->widget_delegate()->CanResize());
    438   // Fall back to the caption if no other component matches.
    439   return (window_component == HTNOWHERE) ? HTCAPTION : window_component;
    440 }
    441 
    442 void ConstrainedWindowFrameView::GetWindowMask(const gfx::Size& size,
    443                                                gfx::Path* window_mask) {
    444   DCHECK(window_mask);
    445   views::GetDefaultWindowMask(size, window_mask);
    446 }
    447 
    448 void ConstrainedWindowFrameView::OnPaint(gfx::Canvas* canvas) {
    449   PaintFrameBorder(canvas);
    450   PaintTitleBar(canvas);
    451   PaintClientEdge(canvas);
    452 }
    453 
    454 void ConstrainedWindowFrameView::Layout() {
    455   LayoutWindowControls();
    456   LayoutTitleBar();
    457   client_view_bounds_ = CalculateClientAreaBounds(width(), height());
    458 }
    459 
    460 void ConstrainedWindowFrameView::OnThemeChanged() {
    461   InitWindowResources();
    462 }
    463 
    464 void ConstrainedWindowFrameView::ButtonPressed(
    465     views::Button* sender, const ui::Event& event) {
    466   if (sender == close_button_)
    467     container_->Close();
    468 }
    469 
    470 int ConstrainedWindowFrameView::NonClientBorderThickness() const {
    471   return kFrameBorderThickness + kClientEdgeThickness;
    472 }
    473 
    474 int ConstrainedWindowFrameView::NonClientTopBorderHeight() const {
    475   return std::max(kFrameBorderThickness + IconSize(),
    476                   kFrameShadowThickness + kCaptionButtonHeightWithPadding) +
    477       TitlebarBottomThickness();
    478 }
    479 
    480 int ConstrainedWindowFrameView::TitlebarBottomThickness() const {
    481   return kTitlebarTopAndBottomEdgeThickness + kClientEdgeThickness;
    482 }
    483 
    484 int ConstrainedWindowFrameView::IconSize() const {
    485 #if defined(OS_WIN)
    486   // This metric scales up if either the titlebar height or the titlebar font
    487   // size are increased.
    488   return GetSystemMetrics(SM_CYSMICON);
    489 #else
    490   return std::max(title_font_->GetHeight(), kIconMinimumSize);
    491 #endif
    492 }
    493 
    494 gfx::Rect ConstrainedWindowFrameView::IconBounds() const {
    495   int size = IconSize();
    496   // Our frame border has a different "3D look" than Windows'.  Theirs has a
    497   // more complex gradient on the top that they push their icon/title below;
    498   // then the maximized window cuts this off and the icon/title are centered
    499   // in the remaining space.  Because the apparent shape of our border is
    500   // simpler, using the same positioning makes things look slightly uncentered
    501   // with restored windows, so instead of calculating the remaining space from
    502   // below the frame border, we calculate from below the 3D edge.
    503   int unavailable_px_at_top = kTitlebarTopAndBottomEdgeThickness;
    504   // When the icon is shorter than the minimum space we reserve for the caption
    505   // button, we vertically center it.  We want to bias rounding to put extra
    506   // space above the icon, since the 3D edge + client edge below looks (to the
    507   // eye) more like additional space than does the 3D edge above; hence the +1.
    508   int y = unavailable_px_at_top + (NonClientTopBorderHeight() -
    509       unavailable_px_at_top - size - TitlebarBottomThickness() + 1) / 2;
    510   return gfx::Rect(kFrameBorderThickness + kTitleLeftSpacing, y, size, size);
    511 }
    512 
    513 void ConstrainedWindowFrameView::PaintFrameBorder(gfx::Canvas* canvas) {
    514   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    515   frame_background_->set_frame_color(ThemeProperties::GetDefaultColor(
    516       ThemeProperties::COLOR_FRAME));
    517   chrome::HostDesktopType desktop_type =
    518       chrome::GetHostDesktopTypeForNativeView(GetWidget()->GetNativeView());
    519   gfx::ImageSkia* theme_frame = rb.GetImageSkiaNamed(
    520       chrome::MapThemeImage(desktop_type, IDR_THEME_FRAME));
    521   frame_background_->set_theme_image(theme_frame);
    522   frame_background_->set_theme_overlay_image(NULL);
    523   frame_background_->set_top_area_height(theme_frame->height());
    524 
    525   frame_background_->SetCornerImages(
    526       resources_->GetPartImage(FRAME_TOP_LEFT_CORNER),
    527       resources_->GetPartImage(FRAME_TOP_RIGHT_CORNER),
    528       resources_->GetPartImage(FRAME_BOTTOM_LEFT_CORNER),
    529       resources_->GetPartImage(FRAME_BOTTOM_RIGHT_CORNER));
    530   frame_background_->SetSideImages(
    531       resources_->GetPartImage(FRAME_LEFT_EDGE),
    532       resources_->GetPartImage(FRAME_TOP_EDGE),
    533       resources_->GetPartImage(FRAME_RIGHT_EDGE),
    534       resources_->GetPartImage(FRAME_BOTTOM_EDGE));
    535   frame_background_->PaintRestored(canvas, this);
    536 }
    537 
    538 void ConstrainedWindowFrameView::PaintTitleBar(gfx::Canvas* canvas) {
    539   canvas->DrawStringInt(
    540       container_->widget_delegate()->GetWindowTitle(),
    541       *title_font_, GetTitleColor(), GetMirroredXForRect(title_bounds_),
    542       title_bounds_.y(), title_bounds_.width(), title_bounds_.height());
    543 }
    544 
    545 void ConstrainedWindowFrameView::PaintClientEdge(gfx::Canvas* canvas) {
    546   gfx::Rect client_edge_bounds(CalculateClientAreaBounds(width(), height()));
    547   client_edge_bounds.Inset(-kClientEdgeThickness, -kClientEdgeThickness);
    548   gfx::Rect frame_shadow_bounds(client_edge_bounds);
    549   frame_shadow_bounds.Inset(-kFrameShadowThickness, -kFrameShadowThickness);
    550 
    551   canvas->FillRect(frame_shadow_bounds, kContentsBorderShadow);
    552   canvas->FillRect(client_edge_bounds, views::kClientEdgeColor);
    553 }
    554 
    555 void ConstrainedWindowFrameView::LayoutWindowControls() {
    556   gfx::Size close_button_size = close_button_->GetPreferredSize();
    557   close_button_->SetBounds(
    558       width() - kFrameBorderThickness - close_button_size.width(),
    559       kFrameShadowThickness, close_button_size.width(),
    560       close_button_size.height());
    561 }
    562 
    563 void ConstrainedWindowFrameView::LayoutTitleBar() {
    564   // The window title is based on the calculated icon position, even though'
    565   // there is no icon in constrained windows.
    566   gfx::Rect icon_bounds(IconBounds());
    567   int title_x = icon_bounds.x();
    568   int title_height = title_font_->GetHeight();
    569   // We bias the title position so that when the difference between the icon and
    570   // title heights is odd, the extra pixel of the title is above the vertical
    571   // midline rather than below.  This compensates for how the icon is already
    572   // biased downwards (see IconBounds()) and helps prevent descenders on the
    573   // title from overlapping the 3D edge at the bottom of the titlebar.
    574   title_bounds_.SetRect(title_x,
    575       icon_bounds.y() + ((icon_bounds.height() - title_height - 1) / 2),
    576       std::max(0, close_button_->x() - kTitleCaptionSpacing - title_x),
    577       title_height);
    578 }
    579 
    580 gfx::Rect ConstrainedWindowFrameView::CalculateClientAreaBounds(
    581     int width,
    582     int height) const {
    583   int top_height = NonClientTopBorderHeight();
    584   int border_thickness = NonClientBorderThickness();
    585   return gfx::Rect(border_thickness, top_height,
    586                    std::max(0, width - (2 * border_thickness)),
    587                    std::max(0, height - top_height - border_thickness));
    588 }
    589 
    590 void ConstrainedWindowFrameView::InitWindowResources() {
    591 #if defined(OS_WIN) && !defined(USE_AURA)
    592   resources_.reset(ui::win::IsAeroGlassEnabled() ?
    593       static_cast<views::WindowResources*>(new VistaWindowResources) :
    594       new XPWindowResources);
    595 #else
    596   // TODO(oshima): Use aura frame decoration.
    597   resources_.reset(new XPWindowResources);
    598 #endif
    599 }
    600 
    601 // static
    602 void ConstrainedWindowFrameView::InitClass() {
    603   static bool initialized = false;
    604   if (!initialized) {
    605 #if defined(OS_WIN) && !defined(USE_AURA)
    606     title_font_ = new gfx::Font(views::NativeWidgetWin::GetWindowTitleFont());
    607 #else
    608     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    609     title_font_ = &rb.GetFont(ui::ResourceBundle::MediumFont);
    610 #endif
    611     initialized = true;
    612   }
    613 }
    614 
    615 #if defined(USE_ASH)
    616 // Ash has its own window frames, but we need the special close semantics for
    617 // constrained windows.
    618 class ConstrainedWindowFrameViewAsh : public ash::CustomFrameViewAsh {
    619  public:
    620   explicit ConstrainedWindowFrameViewAsh()
    621       : ash::CustomFrameViewAsh(),
    622         container_(NULL) {
    623   }
    624 
    625   void Init(views::Widget* container) {
    626     container_ = container;
    627     ash::CustomFrameViewAsh::Init(container);
    628     // Always use "active" look.
    629     SetInactiveRenderingDisabled(true);
    630   }
    631 
    632   // views::ButtonListener overrides:
    633   virtual void ButtonPressed(views::Button* sender,
    634                              const ui::Event& event) OVERRIDE {
    635     if (sender == close_button())
    636       container_->Close();
    637   }
    638 
    639  private:
    640   views::Widget* container_;  // not owned
    641   DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowFrameViewAsh);
    642 };
    643 #endif  // defined(USE_ASH)
    644 
    645 views::Widget* CreateWebContentsModalDialogViews(
    646     views::WidgetDelegate* widget_delegate,
    647     gfx::NativeView parent,
    648     WebContentsModalDialogHost* dialog_host) {
    649   views::Widget* dialog = new views::Widget;
    650 
    651   views::Widget::InitParams params;
    652   params.delegate = widget_delegate;
    653   params.child = true;
    654   WebContentsModalDialogHostObserver* dialog_host_observer = NULL;
    655   if (views::DialogDelegate::UseNewStyle()) {
    656     params.parent = dialog_host->GetHostView();
    657     params.remove_standard_frame = true;
    658     dialog_host_observer =
    659         new WebContentsModalDialogHostObserverViews(
    660             dialog_host,
    661             dialog,
    662             kWebContentsModalDialogHostObserverViewsKey);
    663 #if defined(USE_AURA)
    664     params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
    665 #endif
    666   } else {
    667     params.parent = parent;
    668   }
    669 
    670   dialog->Init(params);
    671 
    672 #if defined(USE_AURA)
    673   if (views::DialogDelegate::UseNewStyle()) {
    674     // TODO(msw): Add a matching shadow type and remove the bubble frame border?
    675     views::corewm::SetShadowType(dialog->GetNativeWindow(),
    676                                  views::corewm::SHADOW_TYPE_NONE);
    677   }
    678 #endif
    679 
    680   if (dialog_host_observer) {
    681     dialog_host_observer->OnPositionRequiresUpdate();
    682     dialog->SetNativeWindowProperty(kWebContentsModalDialogHostObserverViewsKey,
    683                                     dialog_host_observer);
    684   }
    685 
    686   return dialog;
    687 }
    688 
    689 views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog,
    690                                              gfx::NativeWindow parent) {
    691   views::Widget* widget =
    692       views::DialogDelegate::CreateDialogWidget(dialog, NULL, parent);
    693   if (!dialog->UseNewStyleForThisDialog())
    694     return widget;
    695 
    696   // Get the browser dialog management and hosting components from |parent|.
    697   Browser* browser = chrome::FindBrowserWithWindow(parent);
    698   if (browser) {
    699     ChromeWebModalDialogManagerDelegate* manager = browser;
    700     WebContentsModalDialogHost* host = manager->GetWebContentsModalDialogHost();
    701     DCHECK_EQ(parent, host->GetHostView());
    702     WebContentsModalDialogHostObserver* dialog_host_observer =
    703         new WebContentsModalDialogHostObserverViews(
    704             host, widget, kWebContentsModalDialogHostObserverViewsKey);
    705     dialog_host_observer->OnPositionRequiresUpdate();
    706   }
    707   return widget;
    708 }
    709 
    710 views::NonClientFrameView* CreateConstrainedStyleNonClientFrameView(
    711     views::Widget* widget,
    712     content::BrowserContext* browser_context) {
    713   if (views::DialogDelegate::UseNewStyle()) {
    714 #if defined(USE_AURA)
    715     const bool force_opaque_border = false;
    716 #else
    717     const bool force_opaque_border = true;
    718 #endif
    719     return views::DialogDelegate::CreateNewStyleFrameView(widget,
    720                                                           force_opaque_border);
    721   }
    722 #if defined(USE_ASH)
    723   ConstrainedWindowFrameViewAsh* frame = new ConstrainedWindowFrameViewAsh;
    724   frame->Init(widget);
    725   return frame;
    726 #endif
    727   return new ConstrainedWindowFrameView(widget,
    728                                         browser_context->IsOffTheRecord());
    729 }
    730