| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view_aura.h" | 5 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view_aura.h" |
| 6 | 6 |
| 7 #include "chrome/browser/ui/views/frame/browser_frame.h" | 7 #include "chrome/browser/ui/views/frame/browser_frame.h" |
| 8 #include "chrome/browser/ui/views/frame/browser_view.h" | 8 #include "chrome/browser/ui/views/frame/browser_view.h" |
| 9 #include "content/public/browser/web_contents.h" |
| 9 #include "grit/generated_resources.h" // Accessibility names | 10 #include "grit/generated_resources.h" // Accessibility names |
| 11 #include "grit/theme_resources.h" |
| 12 #include "grit/theme_resources_standard.h" |
| 10 #include "grit/ui_resources.h" | 13 #include "grit/ui_resources.h" |
| 11 #include "third_party/skia/include/core/SkCanvas.h" | 14 #include "third_party/skia/include/core/SkCanvas.h" |
| 12 #include "third_party/skia/include/core/SkColor.h" | |
| 13 #include "third_party/skia/include/core/SkPaint.h" | 15 #include "third_party/skia/include/core/SkPaint.h" |
| 14 #include "ui/aura/cursor.h" | 16 #include "third_party/skia/include/core/SkPath.h" |
| 15 #include "ui/base/animation/throb_animation.h" | 17 #include "third_party/skia/include/core/SkShader.h" |
| 18 #include "ui/aura/window.h" |
| 19 #include "ui/base/accessibility/accessible_view_state.h" |
| 16 #include "ui/base/hit_test.h" | 20 #include "ui/base/hit_test.h" |
| 17 #include "ui/base/l10n/l10n_util.h" | 21 #include "ui/base/l10n/l10n_util.h" |
| 18 #include "ui/base/resource/resource_bundle.h" | 22 #include "ui/base/resource/resource_bundle.h" |
| 23 #include "ui/base/theme_provider.h" |
| 19 #include "ui/gfx/canvas.h" | 24 #include "ui/gfx/canvas.h" |
| 20 #include "ui/gfx/compositor/layer.h" | 25 #include "ui/gfx/font.h" |
| 21 #include "ui/views/controls/button/custom_button.h" | 26 #include "ui/views/controls/button/image_button.h" |
| 22 #include "ui/views/widget/widget.h" | 27 #include "ui/views/widget/widget.h" |
| 23 #include "ui/views/widget/widget_delegate.h" | 28 #include "ui/views/widget/widget_delegate.h" |
| 24 | 29 |
| 25 namespace { | 30 namespace { |
| 26 // Our window is larger than it appears, as it includes space around the edges | |
| 27 // where resize handles can appear. | |
| 28 const int kResizeBorderThickness = 8; | |
| 29 // The top edge is a little thinner, as it is not draggable for resize. | |
| 30 const int kTopBorderThickness = 4; | |
| 31 // Offset between top of non-client frame and top edge of opaque frame | |
| 32 // background at start of slide-in animation. | |
| 33 const int kFrameBackgroundTopOffset = 25; | |
| 34 | 31 |
| 35 // Width of a persistent border that we show around the window (using | 32 // Size of border along top edge, used for resize handle computations. |
| 36 // FrameBackground) even when the resize border isn't visible. | 33 const int kTopThickness = 1; |
| 37 const int kPersistentBorderThickness = 2; | 34 // TODO(jamescook): Border is specified to be a single pixel overlapping |
| 35 // the web content and may need to be built into the shadow layers instead. |
| 36 const int kBorderThickness = 0; |
| 37 // Number of pixels outside the window frame to look for resize events. |
| 38 const int kResizeAreaOutsideBounds = 6; |
| 39 // In the window corners, the resize areas don't actually expand bigger, but the |
| 40 // 16 px at the end of each edge triggers diagonal resizing. |
| 41 const int kResizeAreaCornerSize = 16; |
| 42 // Space between left edge of window and popup window icon. |
| 43 const int kIconOffsetX = 4; |
| 44 // Space between top of window and popup window icon. |
| 45 const int kIconOffsetY = 4; |
| 46 // Height and width of window icon. |
| 47 const int kIconSize = 16; |
| 48 // Space between the title text and the caption buttons. |
| 49 const int kTitleLogoSpacing = 5; |
| 50 // Space between title text and icon. |
| 51 const int kTitleOffsetX = 4; |
| 52 // Space between title text and top of window. |
| 53 const int kTitleOffsetY = 6; |
| 54 // Space between close button and right edge of window. |
| 55 const int kCloseButtonOffsetX = 0; |
| 56 // Space between close button and top edge of window. |
| 57 const int kCloseButtonOffsetY = 0; |
| 58 // Space between left edge of window and tabstrip. |
| 59 const int kTabstripLeftSpacing = 4; |
| 60 // Space between right edge of tabstrip and maximize button. |
| 61 const int kTabstripRightSpacing = 10; |
| 62 // Space between top of window and top of tabstrip for restored windows. |
| 63 const int kTabstripTopSpacingRestored = 10; |
| 64 // Space between top of window and top of tabstrip for maximized windows. |
| 65 const int kTabstripTopSpacingMaximized = 1; |
| 38 | 66 |
| 39 // The color used to fill the frame. Opacity is handled in the layer. | 67 // Tiles an image into an area, rounding the top corners. |
| 40 const SkColor kFrameColor = SK_ColorBLACK; | 68 void TileRoundRect(gfx::Canvas* canvas, |
| 41 // Radius of rounded rectangle corners. | 69 int x, int y, int w, int h, |
| 42 const int kRoundedRectRadius = 3; | 70 const SkBitmap& bitmap, |
| 43 // Frame border fades in over this range of opacity. | 71 int corner_radius) { |
| 44 const double kFrameBorderStartOpacity = 0.2; | 72 SkRect rect; |
| 45 const double kFrameBorderEndOpacity = 0.3; | 73 rect.iset(x, y, x + w, y + h); |
| 46 // How long the hover animation takes if uninterrupted. | 74 const SkScalar kRadius = SkIntToScalar(corner_radius); |
| 47 const int kHoverFadeDurationMs = 250; | 75 SkScalar radii[8] = { |
| 76 kRadius, kRadius, // top-left |
| 77 kRadius, kRadius, // top-right |
| 78 0, 0, // bottom-right |
| 79 0, 0}; // bottom-left |
| 80 SkPath path; |
| 81 path.addRoundRect(rect, radii, SkPath::kCW_Direction); |
| 48 | 82 |
| 49 // Color shown when window control is hovered. | 83 SkPaint paint; |
| 50 const SkColor kMaximizeButtonBackgroundColor = SkColorSetRGB(0, 255, 0); | 84 SkShader* shader = SkShader::CreateBitmapShader(bitmap, |
| 51 const SkColor kCloseButtonBackgroundColor = SkColorSetRGB(255, 0, 0); | 85 SkShader::kRepeat_TileMode, |
| 52 | 86 SkShader::kRepeat_TileMode); |
| 53 bool HitVisibleView(views::View* view, gfx::Point point) { | 87 paint.setShader(shader); |
| 54 return view->visible() && view->GetMirroredBounds().Contains(point); | 88 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); |
| 89 // CreateBitmapShader returns a Shader with a reference count of one, we |
| 90 // need to unref after paint takes ownership of the shader. |
| 91 shader->unref(); |
| 92 canvas->GetSkCanvas()->drawPath(path, paint); |
| 55 } | 93 } |
| 56 | 94 |
| 57 } // namespace | 95 } // namespace |
| 58 | 96 |
| 59 // Buttons for window controls - close, zoom, etc. | |
| 60 // Note that views::CustomButton is already a ui::AnimationDelegate. | |
| 61 class WindowControlButton : public views::CustomButton { | |
| 62 public: | |
| 63 WindowControlButton(BrowserNonClientFrameViewAura* owner, | |
| 64 SkColor color, | |
| 65 const SkBitmap& icon) | |
| 66 : views::CustomButton(owner), | |
| 67 owner_(owner), | |
| 68 color_(color), | |
| 69 icon_(icon), | |
| 70 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 71 show_animation_(new ui::SlideAnimation(this))) { | |
| 72 show_animation_->SetSlideDuration(kHoverFadeDurationMs); | |
| 73 SetPaintToLayer(true); | |
| 74 layer()->SetFillsBoundsOpaquely(false); | |
| 75 layer()->SetOpacity(0.f); | |
| 76 } | |
| 77 virtual ~WindowControlButton() {} | |
| 78 | |
| 79 void Show() { | |
| 80 show_animation_->Show(); | |
| 81 } | |
| 82 void Hide() { | |
| 83 show_animation_->Hide(); | |
| 84 } | |
| 85 | |
| 86 // Overridden from views::View: | |
| 87 virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE { | |
| 88 // Ensure the caption/frame background shows when we hover this button. | |
| 89 owner_->ShowFrameBackground(); | |
| 90 views::CustomButton::OnMouseEntered(event); | |
| 91 } | |
| 92 virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE { | |
| 93 owner_->HideFrameBackground(); | |
| 94 views::CustomButton::OnMouseExited(event); | |
| 95 } | |
| 96 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { | |
| 97 canvas->FillRect(GetLocalBounds(), GetBackgroundColor()); | |
| 98 canvas->DrawBitmapInt(icon_, 0, 0); | |
| 99 } | |
| 100 virtual gfx::Size GetPreferredSize() OVERRIDE { | |
| 101 return gfx::Size(icon_.width(), icon_.height()); | |
| 102 } | |
| 103 | |
| 104 // Overridden from ui::AnimationDelegate: | |
| 105 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE { | |
| 106 if (animation == show_animation_.get()) { | |
| 107 double opacity = show_animation_->GetCurrentValue(); | |
| 108 layer()->SetOpacity(static_cast<float>(opacity)); | |
| 109 return; | |
| 110 } | |
| 111 views::CustomButton::AnimationProgressed(animation); | |
| 112 } | |
| 113 | |
| 114 private: | |
| 115 SkColor GetBackgroundColor() { | |
| 116 // Background animates in separately, so handle opacity manually. | |
| 117 return SkColorSetARGB(hover_animation_->CurrentValueBetween(0, 150), | |
| 118 SkColorGetR(color_), | |
| 119 SkColorGetG(color_), | |
| 120 SkColorGetB(color_)); | |
| 121 } | |
| 122 | |
| 123 BrowserNonClientFrameViewAura* owner_; | |
| 124 SkColor color_; | |
| 125 SkBitmap icon_; | |
| 126 scoped_ptr<ui::SlideAnimation> show_animation_; | |
| 127 | |
| 128 DISALLOW_COPY_AND_ASSIGN(WindowControlButton); | |
| 129 }; | |
| 130 | |
| 131 // Layer that visually sits "behind" the window contents and expands out to | |
| 132 // provide visual resize handles on the sides. Hit testing and resize handling | |
| 133 // is in the parent NonClientFrameView. | |
| 134 class FrameBackgroundView : public views::View, | |
| 135 public ui::AnimationDelegate { | |
| 136 public: | |
| 137 FrameBackgroundView() | |
| 138 : ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 139 size_animation_(new ui::SlideAnimation(this))), | |
| 140 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 141 color_animation_(new ui::SlideAnimation(this))) { | |
| 142 size_animation_->SetSlideDuration(kHoverFadeDurationMs); | |
| 143 color_animation_->SetSlideDuration(kHoverFadeDurationMs); | |
| 144 SetPaintToLayer(true); | |
| 145 UpdateOpacity(); | |
| 146 } | |
| 147 virtual ~FrameBackgroundView() { | |
| 148 } | |
| 149 | |
| 150 void Configure(const gfx::Rect& start_bounds, const gfx::Rect& end_bounds) { | |
| 151 start_bounds_ = start_bounds; | |
| 152 end_bounds_ = end_bounds; | |
| 153 UpdateBounds(); | |
| 154 } | |
| 155 void SetEndBounds(const gfx::Rect& end_bounds) { | |
| 156 end_bounds_ = end_bounds; | |
| 157 UpdateBounds(); | |
| 158 } | |
| 159 void Show() { | |
| 160 size_animation_->Show(); | |
| 161 color_animation_->Show(); | |
| 162 } | |
| 163 void Hide() { | |
| 164 size_animation_->Hide(); | |
| 165 color_animation_->Hide(); | |
| 166 } | |
| 167 | |
| 168 protected: | |
| 169 // Overridden from views::View: | |
| 170 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { | |
| 171 SkRect rect = { SkIntToScalar(0), SkIntToScalar(0), | |
| 172 SkIntToScalar(width()), SkIntToScalar(height()) }; | |
| 173 SkScalar radius = SkIntToScalar(kRoundedRectRadius); | |
| 174 SkPaint paint; | |
| 175 // Animation handles setting the opacity for the whole layer. | |
| 176 paint.setColor(kFrameColor); | |
| 177 paint.setStyle(SkPaint::kFill_Style); | |
| 178 canvas->GetSkCanvas()->drawRoundRect(rect, radius, radius, paint); | |
| 179 } | |
| 180 | |
| 181 // Overridden from ui::AnimationDelegate: | |
| 182 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE { | |
| 183 if (animation == color_animation_.get()) { | |
| 184 UpdateOpacity(); | |
| 185 } else if (animation == size_animation_.get()) { | |
| 186 UpdateBounds(); | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 private: | |
| 191 void UpdateOpacity() { | |
| 192 double opacity = color_animation_->CurrentValueBetween( | |
| 193 kFrameBorderStartOpacity, kFrameBorderEndOpacity); | |
| 194 layer()->SetOpacity(static_cast<float>(opacity)); | |
| 195 } | |
| 196 | |
| 197 void UpdateBounds() { | |
| 198 gfx::Rect current_bounds = | |
| 199 size_animation_->CurrentValueBetween(start_bounds_, end_bounds_); | |
| 200 SetBoundsRect(current_bounds); | |
| 201 SchedulePaint(); | |
| 202 } | |
| 203 | |
| 204 scoped_ptr<ui::SlideAnimation> size_animation_; | |
| 205 scoped_ptr<ui::SlideAnimation> color_animation_; | |
| 206 // Default "hidden" rectangle. | |
| 207 gfx::Rect default_bounds_; | |
| 208 // When moving mouse from one target to another (e.g. from edge to corner) | |
| 209 // the size animation start point may not be the default size. | |
| 210 gfx::Rect start_bounds_; | |
| 211 // Expanded bounds, with edges visible from behind the client area. | |
| 212 gfx::Rect end_bounds_; | |
| 213 | |
| 214 DISALLOW_COPY_AND_ASSIGN(FrameBackgroundView); | |
| 215 }; | |
| 216 | |
| 217 /////////////////////////////////////////////////////////////////////////////// | 97 /////////////////////////////////////////////////////////////////////////////// |
| 218 // BrowserNonClientFrameViewAura, public: | 98 // BrowserNonClientFrameViewAura, public: |
| 219 | 99 |
| 220 BrowserNonClientFrameViewAura::BrowserNonClientFrameViewAura( | 100 BrowserNonClientFrameViewAura::BrowserNonClientFrameViewAura( |
| 221 BrowserFrame* frame, BrowserView* browser_view) | 101 BrowserFrame* frame, BrowserView* browser_view) |
| 222 : BrowserNonClientFrameView(frame, browser_view), | 102 : BrowserNonClientFrameView(frame, browser_view), |
| 223 last_hittest_code_(HTNOWHERE) { | 103 maximize_button_(NULL), |
| 224 frame_background_ = new FrameBackgroundView(); | 104 close_button_(NULL), |
| 225 AddChildView(frame_background_); | 105 window_icon_(NULL), |
| 106 button_separator_(NULL), |
| 107 top_left_corner_(NULL), |
| 108 top_edge_(NULL), |
| 109 top_right_corner_(NULL), |
| 110 header_left_edge_(NULL), |
| 111 header_right_edge_(NULL) { |
| 112 } |
| 226 | 113 |
| 227 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 114 BrowserNonClientFrameViewAura::~BrowserNonClientFrameViewAura() { |
| 228 maximize_button_ = | 115 } |
| 229 new WindowControlButton(this, | 116 |
| 230 kMaximizeButtonBackgroundColor, | 117 void BrowserNonClientFrameViewAura::Init() { |
| 231 *rb.GetBitmapNamed(IDR_AURA_WINDOW_ZOOM_ICON)); | 118 // Ensure we get resize cursors for a few pixels outside our bounds. |
| 119 frame()->GetNativeWindow()->set_hit_test_bounds_inset( |
| 120 -kResizeAreaOutsideBounds); |
| 121 |
| 122 // Caption buttons. |
| 123 maximize_button_ = new views::ImageButton(this); |
| 124 SetButtonImages(maximize_button_, |
| 125 IDR_AURA_WINDOW_MAXIMIZE, |
| 126 IDR_AURA_WINDOW_MAXIMIZE_H, |
| 127 IDR_AURA_WINDOW_MAXIMIZE_P); |
| 232 maximize_button_->SetAccessibleName( | 128 maximize_button_->SetAccessibleName( |
| 233 l10n_util::GetStringUTF16(IDS_ACCNAME_MAXIMIZE)); | 129 l10n_util::GetStringUTF16(IDS_ACCNAME_MAXIMIZE)); |
| 234 AddChildView(maximize_button_); | 130 AddChildView(maximize_button_); |
| 235 | 131 close_button_ = new views::ImageButton(this); |
| 236 close_button_ = | 132 SetButtonImages(close_button_, |
| 237 new WindowControlButton(this, | 133 IDR_AURA_WINDOW_CLOSE, |
| 238 kCloseButtonBackgroundColor, | 134 IDR_AURA_WINDOW_CLOSE_H, |
| 239 *rb.GetBitmapNamed(IDR_AURA_WINDOW_CLOSE_ICON)); | 135 IDR_AURA_WINDOW_CLOSE_P); |
| 240 close_button_->SetAccessibleName( | 136 close_button_->SetAccessibleName( |
| 241 l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE)); | 137 l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE)); |
| 242 AddChildView(close_button_); | 138 AddChildView(close_button_); |
| 243 | 139 |
| 244 // The BrowserFrame will become our owning window/widget. | 140 // Window frame image parts. |
| 245 frame->AsWidget()->AddObserver(this); | 141 ResourceBundle& bundle = ResourceBundle::GetSharedInstance(); |
| 246 // Associate our WindowFrame interface with our owning window/widget so | 142 button_separator_ = |
| 247 // we get callbacks from aura_shell. | 143 bundle.GetBitmapNamed(IDR_AURA_WINDOW_BUTTON_SEPARATOR); |
| 248 frame->AsWidget()->GetNativeWindow()->SetProperty( | 144 top_left_corner_ = |
| 249 ash::kWindowFrameKey, | 145 bundle.GetBitmapNamed(IDR_AURA_WINDOW_HEADER_SHADE_TOP_LEFT); |
| 250 static_cast<ash::WindowFrame*>(this)); | 146 top_edge_ = |
| 251 } | 147 bundle.GetBitmapNamed(IDR_AURA_WINDOW_HEADER_SHADE_TOP); |
| 148 top_right_corner_ = |
| 149 bundle.GetBitmapNamed(IDR_AURA_WINDOW_HEADER_SHADE_TOP_RIGHT); |
| 150 header_left_edge_ = |
| 151 bundle.GetBitmapNamed(IDR_AURA_WINDOW_HEADER_SHADE_LEFT); |
| 152 header_right_edge_ = |
| 153 bundle.GetBitmapNamed(IDR_AURA_WINDOW_HEADER_SHADE_RIGHT); |
| 154 // TODO(jamescook): Should we paint the header bottom edge here, or keep |
| 155 // it in BrowserFrameAura::ToolbarBackground as we do now? |
| 252 | 156 |
| 253 BrowserNonClientFrameViewAura::~BrowserNonClientFrameViewAura() { | 157 // Initializing the TabIconView is expensive, so only do it if we need to. |
| 254 // Don't need to remove the Widget observer, the window is deleted before us. | 158 if (browser_view()->ShouldShowWindowIcon()) { |
| 255 } | 159 window_icon_ = new TabIconView(this); |
| 256 | 160 window_icon_->set_is_light(true); |
| 257 void BrowserNonClientFrameViewAura::ShowFrameBackground() { | 161 AddChildView(window_icon_); |
| 258 UpdateFrameBackground(ShouldPaintAsActive()); | 162 window_icon_->Update(); |
| 259 frame_background_->Show(); | 163 } |
| 260 } | |
| 261 | |
| 262 void BrowserNonClientFrameViewAura::HideFrameBackground() { | |
| 263 frame_background_->Hide(); | |
| 264 } | 164 } |
| 265 | 165 |
| 266 /////////////////////////////////////////////////////////////////////////////// | 166 /////////////////////////////////////////////////////////////////////////////// |
| 267 // BrowserNonClientFrameViewAura, private: | |
| 268 | |
| 269 int BrowserNonClientFrameViewAura::NonClientHitTestImpl( | |
| 270 const gfx::Point& point) { | |
| 271 if (!GetLocalBounds().Contains(point)) | |
| 272 return HTNOWHERE; | |
| 273 | |
| 274 // Window controls get first try because they overlap the client area. | |
| 275 if (HitVisibleView(maximize_button_, point)) | |
| 276 return HTMAXBUTTON; | |
| 277 if (HitVisibleView(close_button_, point)) | |
| 278 return HTCLOSE; | |
| 279 | |
| 280 int frame_component = GetWidget()->client_view()->NonClientHitTest(point); | |
| 281 if (frame_component != HTNOWHERE) | |
| 282 return frame_component; | |
| 283 | |
| 284 // Test window resize components. | |
| 285 bool can_resize = GetWidget()->widget_delegate()->CanResize(); | |
| 286 // TODO(derat): Disallow resizing via the top border in the Aura shell | |
| 287 // instead of enforcing it here. See http://crbug.com/101830. | |
| 288 frame_component = GetHTComponentForFrame(point, | |
| 289 0, | |
| 290 kResizeBorderThickness, | |
| 291 kResizeBorderThickness, | |
| 292 kResizeBorderThickness, | |
| 293 can_resize); | |
| 294 if (frame_component != HTNOWHERE) | |
| 295 return frame_component; | |
| 296 // Use HTCAPTION as a final fallback. | |
| 297 return HTCAPTION; | |
| 298 } | |
| 299 | |
| 300 // Pass |active_window| explicitly because deactivating a window causes | |
| 301 // OnWidgetActivationChanged() to be called before GetWidget()->IsActive() | |
| 302 // changes state. | |
| 303 gfx::Rect BrowserNonClientFrameViewAura::GetFrameBackgroundBounds( | |
| 304 int hittest_code, | |
| 305 bool active_window) { | |
| 306 bool show_left = false; | |
| 307 bool show_top = false; | |
| 308 bool show_right = false; | |
| 309 bool show_bottom = false; | |
| 310 switch (hittest_code) { | |
| 311 case HTBOTTOM: | |
| 312 show_bottom = true; | |
| 313 break; | |
| 314 case HTBOTTOMLEFT: | |
| 315 show_bottom = true; | |
| 316 show_left = true; | |
| 317 break; | |
| 318 case HTBOTTOMRIGHT: | |
| 319 show_bottom = true; | |
| 320 show_right = true; | |
| 321 break; | |
| 322 case HTCAPTION: | |
| 323 show_top = true; | |
| 324 break; | |
| 325 case HTCLOSE: | |
| 326 show_top = true; | |
| 327 break; | |
| 328 case HTLEFT: | |
| 329 show_left = true; | |
| 330 break; | |
| 331 case HTMAXBUTTON: | |
| 332 show_top = true; | |
| 333 break; | |
| 334 case HTRIGHT: | |
| 335 show_right = true; | |
| 336 break; | |
| 337 case HTTOP: | |
| 338 show_top = true; | |
| 339 break; | |
| 340 case HTTOPLEFT: | |
| 341 show_top = true; | |
| 342 show_left = true; | |
| 343 break; | |
| 344 case HTTOPRIGHT: | |
| 345 show_top = true; | |
| 346 show_right = true; | |
| 347 break; | |
| 348 default: | |
| 349 break; | |
| 350 } | |
| 351 // Always show top edge for the active window so that you can tell which | |
| 352 // window has focus. | |
| 353 if (active_window) | |
| 354 show_top = true; | |
| 355 gfx::Rect target = bounds(); | |
| 356 // Inset the sides that are not showing. | |
| 357 target.Inset( | |
| 358 (show_left ? 0 : kResizeBorderThickness - kPersistentBorderThickness), | |
| 359 (show_top ? 0 : kTopBorderThickness + kFrameBackgroundTopOffset), | |
| 360 (show_right ? 0 : kResizeBorderThickness - kPersistentBorderThickness), | |
| 361 (show_bottom ? 0 : kResizeBorderThickness - kPersistentBorderThickness)); | |
| 362 return target; | |
| 363 } | |
| 364 | |
| 365 void BrowserNonClientFrameViewAura::UpdateFrameBackground(bool active_window) { | |
| 366 gfx::Rect start_bounds = GetFrameBackgroundBounds(HTNOWHERE, active_window); | |
| 367 gfx::Rect end_bounds = | |
| 368 GetFrameBackgroundBounds(last_hittest_code_, active_window); | |
| 369 frame_background_->Configure(start_bounds, end_bounds); | |
| 370 } | |
| 371 | |
| 372 void BrowserNonClientFrameViewAura::ActiveStateChanged() { | |
| 373 bool active = ShouldPaintAsActive(); | |
| 374 // Active windows have different background bounds. | |
| 375 UpdateFrameBackground(active); | |
| 376 if (active) | |
| 377 frame_background_->Show(); | |
| 378 else | |
| 379 frame_background_->Hide(); | |
| 380 } | |
| 381 | |
| 382 /////////////////////////////////////////////////////////////////////////////// | |
| 383 // BrowserNonClientFrameView overrides: | 167 // BrowserNonClientFrameView overrides: |
| 384 | 168 |
| 385 gfx::Rect BrowserNonClientFrameViewAura::GetBoundsForTabStrip( | 169 gfx::Rect BrowserNonClientFrameViewAura::GetBoundsForTabStrip( |
| 386 views::View* tabstrip) const { | 170 views::View* tabstrip) const { |
| 387 if (!tabstrip) | 171 if (!tabstrip) |
| 388 return gfx::Rect(); | 172 return gfx::Rect(); |
| 389 // TODO(jamescook): Avatar icon support. | 173 bool restored = !frame()->IsMaximized(); |
| 390 // Reserve space on the right for close/maximize buttons. | 174 return gfx::Rect(kTabstripLeftSpacing, |
| 391 int tabstrip_x = kResizeBorderThickness; | 175 GetHorizontalTabStripVerticalOffset(restored), |
| 392 int tabstrip_width = maximize_button_->x() - tabstrip_x; | 176 maximize_button_->x() - kTabstripRightSpacing, |
| 393 return gfx::Rect(tabstrip_x, | |
| 394 GetHorizontalTabStripVerticalOffset(false), | |
| 395 tabstrip_width, | |
| 396 tabstrip->GetPreferredSize().height()); | 177 tabstrip->GetPreferredSize().height()); |
| 397 | |
| 398 } | 178 } |
| 399 | 179 |
| 400 int BrowserNonClientFrameViewAura::GetHorizontalTabStripVerticalOffset( | 180 int BrowserNonClientFrameViewAura::GetHorizontalTabStripVerticalOffset( |
| 401 bool restored) const { | 181 bool restored) const { |
| 402 return kTopBorderThickness; | 182 return NonClientTopBorderHeight(restored); |
| 403 } | 183 } |
| 404 | 184 |
| 405 void BrowserNonClientFrameViewAura::UpdateThrobber(bool running) { | 185 void BrowserNonClientFrameViewAura::UpdateThrobber(bool running) { |
| 406 // TODO(jamescook): Do we need this? | 186 if (window_icon_) |
| 187 window_icon_->Update(); |
| 407 } | 188 } |
| 408 | 189 |
| 409 /////////////////////////////////////////////////////////////////////////////// | 190 /////////////////////////////////////////////////////////////////////////////// |
| 410 // views::NonClientFrameView overrides: | 191 // views::NonClientFrameView overrides: |
| 411 | 192 |
| 412 gfx::Rect BrowserNonClientFrameViewAura::GetBoundsForClientView() const { | 193 gfx::Rect BrowserNonClientFrameViewAura::GetBoundsForClientView() const { |
| 413 gfx::Rect bounds = GetLocalBounds(); | 194 int top_height = NonClientTopBorderHeight(false); |
| 414 bounds.Inset(kResizeBorderThickness, | 195 return gfx::Rect(kBorderThickness, |
| 415 kTopBorderThickness, | 196 top_height, |
| 416 kResizeBorderThickness, | 197 std::max(0, width() - (2 * kBorderThickness)), |
| 417 kResizeBorderThickness); | 198 std::max(0, height() - top_height - kBorderThickness)); |
| 418 return bounds; | |
| 419 } | 199 } |
| 420 | 200 |
| 421 gfx::Rect BrowserNonClientFrameViewAura::GetWindowBoundsForClientBounds( | 201 gfx::Rect BrowserNonClientFrameViewAura::GetWindowBoundsForClientBounds( |
| 422 const gfx::Rect& client_bounds) const { | 202 const gfx::Rect& client_bounds) const { |
| 423 gfx::Rect bounds = client_bounds; | 203 int top_height = NonClientTopBorderHeight(false); |
| 424 bounds.Inset(-kResizeBorderThickness, | 204 return gfx::Rect(std::max(0, client_bounds.x() - kBorderThickness), |
| 425 -kTopBorderThickness, | 205 std::max(0, client_bounds.y() - top_height), |
| 426 -kResizeBorderThickness, | 206 client_bounds.width() + (2 * kBorderThickness), |
| 427 -kResizeBorderThickness); | 207 client_bounds.height() + top_height + kBorderThickness); |
| 428 return bounds; | |
| 429 } | 208 } |
| 430 | 209 |
| 431 int BrowserNonClientFrameViewAura::NonClientHitTest(const gfx::Point& point) { | 210 int BrowserNonClientFrameViewAura::NonClientHitTest(const gfx::Point& point) { |
| 432 last_hittest_code_ = NonClientHitTestImpl(point); | 211 gfx::Rect expanded_bounds = bounds(); |
| 433 return last_hittest_code_; | 212 expanded_bounds.Inset(-kResizeAreaOutsideBounds, -kResizeAreaOutsideBounds); |
| 213 if (!expanded_bounds.Contains(point)) |
| 214 return HTNOWHERE; |
| 215 |
| 216 // No avatar button for Chrome OS. |
| 217 |
| 218 // Check the client view first, as it overlaps the window caption area. |
| 219 int client_component = frame()->client_view()->NonClientHitTest(point); |
| 220 if (client_component != HTNOWHERE) |
| 221 return client_component; |
| 222 |
| 223 // Then see if the point is within any of the window controls. |
| 224 if (close_button_->visible() && |
| 225 close_button_->GetMirroredBounds().Contains(point)) |
| 226 return HTCLOSE; |
| 227 if (maximize_button_->visible() && |
| 228 maximize_button_->GetMirroredBounds().Contains(point)) |
| 229 return HTMAXBUTTON; |
| 230 |
| 231 bool can_resize = frame()->widget_delegate() ? |
| 232 frame()->widget_delegate()->CanResize() : |
| 233 false; |
| 234 int frame_component = GetHTComponentForFrame(point, |
| 235 kTopThickness, |
| 236 kBorderThickness, |
| 237 kResizeAreaCornerSize, |
| 238 kResizeAreaCornerSize, |
| 239 can_resize); |
| 240 if (frame_component != HTNOWHERE) |
| 241 return frame_component; |
| 242 |
| 243 // Caption is a safe default. |
| 244 return HTCAPTION; |
| 434 } | 245 } |
| 435 | 246 |
| 436 void BrowserNonClientFrameViewAura::GetWindowMask(const gfx::Size& size, | 247 void BrowserNonClientFrameViewAura::GetWindowMask(const gfx::Size& size, |
| 437 gfx::Path* window_mask) { | 248 gfx::Path* window_mask) { |
| 438 // Nothing. | 249 // Aura does not use window masks. |
| 439 } | 250 } |
| 440 | 251 |
| 441 void BrowserNonClientFrameViewAura::ResetWindowControls() { | 252 void BrowserNonClientFrameViewAura::ResetWindowControls() { |
| 442 maximize_button_->SetState(views::CustomButton::BS_NORMAL); | 253 maximize_button_->SetState(views::CustomButton::BS_NORMAL); |
| 443 // The close button isn't affected by this constraint. | 254 // The close button isn't affected by this constraint. |
| 444 } | 255 } |
| 445 | 256 |
| 446 void BrowserNonClientFrameViewAura::UpdateWindowIcon() { | 257 void BrowserNonClientFrameViewAura::UpdateWindowIcon() { |
| 447 // TODO(jamescook): We will need this for app frames. | 258 if (window_icon_) |
| 448 } | 259 window_icon_->SchedulePaint(); |
| 449 | |
| 450 void BrowserNonClientFrameViewAura::ShouldPaintAsActiveChanged() { | |
| 451 ActiveStateChanged(); | |
| 452 } | 260 } |
| 453 | 261 |
| 454 /////////////////////////////////////////////////////////////////////////////// | 262 /////////////////////////////////////////////////////////////////////////////// |
| 455 // views::View overrides: | 263 // views::View overrides: |
| 456 | 264 |
| 457 void BrowserNonClientFrameViewAura::Layout() { | 265 void BrowserNonClientFrameViewAura::OnPaint(gfx::Canvas* canvas) { |
| 458 // Layout window buttons from right to left. | 266 if (frame()->IsFullscreen()) |
| 459 int right = width() - kResizeBorderThickness; | 267 return; // Nothing visible, don't paint. |
| 460 gfx::Size preferred = close_button_->GetPreferredSize(); | 268 PaintHeader(canvas); |
| 461 close_button_->SetBounds(right - preferred.width(), kTopBorderThickness, | 269 PaintTitleBar(canvas); |
| 462 preferred.width(), preferred.height()); | 270 // Paint the view hierarchy, which draws the caption buttons. |
| 463 right -= preferred.width(); // No padding. | 271 BrowserNonClientFrameView::OnPaint(canvas); |
| 464 preferred = maximize_button_->GetPreferredSize(); | |
| 465 maximize_button_->SetBounds(right - preferred.width(), kTopBorderThickness, | |
| 466 preferred.width(), preferred.height()); | |
| 467 UpdateFrameBackground(ShouldPaintAsActive()); | |
| 468 } | 272 } |
| 469 | 273 |
| 470 views::View* BrowserNonClientFrameViewAura::GetEventHandlerForPoint( | 274 void BrowserNonClientFrameViewAura::Layout() { |
| 471 const gfx::Point& point) { | 275 // Maximized windows and app/popup windows use shorter buttons. |
| 472 // Mouse hovers near the resizing edges result in the animation starting and | 276 if (frame()->IsMaximized() || |
| 473 // stopping as the frame background changes size. Just ignore events | 277 !browser_view()->IsBrowserTypeNormal()) { |
| 474 // destined for the frame background and handle them at this level. | 278 SetButtonImages(close_button_, |
| 475 views::View* view = View::GetEventHandlerForPoint(point); | 279 IDR_AURA_WINDOW_MAXIMIZED_CLOSE, |
| 476 if (view == frame_background_) | 280 IDR_AURA_WINDOW_MAXIMIZED_CLOSE_H, |
| 477 return this; | 281 IDR_AURA_WINDOW_MAXIMIZED_CLOSE_P); |
| 478 return view; | 282 SetButtonImages(maximize_button_, |
| 283 IDR_AURA_WINDOW_MAXIMIZED_RESTORE, |
| 284 IDR_AURA_WINDOW_MAXIMIZED_RESTORE_H, |
| 285 IDR_AURA_WINDOW_MAXIMIZED_RESTORE_P); |
| 286 } else { |
| 287 SetButtonImages(close_button_, |
| 288 IDR_AURA_WINDOW_CLOSE, |
| 289 IDR_AURA_WINDOW_CLOSE_H, |
| 290 IDR_AURA_WINDOW_CLOSE_P); |
| 291 SetButtonImages(maximize_button_, |
| 292 IDR_AURA_WINDOW_MAXIMIZE, |
| 293 IDR_AURA_WINDOW_MAXIMIZE_H, |
| 294 IDR_AURA_WINDOW_MAXIMIZE_P); |
| 295 } |
| 296 |
| 297 gfx::Size close_size = close_button_->GetPreferredSize(); |
| 298 close_button_->SetBounds( |
| 299 width() - close_size.width() - kCloseButtonOffsetX, |
| 300 kCloseButtonOffsetY, |
| 301 close_size.width(), |
| 302 close_size.height()); |
| 303 |
| 304 gfx::Size maximize_size = maximize_button_->GetPreferredSize(); |
| 305 maximize_button_->SetBounds( |
| 306 close_button_->x() - button_separator_->width() - maximize_size.width(), |
| 307 close_button_->y(), |
| 308 maximize_size.width(), |
| 309 maximize_size.height()); |
| 310 |
| 311 if (window_icon_) |
| 312 window_icon_->SetBoundsRect( |
| 313 gfx::Rect(kIconOffsetX, kIconOffsetY, kIconSize, kIconSize)); |
| 314 |
| 315 BrowserNonClientFrameView::Layout(); |
| 479 } | 316 } |
| 480 | 317 |
| 481 bool BrowserNonClientFrameViewAura::HitTest(const gfx::Point& p) const { | 318 bool BrowserNonClientFrameViewAura::HitTest(const gfx::Point& l) const { |
| 482 // Claim all events outside the client area. | 319 // If the point is outside the bounds of the client area, claim it. |
| 483 bool in_client = GetWidget()->client_view()->bounds().Contains(p); | 320 if (NonClientFrameView::HitTest(l)) |
| 484 if (!in_client) | |
| 485 return true; | 321 return true; |
| 486 // Window controls overlap the client area, so explicitly check for points | 322 |
| 487 // inside of them. | |
| 488 if (close_button_->bounds().Contains(p) || | |
| 489 maximize_button_->bounds().Contains(p)) | |
| 490 return true; | |
| 491 // Otherwise claim it only if it's in a non-tab portion of the tabstrip. | 323 // Otherwise claim it only if it's in a non-tab portion of the tabstrip. |
| 492 if (!browser_view()->tabstrip()) | 324 if (!browser_view()->tabstrip()) |
| 493 return false; | 325 return false; |
| 494 gfx::Rect tabstrip_bounds(browser_view()->tabstrip()->bounds()); | 326 gfx::Rect tabstrip_bounds(browser_view()->tabstrip()->bounds()); |
| 495 gfx::Point tabstrip_origin(tabstrip_bounds.origin()); | 327 gfx::Point tabstrip_origin(tabstrip_bounds.origin()); |
| 496 View::ConvertPointToView( | 328 View::ConvertPointToView(frame()->client_view(), this, &tabstrip_origin); |
| 497 frame()->client_view(), this, &tabstrip_origin); | |
| 498 tabstrip_bounds.set_origin(tabstrip_origin); | 329 tabstrip_bounds.set_origin(tabstrip_origin); |
| 499 if (p.y() > tabstrip_bounds.bottom()) | 330 if (l.y() > tabstrip_bounds.bottom()) |
| 500 return false; | 331 return false; |
| 501 | 332 |
| 502 // We convert from our parent's coordinates since we assume we fill its bounds | 333 // We convert from our parent's coordinates since we assume we fill its bounds |
| 503 // completely. We need to do this since we're not a parent of the tabstrip, | 334 // completely. We need to do this since we're not a parent of the tabstrip, |
| 504 // meaning ConvertPointToView would otherwise return something bogus. | 335 // meaning ConvertPointToView would otherwise return something bogus. |
| 505 gfx::Point browser_view_point(p); | 336 gfx::Point browser_view_point(l); |
| 506 View::ConvertPointToView(parent(), browser_view(), &browser_view_point); | 337 View::ConvertPointToView(parent(), browser_view(), &browser_view_point); |
| 507 return browser_view()->IsPositionInWindowCaption(browser_view_point); | 338 return browser_view()->IsPositionInWindowCaption(browser_view_point); |
| 508 } | 339 } |
| 509 | 340 |
| 510 void BrowserNonClientFrameViewAura::OnMouseMoved( | 341 void BrowserNonClientFrameViewAura::GetAccessibleState( |
| 511 const views::MouseEvent& event) { | 342 ui::AccessibleViewState* state) { |
| 512 // We may be hovering over the resize edge. | 343 state->role = ui::AccessibilityTypes::ROLE_TITLEBAR; |
| 513 ShowFrameBackground(); | |
| 514 } | |
| 515 | |
| 516 void BrowserNonClientFrameViewAura::OnMouseExited( | |
| 517 const views::MouseEvent& event) { | |
| 518 // We hovered away from the resize edge. | |
| 519 HideFrameBackground(); | |
| 520 } | |
| 521 | |
| 522 gfx::NativeCursor BrowserNonClientFrameViewAura::GetCursor( | |
| 523 const views::MouseEvent& event) { | |
| 524 switch (last_hittest_code_) { | |
| 525 case HTBOTTOM: | |
| 526 return aura::kCursorSouthResize; | |
| 527 case HTBOTTOMLEFT: | |
| 528 return aura::kCursorSouthWestResize; | |
| 529 case HTBOTTOMRIGHT: | |
| 530 return aura::kCursorSouthEastResize; | |
| 531 case HTLEFT: | |
| 532 return aura::kCursorWestResize; | |
| 533 case HTRIGHT: | |
| 534 return aura::kCursorEastResize; | |
| 535 case HTTOP: | |
| 536 // Resizing from the top edge is not allowed. | |
| 537 return aura::kCursorNull; | |
| 538 case HTTOPLEFT: | |
| 539 return aura::kCursorWestResize; | |
| 540 case HTTOPRIGHT: | |
| 541 return aura::kCursorEastResize; | |
| 542 default: | |
| 543 return aura::kCursorNull; | |
| 544 } | |
| 545 } | 344 } |
| 546 | 345 |
| 547 /////////////////////////////////////////////////////////////////////////////// | 346 /////////////////////////////////////////////////////////////////////////////// |
| 548 // views::ButtonListener overrides: | 347 // views::ButtonListener overrides: |
| 549 | 348 |
| 550 void BrowserNonClientFrameViewAura::ButtonPressed(views::Button* sender, | 349 void BrowserNonClientFrameViewAura::ButtonPressed(views::Button* sender, |
| 551 const views::Event& event) { | 350 const views::Event& event) { |
| 552 if (sender == close_button_) { | 351 if (sender == maximize_button_) { |
| 553 frame()->Close(); | |
| 554 } else if (sender == maximize_button_) { | |
| 555 if (frame()->IsMaximized()) | 352 if (frame()->IsMaximized()) |
| 556 frame()->Restore(); | 353 frame()->Restore(); |
| 557 else | 354 else |
| 558 frame()->Maximize(); | 355 frame()->Maximize(); |
| 356 // The maximize button may have moved out from under the cursor. |
| 357 ResetWindowControls(); |
| 358 } else if (sender == close_button_) { |
| 359 frame()->Close(); |
| 559 } | 360 } |
| 560 } | 361 } |
| 561 | 362 |
| 562 /////////////////////////////////////////////////////////////////////////////// | 363 /////////////////////////////////////////////////////////////////////////////// |
| 563 // views::Widget::Observer overrides: | 364 // TabIconView::TabIconViewModel overrides: |
| 564 | 365 |
| 565 void BrowserNonClientFrameViewAura::OnWidgetActivationChanged( | 366 bool BrowserNonClientFrameViewAura::ShouldTabIconViewAnimate() const { |
| 566 views::Widget* widget, | 367 // This function is queried during the creation of the window as the |
| 567 bool active) { | 368 // TabIconView we host is initialized, so we need to NULL check the selected |
| 568 ActiveStateChanged(); | 369 // WebContents because in this condition there is not yet a selected tab. |
| 370 content::WebContents* current_tab = browser_view()->GetSelectedWebContents(); |
| 371 return current_tab ? current_tab->IsLoading() : false; |
| 372 } |
| 373 |
| 374 SkBitmap BrowserNonClientFrameViewAura::GetFaviconForTabIconView() { |
| 375 views::WidgetDelegate* delegate = frame()->widget_delegate(); |
| 376 if (!delegate) |
| 377 return SkBitmap(); |
| 378 return delegate->GetWindowIcon(); |
| 569 } | 379 } |
| 570 | 380 |
| 571 /////////////////////////////////////////////////////////////////////////////// | 381 /////////////////////////////////////////////////////////////////////////////// |
| 572 // ash::WindowFrame overrides: | 382 // BrowserNonClientFrameViewAura, private: |
| 573 | 383 |
| 574 void BrowserNonClientFrameViewAura::OnWindowHoverChanged(bool hovered) { | 384 void BrowserNonClientFrameViewAura::SetButtonImages(views::ImageButton* button, |
| 575 if (hovered) { | 385 int normal_bitmap_id, |
| 576 maximize_button_->Show(); | 386 int hot_bitmap_id, |
| 577 close_button_->Show(); | 387 int pushed_bitmap_id) { |
| 578 } else { | 388 ui::ThemeProvider* tp = frame()->GetThemeProvider(); |
| 579 maximize_button_->Hide(); | 389 button->SetImage(views::CustomButton::BS_NORMAL, |
| 580 close_button_->Hide(); | 390 tp->GetBitmapNamed(normal_bitmap_id)); |
| 391 button->SetImage(views::CustomButton::BS_HOT, |
| 392 tp->GetBitmapNamed(hot_bitmap_id)); |
| 393 button->SetImage(views::CustomButton::BS_PUSHED, |
| 394 tp->GetBitmapNamed(pushed_bitmap_id)); |
| 395 } |
| 396 |
| 397 int BrowserNonClientFrameViewAura::NonClientTopBorderHeight( |
| 398 bool restored) const { |
| 399 if (frame()->widget_delegate() && |
| 400 frame()->widget_delegate()->ShouldShowWindowTitle()) { |
| 401 // For popups ensure we have enough space to see the full window buttons. |
| 402 return kCloseButtonOffsetY + close_button_->height(); |
| 403 } |
| 404 if (restored) |
| 405 return kTabstripTopSpacingRestored; |
| 406 return kTabstripTopSpacingMaximized; |
| 407 } |
| 408 |
| 409 void BrowserNonClientFrameViewAura::PaintHeader(gfx::Canvas* canvas) { |
| 410 // The primary header image changes based on window activation state and |
| 411 // theme, so we look it up for each paint. |
| 412 SkBitmap* theme_frame = GetThemeFrameBitmap(); |
| 413 SkBitmap* theme_frame_overlay = GetThemeFrameOverlayBitmap(); |
| 414 |
| 415 // Draw the header background, clipping the corners to be rounded. |
| 416 const int kCornerRadius = 2; |
| 417 TileRoundRect(canvas, |
| 418 0, 0, width(), theme_frame->height(), |
| 419 *theme_frame, |
| 420 kCornerRadius); |
| 421 |
| 422 // Draw the theme frame overlay, if available. |
| 423 if (theme_frame_overlay) |
| 424 canvas->DrawBitmapInt(*theme_frame_overlay, 0, 0); |
| 425 |
| 426 // Separator between the maximize and close buttons. |
| 427 canvas->DrawBitmapInt(*button_separator_, |
| 428 close_button_->x() - button_separator_->width(), |
| 429 close_button_->y()); |
| 430 |
| 431 // Draw the top corners and edge. |
| 432 int top_left_height = top_left_corner_->height(); |
| 433 canvas->DrawBitmapInt(*top_left_corner_, |
| 434 0, 0, top_left_corner_->width(), top_left_height, |
| 435 0, 0, top_left_corner_->width(), top_left_height, |
| 436 false); |
| 437 canvas->TileImageInt(*top_edge_, |
| 438 top_left_corner_->width(), |
| 439 0, |
| 440 width() - top_left_corner_->width() - top_right_corner_->width(), |
| 441 top_edge_->height()); |
| 442 int top_right_height = top_right_corner_->height(); |
| 443 canvas->DrawBitmapInt(*top_right_corner_, |
| 444 0, 0, |
| 445 top_right_corner_->width(), top_right_height, |
| 446 width() - top_right_corner_->width(), 0, |
| 447 top_right_corner_->width(), top_right_height, |
| 448 false); |
| 449 |
| 450 // Header left edge. |
| 451 int header_left_height = theme_frame->height() - top_left_height; |
| 452 canvas->TileImageInt(*header_left_edge_, |
| 453 0, top_left_height, |
| 454 header_left_edge_->width(), header_left_height); |
| 455 |
| 456 // Header right edge. |
| 457 int header_right_height = theme_frame->height() - top_right_height; |
| 458 canvas->TileImageInt(*header_right_edge_, |
| 459 width() - header_right_edge_->width(), top_right_height, |
| 460 header_right_edge_->width(), header_right_height); |
| 461 |
| 462 // We don't draw edges around the content area. Web content goes flush |
| 463 // to the edge of the window. |
| 464 } |
| 465 |
| 466 void BrowserNonClientFrameViewAura::PaintTitleBar(gfx::Canvas* canvas) { |
| 467 // The window icon is painted by the TabIconView. |
| 468 views::WidgetDelegate* delegate = frame()->widget_delegate(); |
| 469 if (delegate && delegate->ShouldShowWindowTitle()) { |
| 470 int icon_right = window_icon_ ? window_icon_->bounds().right() : 0; |
| 471 gfx::Rect title_bounds( |
| 472 icon_right + kTitleOffsetX, |
| 473 kTitleOffsetY, |
| 474 std::max(0, maximize_button_->x() - kTitleLogoSpacing - icon_right), |
| 475 BrowserFrame::GetTitleFont().GetHeight()); |
| 476 canvas->DrawStringInt(delegate->GetWindowTitle(), |
| 477 BrowserFrame::GetTitleFont(), |
| 478 SK_ColorWHITE, |
| 479 GetMirroredXForRect(title_bounds), |
| 480 title_bounds.y(), |
| 481 title_bounds.width(), |
| 482 title_bounds.height()); |
| 581 } | 483 } |
| 582 } | 484 } |
| 485 |
| 486 SkBitmap* BrowserNonClientFrameViewAura::GetThemeFrameBitmap() const { |
| 487 bool is_incognito = browser_view()->IsOffTheRecord(); |
| 488 int resource_id; |
| 489 if (browser_view()->IsBrowserTypeNormal()) { |
| 490 if (ShouldPaintAsActive()) { |
| 491 // Use the standard resource ids to allow users to theme the frames. |
| 492 // TODO(jamescook): If this becomes the only frame we use on Aura, define |
| 493 // the resources to use the standard ids like IDR_THEME_FRAME, etc. |
| 494 if (is_incognito) { |
| 495 return GetCustomBitmap(IDR_THEME_FRAME_INCOGNITO, |
| 496 IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_ACTIVE); |
| 497 } |
| 498 return GetCustomBitmap(IDR_THEME_FRAME, |
| 499 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE); |
| 500 } |
| 501 if (is_incognito) { |
| 502 return GetCustomBitmap(IDR_THEME_FRAME_INCOGNITO_INACTIVE, |
| 503 IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_INACTIVE); |
| 504 } |
| 505 return GetCustomBitmap(IDR_THEME_FRAME_INACTIVE, |
| 506 IDR_AURA_WINDOW_HEADER_BASE_INACTIVE); |
| 507 } |
| 508 // Never theme app and popup windows. |
| 509 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 510 if (ShouldPaintAsActive()) { |
| 511 resource_id = is_incognito ? |
| 512 IDR_THEME_FRAME_INCOGNITO : IDR_FRAME; |
| 513 } else { |
| 514 resource_id = is_incognito ? |
| 515 IDR_THEME_FRAME_INCOGNITO_INACTIVE : IDR_THEME_FRAME_INACTIVE; |
| 516 } |
| 517 return rb.GetBitmapNamed(resource_id); |
| 518 } |
| 519 |
| 520 SkBitmap* BrowserNonClientFrameViewAura::GetThemeFrameOverlayBitmap() const { |
| 521 ui::ThemeProvider* tp = GetThemeProvider(); |
| 522 if (tp->HasCustomImage(IDR_THEME_FRAME_OVERLAY) && |
| 523 browser_view()->IsBrowserTypeNormal() && |
| 524 !browser_view()->IsOffTheRecord()) { |
| 525 return tp->GetBitmapNamed(ShouldPaintAsActive() ? |
| 526 IDR_THEME_FRAME_OVERLAY : IDR_THEME_FRAME_OVERLAY_INACTIVE); |
| 527 } |
| 528 return NULL; |
| 529 } |
| 530 |
| 531 SkBitmap* BrowserNonClientFrameViewAura::GetCustomBitmap( |
| 532 int bitmap_id, |
| 533 int fallback_bitmap_id) const { |
| 534 ui::ThemeProvider* tp = GetThemeProvider(); |
| 535 if (tp->HasCustomImage(bitmap_id)) |
| 536 return tp->GetBitmapNamed(bitmap_id); |
| 537 return tp->GetBitmapNamed(fallback_bitmap_id); |
| 538 } |
| OLD | NEW |