Chromium Code Reviews| 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/tabs/tab_strip.h" | 5 #include "chrome/browser/ui/views/tabs/tab_strip.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <iterator> | 8 #include <iterator> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
| 14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
| 16 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
| 17 #include "chrome/browser/defaults.h" | 17 #include "chrome/browser/defaults.h" |
| 18 #include "chrome/browser/ui/host_desktop.h" | 18 #include "chrome/browser/ui/host_desktop.h" |
| 19 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 19 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 20 #include "chrome/browser/ui/view_ids.h" | 20 #include "chrome/browser/ui/view_ids.h" |
| 21 #include "chrome/browser/ui/views/frame/browser_view.h" | |
| 21 #include "chrome/browser/ui/views/layout_constants.h" | 22 #include "chrome/browser/ui/views/layout_constants.h" |
| 22 #include "chrome/browser/ui/views/tabs/stacked_tab_strip_layout.h" | 23 #include "chrome/browser/ui/views/tabs/stacked_tab_strip_layout.h" |
| 23 #include "chrome/browser/ui/views/tabs/tab.h" | 24 #include "chrome/browser/ui/views/tabs/tab.h" |
| 24 #include "chrome/browser/ui/views/tabs/tab_drag_controller.h" | 25 #include "chrome/browser/ui/views/tabs/tab_drag_controller.h" |
| 25 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h" | 26 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h" |
| 26 #include "chrome/browser/ui/views/tabs/tab_strip_layout.h" | 27 #include "chrome/browser/ui/views/tabs/tab_strip_layout.h" |
| 27 #include "chrome/browser/ui/views/tabs/tab_strip_observer.h" | 28 #include "chrome/browser/ui/views/tabs/tab_strip_observer.h" |
| 28 #include "chrome/browser/ui/views/touch_uma/touch_uma.h" | 29 #include "chrome/browser/ui/views/touch_uma/touch_uma.h" |
| 29 #include "chrome/common/chrome_switches.h" | 30 #include "chrome/common/chrome_switches.h" |
| 30 #include "chrome/grit/generated_resources.h" | 31 #include "chrome/grit/generated_resources.h" |
| 31 #include "content/public/browser/user_metrics.h" | 32 #include "content/public/browser/user_metrics.h" |
| 32 #include "content/public/common/content_switches.h" | 33 #include "content/public/common/content_switches.h" |
| 33 #include "grit/theme_resources.h" | 34 #include "grit/theme_resources.h" |
| 35 #include "third_party/skia/include/core/SkColorFilter.h" | |
| 36 #include "third_party/skia/include/effects/SkBlurMaskFilter.h" | |
| 37 #include "third_party/skia/include/effects/SkLayerDrawLooper.h" | |
| 38 #include "third_party/skia/include/pathops/SkPathOps.h" | |
| 34 #include "ui/accessibility/ax_view_state.h" | 39 #include "ui/accessibility/ax_view_state.h" |
| 35 #include "ui/base/default_theme_provider.h" | 40 #include "ui/base/default_theme_provider.h" |
| 36 #include "ui/base/dragdrop/drag_drop_types.h" | 41 #include "ui/base/dragdrop/drag_drop_types.h" |
| 37 #include "ui/base/l10n/l10n_util.h" | 42 #include "ui/base/l10n/l10n_util.h" |
| 38 #include "ui/base/models/list_selection_model.h" | 43 #include "ui/base/models/list_selection_model.h" |
| 44 #include "ui/base/resource/material_design/material_design_controller.h" | |
| 39 #include "ui/base/resource/resource_bundle.h" | 45 #include "ui/base/resource/resource_bundle.h" |
| 40 #include "ui/compositor/compositing_recorder.h" | 46 #include "ui/compositor/compositing_recorder.h" |
| 41 #include "ui/compositor/paint_recorder.h" | 47 #include "ui/compositor/paint_recorder.h" |
| 42 #include "ui/gfx/animation/animation_container.h" | 48 #include "ui/gfx/animation/animation_container.h" |
| 43 #include "ui/gfx/animation/throb_animation.h" | 49 #include "ui/gfx/animation/throb_animation.h" |
| 44 #include "ui/gfx/canvas.h" | 50 #include "ui/gfx/canvas.h" |
| 45 #include "ui/gfx/display.h" | 51 #include "ui/gfx/display.h" |
| 46 #include "ui/gfx/geometry/rect_conversions.h" | 52 #include "ui/gfx/geometry/rect_conversions.h" |
| 47 #include "ui/gfx/geometry/size.h" | 53 #include "ui/gfx/geometry/size.h" |
| 48 #include "ui/gfx/image/image_skia.h" | 54 #include "ui/gfx/image/image_skia.h" |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 119 return gfx::Size(GetLayoutConstant(NEW_TAB_BUTTON_WIDTH), | 125 return gfx::Size(GetLayoutConstant(NEW_TAB_BUTTON_WIDTH), |
| 120 kNewTabButtonHeight); | 126 kNewTabButtonHeight); |
| 121 } | 127 } |
| 122 | 128 |
| 123 // Returns the width needed for the new tab button (and padding). | 129 // Returns the width needed for the new tab button (and padding). |
| 124 int GetNewTabButtonWidth() { | 130 int GetNewTabButtonWidth() { |
| 125 return GetLayoutConstant(NEW_TAB_BUTTON_WIDTH) - | 131 return GetLayoutConstant(NEW_TAB_BUTTON_WIDTH) - |
| 126 GetLayoutConstant(TABSTRIP_NEW_TAB_BUTTON_OVERLAP); | 132 GetLayoutConstant(TABSTRIP_NEW_TAB_BUTTON_OVERLAP); |
| 127 } | 133 } |
| 128 | 134 |
| 135 skia::RefPtr<SkDrawLooper> CreateShadowDrawLooper(SkAlpha alpha) { | |
| 136 SkLayerDrawLooper::Builder looper_builder; | |
| 137 looper_builder.addLayer(); | |
| 138 | |
| 139 SkLayerDrawLooper::LayerInfo layer_info; | |
| 140 layer_info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; | |
| 141 layer_info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit; | |
| 142 layer_info.fColorMode = SkXfermode::kDst_Mode; | |
| 143 layer_info.fOffset.set(0, 1); | |
| 144 skia::RefPtr<SkMaskFilter> blur_mask = | |
| 145 skia::AdoptRef(SkBlurMaskFilter::Create( | |
| 146 kNormal_SkBlurStyle, 0.5, SkBlurMaskFilter::kHighQuality_BlurFlag)); | |
| 147 skia::RefPtr<SkColorFilter> color_filter = | |
| 148 skia::AdoptRef(SkColorFilter::CreateModeFilter( | |
| 149 SkColorSetA(SK_ColorBLACK, alpha), SkXfermode::kSrcIn_Mode)); | |
| 150 SkPaint* layer_paint = looper_builder.addLayer(layer_info); | |
| 151 layer_paint->setMaskFilter(blur_mask.get()); | |
| 152 layer_paint->setColorFilter(color_filter.get()); | |
| 153 | |
| 154 return skia::AdoptRef(looper_builder.detachLooper()); | |
| 155 } | |
| 156 | |
| 129 // Animation delegate used for any automatic tab movement. Hides the tab if it | 157 // Animation delegate used for any automatic tab movement. Hides the tab if it |
| 130 // is not fully visible within the tabstrip area, to prevent overflow clipping. | 158 // is not fully visible within the tabstrip area, to prevent overflow clipping. |
| 131 class TabAnimationDelegate : public gfx::AnimationDelegate { | 159 class TabAnimationDelegate : public gfx::AnimationDelegate { |
| 132 public: | 160 public: |
| 133 TabAnimationDelegate(TabStrip* tab_strip, Tab* tab); | 161 TabAnimationDelegate(TabStrip* tab_strip, Tab* tab); |
| 134 ~TabAnimationDelegate() override; | 162 ~TabAnimationDelegate() override; |
| 135 | 163 |
| 136 void AnimationProgressed(const gfx::Animation* animation) override; | 164 void AnimationProgressed(const gfx::Animation* animation) override; |
| 137 | 165 |
| 138 protected: | 166 protected: |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 // views::ImageButton: | 288 // views::ImageButton: |
| 261 #if defined(OS_WIN) | 289 #if defined(OS_WIN) |
| 262 void OnMouseReleased(const ui::MouseEvent& event) override; | 290 void OnMouseReleased(const ui::MouseEvent& event) override; |
| 263 #endif | 291 #endif |
| 264 void OnGestureEvent(ui::GestureEvent* event) override; | 292 void OnGestureEvent(ui::GestureEvent* event) override; |
| 265 void OnPaint(gfx::Canvas* canvas) override; | 293 void OnPaint(gfx::Canvas* canvas) override; |
| 266 | 294 |
| 267 // views::MaskedTargeterDelegate: | 295 // views::MaskedTargeterDelegate: |
| 268 bool GetHitTestMask(gfx::Path* mask) const override; | 296 bool GetHitTestMask(gfx::Path* mask) const override; |
| 269 | 297 |
| 298 // Computes a path corresponding to the button's outer border for a given | |
| 299 // |scale| and stores it in |path|. |button_y| is used as the y-coordinate | |
| 300 // for the top of the button. If |extend_to_top| is true, the path is | |
| 301 // extended vertically to y = 0. The caller uses this for Fitts' Law purposes | |
| 302 // in maximized/fullscreen mode. | |
| 303 void GetBorderPath(float button_y, | |
| 304 float scale, | |
| 305 bool extend_to_top, | |
| 306 SkPath* path) const; | |
| 307 | |
| 270 // Paints the fill region of the button into |canvas|, according to the | 308 // Paints the fill region of the button into |canvas|, according to the |
| 271 // supplied values from GetImage(). | 309 // supplied values from GetImage() and the given |fill| path. |
| 272 void PaintFill(bool pressed, | 310 void PaintFill(bool pressed, |
| 273 double hover_value, | 311 double hover_value, |
| 274 float scale, | 312 float scale, |
| 313 const SkPath& fill, | |
| 275 gfx::Canvas* canvas) const; | 314 gfx::Canvas* canvas) const; |
| 276 | 315 |
| 277 // Tab strip that contains this button. | 316 // Tab strip that contains this button. |
| 278 TabStrip* tab_strip_; | 317 TabStrip* tab_strip_; |
| 279 | 318 |
| 280 // The offset used to paint the background image. | 319 // The offset used to paint the background image. |
| 281 gfx::Point background_offset_; | 320 gfx::Point background_offset_; |
| 282 | 321 |
| 283 // were we destroyed? | 322 // were we destroyed? |
| 284 bool* destroyed_; | 323 bool* destroyed_; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 332 gfx::ScopedCanvas scoped_canvas(canvas); | 371 gfx::ScopedCanvas scoped_canvas(canvas); |
| 333 canvas->Translate(gfx::Vector2d(0, height() - kNewTabButtonHeight)); | 372 canvas->Translate(gfx::Vector2d(0, height() - kNewTabButtonHeight)); |
| 334 | 373 |
| 335 const bool pressed = state() == views::CustomButton::STATE_PRESSED; | 374 const bool pressed = state() == views::CustomButton::STATE_PRESSED; |
| 336 double hover_value = | 375 double hover_value = |
| 337 (state() == views::CustomButton::STATE_HOVERED) ? 1 : 0; | 376 (state() == views::CustomButton::STATE_HOVERED) ? 1 : 0; |
| 338 if (hover_animation_->is_animating()) | 377 if (hover_animation_->is_animating()) |
| 339 hover_value = hover_animation_->GetCurrentValue(); | 378 hover_value = hover_animation_->GetCurrentValue(); |
| 340 const float scale = canvas->image_scale(); | 379 const float scale = canvas->image_scale(); |
| 341 | 380 |
| 342 // Fill. | 381 SkPath fill; |
| 343 gfx::ImageSkia* mask = | 382 if (ui::MaterialDesignController::IsModeMaterial()) { |
| 344 GetThemeProvider()->GetImageSkiaNamed(IDR_NEWTAB_BUTTON_MASK); | 383 // Fill. |
| 345 // The canvas and mask have to use the same scale factor. | 384 fill.moveTo(9.75 * scale, 16 * scale); |
| 346 const float fill_canvas_scale = mask->HasRepresentation(scale) ? | 385 fill.rCubicTo(-0.75 * scale, 0, -1.625 * scale, -0.5 * scale, -2 * scale, |
| 347 scale : ui::GetScaleForScaleFactor(ui::SCALE_FACTOR_100P); | 386 -1.5 * scale); |
| 348 gfx::Canvas fill_canvas(GetNewTabButtonSize(), fill_canvas_scale, false); | 387 fill.rLineTo(-5.75 * scale, -12.5 * scale); |
| 349 PaintFill(pressed, hover_value, fill_canvas_scale, &fill_canvas); | 388 fill.rCubicTo(0, -0.5 * scale, 0.25 * scale, -scale, scale, -scale); |
| 350 gfx::ImageSkia image(fill_canvas.ExtractImageRep()); | 389 fill.rLineTo(23.25 * scale, 0); |
| 351 canvas->DrawImageInt( | 390 fill.rCubicTo(0.75 * scale, 0, 1.625 * scale, 0.5 * scale, 2 * scale, |
| 352 gfx::ImageSkiaOperations::CreateMaskedImage(image, *mask), 0, 0); | 391 1.5 * scale); |
| 392 fill.rLineTo(5.75 * scale, 12.5 * scale); | |
| 393 fill.rCubicTo(0, 0.5 * scale, -0.25 * scale, scale, -scale, scale); | |
| 394 fill.close(); | |
| 395 PaintFill(pressed, hover_value, scale, fill, canvas); | |
| 353 | 396 |
| 354 // Stroke. Draw the button border with a slight alpha. | 397 // Stroke. |
| 355 static const SkAlpha kGlassFrameOverlayAlpha = 178; | 398 gfx::ScopedCanvas scoped_canvas(canvas); |
| 356 static const SkAlpha kOpaqueFrameOverlayAlpha = 230; | 399 canvas->UndoDeviceScaleFactor(); |
| 357 const SkAlpha alpha = GetWidget()->ShouldWindowContentsBeTransparent() ? | 400 SkPath stroke; |
| 358 kGlassFrameOverlayAlpha : kOpaqueFrameOverlayAlpha; | 401 GetBorderPath(0, scale, false, &stroke); |
| 359 const int overlay_id = pressed ? IDR_NEWTAB_BUTTON_P : IDR_NEWTAB_BUTTON; | 402 // We want to draw a drop shadow either inside or outside the stroke, |
| 360 canvas->DrawImageInt(*GetThemeProvider()->GetImageSkiaNamed(overlay_id), 0, 0, | 403 // depending on whether we're pressed; so, either clip out what's outside |
| 361 alpha); | 404 // the stroke, or clip out the fill inside it. |
| 405 if (pressed) | |
| 406 canvas->ClipPath(stroke, true); | |
| 407 Op(stroke, fill, kDifference_SkPathOp, &stroke); | |
| 408 if (!pressed) | |
| 409 canvas->sk_canvas()->clipPath(fill, SkRegion::kDifference_Op, true); | |
| 410 // Now draw the stroke and shadow; the stroke will always be visible, while | |
| 411 // the shadow will be affected by the clip we set above. | |
| 412 SkPaint paint; | |
| 413 paint.setAntiAlias(true); | |
| 414 skia::RefPtr<SkDrawLooper> stroke_looper = CreateShadowDrawLooper(0x8C); | |
| 415 paint.setLooper(stroke_looper.get()); | |
| 416 paint.setColor(SkColorSetA(SK_ColorBLACK, pressed ? 0x38 : 0x27)); | |
| 417 canvas->DrawPath(stroke, paint); | |
| 418 } else { | |
|
Peter Kasting
2015/12/09 01:20:30
This arm is copied verbatim from before, just inde
| |
| 419 // Fill. | |
| 420 gfx::ImageSkia* mask = | |
| 421 GetThemeProvider()->GetImageSkiaNamed(IDR_NEWTAB_BUTTON_MASK); | |
| 422 // The canvas and mask have to use the same scale factor. | |
| 423 const float fill_canvas_scale = mask->HasRepresentation(scale) ? | |
| 424 scale : ui::GetScaleForScaleFactor(ui::SCALE_FACTOR_100P); | |
| 425 gfx::Canvas fill_canvas(GetNewTabButtonSize(), fill_canvas_scale, false); | |
| 426 PaintFill(pressed, hover_value, fill_canvas_scale, fill, &fill_canvas); | |
| 427 gfx::ImageSkia image(fill_canvas.ExtractImageRep()); | |
| 428 canvas->DrawImageInt( | |
| 429 gfx::ImageSkiaOperations::CreateMaskedImage(image, *mask), 0, 0); | |
| 430 | |
| 431 // Stroke. Draw the button border with a slight alpha. | |
| 432 static const SkAlpha kGlassFrameOverlayAlpha = 178; | |
| 433 static const SkAlpha kOpaqueFrameOverlayAlpha = 230; | |
| 434 const SkAlpha alpha = GetWidget()->ShouldWindowContentsBeTransparent() ? | |
| 435 kGlassFrameOverlayAlpha : kOpaqueFrameOverlayAlpha; | |
| 436 const int overlay_id = pressed ? IDR_NEWTAB_BUTTON_P : IDR_NEWTAB_BUTTON; | |
| 437 canvas->DrawImageInt(*GetThemeProvider()->GetImageSkiaNamed(overlay_id), 0, | |
| 438 0, alpha); | |
| 439 } | |
| 362 } | 440 } |
| 363 | 441 |
| 364 bool NewTabButton::GetHitTestMask(gfx::Path* mask) const { | 442 bool NewTabButton::GetHitTestMask(gfx::Path* mask) const { |
| 365 DCHECK(mask); | 443 DCHECK(mask); |
| 366 | 444 |
| 367 if (tab_strip_->SizeTabButtonToTopOfTabStrip()) { | 445 if (ui::MaterialDesignController::IsModeMaterial()) { |
| 446 SkPath border; | |
| 447 const float scale = GetWidget()->GetCompositor()->device_scale_factor(); | |
| 448 GetBorderPath(TabStrip::kNewTabButtonVerticalOffset * scale, scale, | |
| 449 tab_strip_->SizeTabButtonToTopOfTabStrip(), &border); | |
| 450 mask->addPath(border, SkMatrix::MakeScale(1 / scale)); | |
| 451 } else if (tab_strip_->SizeTabButtonToTopOfTabStrip()) { | |
| 368 // When the button is sized to the top of the tab strip, we want the hit | 452 // When the button is sized to the top of the tab strip, we want the hit |
| 369 // test mask to be defined as the complete (rectangular) bounds of the | 453 // test mask to be defined as the complete (rectangular) bounds of the |
| 370 // button. | 454 // button. |
| 371 gfx::Rect button_bounds(GetContentsBounds()); | 455 gfx::Rect button_bounds(GetContentsBounds()); |
| 372 button_bounds.set_x(GetMirroredXForRect(button_bounds)); | 456 button_bounds.set_x(GetMirroredXForRect(button_bounds)); |
| 373 mask->addRect(RectToSkRect(button_bounds)); | 457 mask->addRect(RectToSkRect(button_bounds)); |
| 374 } else { | 458 } else { |
| 375 SkScalar w = SkIntToScalar(width()); | 459 SkScalar w = SkIntToScalar(width()); |
| 376 SkScalar v_offset = SkIntToScalar(TabStrip::kNewTabButtonVerticalOffset); | 460 SkScalar v_offset = SkIntToScalar(TabStrip::kNewTabButtonVerticalOffset); |
| 377 | 461 |
| 378 // These values are defined by the shape of the new tab image. Should that | 462 // These values are defined by the shape of the new tab image. Should that |
| 379 // image ever change, these values will need to be updated. They're so | 463 // image ever change, these values will need to be updated. They're so |
| 380 // custom it's not really worth defining constants for. | 464 // custom it's not really worth defining constants for. |
| 381 // These values are correct for regular and USE_ASH versions of the image. | 465 // These values are correct for regular and USE_ASH versions of the image. |
| 382 mask->moveTo(0, v_offset + 1); | 466 mask->moveTo(0, v_offset + 1); |
| 383 mask->lineTo(w - 7, v_offset + 1); | 467 mask->lineTo(w - 7, v_offset + 1); |
| 384 mask->lineTo(w - 4, v_offset + 4); | 468 mask->lineTo(w - 4, v_offset + 4); |
| 385 mask->lineTo(w, v_offset + 16); | 469 mask->lineTo(w, v_offset + 16); |
| 386 mask->lineTo(w - 1, v_offset + 17); | 470 mask->lineTo(w - 1, v_offset + 17); |
| 387 mask->lineTo(7, v_offset + 17); | 471 mask->lineTo(7, v_offset + 17); |
| 388 mask->lineTo(4, v_offset + 13); | 472 mask->lineTo(4, v_offset + 13); |
| 389 mask->lineTo(0, v_offset + 1); | 473 mask->lineTo(0, v_offset + 1); |
| 390 mask->close(); | 474 mask->close(); |
| 391 } | 475 } |
| 392 | 476 |
| 393 return true; | 477 return true; |
| 394 } | 478 } |
| 395 | 479 |
| 480 void NewTabButton::GetBorderPath(float button_y, | |
| 481 float scale, | |
| 482 bool extend_to_top, | |
| 483 SkPath* path) const { | |
| 484 path->moveTo(9.75 * scale - 1, button_y + 16 * scale + 1); | |
| 485 path->rCubicTo(-0.75 * scale, 0, -1.625 * scale, -0.5 * scale, -2 * scale, | |
| 486 -1.5 * scale); | |
| 487 path->rLineTo(-5.75 * scale, -12.5 * scale); | |
| 488 if (extend_to_top) { | |
| 489 // Create the vertical extension by extending the side diagonals at the | |
| 490 // upper left and lower right corners until they reach the top and bottom of | |
| 491 // the border, respectively (in other words, "un-round-off" those corners | |
| 492 // and turn them into sharp points). Then extend upward from the corner | |
| 493 // points to the top of the bounds. | |
| 494 const float dy = scale + 2; | |
| 495 const float dx = 11.5 / 25 * dy; | |
| 496 path->rLineTo(-dx, -dy); | |
| 497 path->rLineTo(0, -button_y - scale + 1); | |
| 498 path->lineTo(34 * scale + 1 + dx, 0); | |
| 499 path->rLineTo(0, button_y + 16 * scale + 1); | |
| 500 } else { | |
| 501 path->rCubicTo(-0.5 * scale, -1.125 * scale, 0.5 * scale, -scale - 2, scale, | |
| 502 -scale - 2); | |
| 503 path->rLineTo(23.25 * scale + 2, 0); | |
| 504 path->rCubicTo(0.75 * scale, 0, 1.625 * scale, 0.5 * scale, 2 * scale, | |
| 505 1.5 * scale); | |
| 506 path->rLineTo(5.75 * scale, 12.5 * scale); | |
| 507 path->rCubicTo(0.5 * scale, 1.125 * scale, -0.5 * scale, scale + 2, -scale, | |
| 508 scale + 2); | |
| 509 } | |
| 510 path->close(); | |
| 511 } | |
| 512 | |
| 396 void NewTabButton::PaintFill(bool pressed, | 513 void NewTabButton::PaintFill(bool pressed, |
| 397 double hover_value, | 514 double hover_value, |
| 398 float scale, | 515 float scale, |
| 516 const SkPath& fill, | |
| 399 gfx::Canvas* canvas) const { | 517 gfx::Canvas* canvas) const { |
| 400 bool custom_image; | 518 bool custom_image; |
| 401 const int bg_id = tab_strip_->GetBackgroundResourceId(&custom_image); | 519 const int bg_id = tab_strip_->GetBackgroundResourceId(&custom_image); |
| 402 | 520 |
| 521 gfx::ScopedCanvas scoped_canvas(canvas); | |
| 522 | |
| 523 const bool md = ui::MaterialDesignController::IsModeMaterial(); | |
| 524 if (md) { | |
| 525 canvas->UndoDeviceScaleFactor(); | |
| 526 | |
| 527 // For unpressed buttons, draw the fill and its shadow. | |
| 528 if (!pressed) { | |
| 529 gfx::ScopedCanvas scoped_canvas(canvas); | |
| 530 | |
| 531 // For custom themes, clip out the fill path itself so only the shadow | |
| 532 // around it is drawn. We'll draw the fill image below. | |
| 533 if (custom_image) | |
| 534 canvas->sk_canvas()->clipPath(fill, SkRegion::kDifference_Op, true); | |
| 535 | |
| 536 SkPaint paint; | |
| 537 paint.setAntiAlias(true); | |
| 538 skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(0x26); | |
| 539 paint.setLooper(looper.get()); | |
| 540 paint.setColor(Tab::kInactiveTabColor); | |
| 541 canvas->DrawPath(fill, paint); | |
| 542 } | |
| 543 | |
| 544 // Clip to just the fill region for any theme drawing and hover/pressed | |
| 545 // state overlay drawing below. In non-MD mode, this is done on the caller | |
| 546 // side using image masking operations. | |
| 547 canvas->ClipPath(fill, true); | |
| 548 canvas->sk_canvas()->scale(scale, scale); | |
| 549 } | |
| 550 | |
| 403 // Draw the fill background image. | 551 // Draw the fill background image. |
| 404 const gfx::Size size(GetNewTabButtonSize()); | 552 const gfx::Size size(GetNewTabButtonSize()); |
| 405 const ui::ThemeProvider* theme_provider = GetThemeProvider(); | 553 if (custom_image || !md) { |
| 406 gfx::ImageSkia* background = theme_provider->GetImageSkiaNamed(bg_id); | 554 const ui::ThemeProvider* theme_provider = GetThemeProvider(); |
| 407 // For custom tab backgrounds the background starts at the top of the tab | 555 gfx::ImageSkia* background = theme_provider->GetImageSkiaNamed(bg_id); |
| 408 // strip. Otherwise the background starts at the top of the frame. | 556 // For custom tab backgrounds the background starts at the top of the tab |
| 409 const int offset_y = theme_provider->HasCustomImage(bg_id) ? | 557 // strip. Otherwise the background starts at the top of the frame. |
| 410 -GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT) : background_offset_.y(); | 558 const int offset_y = theme_provider->HasCustomImage(bg_id) ? |
| 559 -GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT) : background_offset_.y(); | |
| 411 | 560 |
| 412 // The new tab background is mirrored in RTL mode, but the theme background | 561 // The new tab background is mirrored in RTL mode, but the theme background |
| 413 // should never be mirrored. Mirror it here to compensate. | 562 // should never be mirrored. Mirror it here to compensate. |
| 414 float x_scale = 1.0f; | 563 float x_scale = 1.0f; |
| 415 int x = GetMirroredX() + background_offset_.x(); | 564 int x = GetMirroredX() + background_offset_.x(); |
| 416 if (base::i18n::IsRTL()) { | 565 if (base::i18n::IsRTL()) { |
| 417 x_scale = -1.0f; | 566 x_scale = -1.0f; |
| 418 // Offset by |width| such that the same region is painted as if there was | 567 // Offset by |width| such that the same region is painted as if there was |
| 419 // no flip. | 568 // no flip. |
| 420 x += size.width(); | 569 x += size.width(); |
| 421 } | 570 } |
| 422 canvas->TileImageInt(*background, x, | 571 canvas->TileImageInt(*background, x, |
| 423 TabStrip::kNewTabButtonVerticalOffset + offset_y, | 572 TabStrip::kNewTabButtonVerticalOffset + offset_y, |
| 424 x_scale, 1.0f, 0, 0, size.width(), size.height()); | 573 x_scale, 1.0f, 0, 0, size.width(), size.height()); |
| 425 | 574 |
| 426 // Adjust the alpha of the fill to match that of inactive tabs (except for | 575 // For non-MD, adjust the alpha of the fill to match that of inactive tabs |
| 427 // pressed buttons, which get a different value). | 576 // (except for pressed buttons, which get a different value). For MD, we do |
| 428 static const SkAlpha kPressedAlpha = 145; | 577 // this with an opacity recorder in TabStrip::PaintChildren() so the fill |
| 429 const SkAlpha alpha = | 578 // and stroke are both affected, to better match how tabs are handled, but |
| 430 pressed ? kPressedAlpha : tab_strip_->GetInactiveAlpha(true); | 579 // in non-MD, the button stroke is already lighter than the tab stroke, and |
| 431 if (alpha != 255) { | 580 // using the opacity recorder washes it out too much. |
| 432 SkPaint paint; | 581 static const SkAlpha kPressedAlpha = 145; |
| 433 paint.setAlpha(alpha); | 582 const SkAlpha alpha = |
| 434 paint.setXfermodeMode(SkXfermode::kDstIn_Mode); | 583 pressed ? kPressedAlpha : tab_strip_->GetInactiveAlpha(true); |
| 435 paint.setStyle(SkPaint::kFill_Style); | 584 if (alpha != 255 && !md) { |
| 436 canvas->DrawRect(gfx::Rect(size), paint); | 585 SkPaint paint; |
| 586 paint.setAlpha(alpha); | |
| 587 paint.setXfermodeMode(SkXfermode::kDstIn_Mode); | |
| 588 paint.setStyle(SkPaint::kFill_Style); | |
| 589 canvas->DrawRect(gfx::Rect(size), paint); | |
| 590 } | |
| 437 } | 591 } |
| 438 | 592 |
| 439 // White highlight on hover. | 593 // White highlight on hover. |
| 440 if (hover_value) { | 594 if (hover_value) { |
| 441 const int alpha = | 595 const int alpha = |
| 442 gfx::Tween::LinearIntValueBetween(hover_value, 0x00, 0x40); | 596 gfx::Tween::LinearIntValueBetween(hover_value, 0x00, md ? 0x4D : 0x40); |
| 443 canvas->FillRect(GetLocalBounds(), | 597 canvas->FillRect(GetLocalBounds(), |
| 444 SkColorSetA(SK_ColorWHITE, static_cast<SkAlpha>(alpha))); | 598 SkColorSetA(SK_ColorWHITE, static_cast<SkAlpha>(alpha))); |
| 445 } | 599 } |
| 600 | |
| 601 // For MD, most states' opacities are adjusted using an opacity recorder in | |
| 602 // TabStrip::PaintChildren(), but the pressed state is excluded there and | |
| 603 // instead rendered using a dark overlay here. This produces a different | |
| 604 // effect than for non-MD, and avoiding the use of the opacity recorder keeps | |
| 605 // the stroke more visible in this state. | |
| 606 if (md && pressed) | |
| 607 canvas->FillRect(GetLocalBounds(), SkColorSetA(SK_ColorBLACK, 0x14)); | |
| 446 } | 608 } |
| 447 | 609 |
| 448 /////////////////////////////////////////////////////////////////////////////// | 610 /////////////////////////////////////////////////////////////////////////////// |
| 449 // TabStrip::RemoveTabDelegate | 611 // TabStrip::RemoveTabDelegate |
| 450 // | 612 // |
| 451 // AnimationDelegate used when removing a tab. Does the necessary cleanup when | 613 // AnimationDelegate used when removing a tab. Does the necessary cleanup when |
| 452 // done. | 614 // done. |
| 453 class TabStrip::RemoveTabDelegate : public TabAnimationDelegate { | 615 class TabStrip::RemoveTabDelegate : public TabAnimationDelegate { |
| 454 public: | 616 public: |
| 455 RemoveTabDelegate(TabStrip* tab_strip, Tab* tab); | 617 RemoveTabDelegate(TabStrip* tab_strip, Tab* tab); |
| (...skipping 807 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1263 void TabStrip::PaintChildren(const ui::PaintContext& context) { | 1425 void TabStrip::PaintChildren(const ui::PaintContext& context) { |
| 1264 // The view order doesn't match the paint order (tabs_ contains the tab | 1426 // The view order doesn't match the paint order (tabs_ contains the tab |
| 1265 // ordering). Additionally we need to paint the tabs that are closing in | 1427 // ordering). Additionally we need to paint the tabs that are closing in |
| 1266 // |tabs_closing_map_|. | 1428 // |tabs_closing_map_|. |
| 1267 bool is_dragging = false; | 1429 bool is_dragging = false; |
| 1268 Tab* active_tab = NULL; | 1430 Tab* active_tab = NULL; |
| 1269 Tabs tabs_dragging; | 1431 Tabs tabs_dragging; |
| 1270 Tabs selected_tabs; | 1432 Tabs selected_tabs; |
| 1271 | 1433 |
| 1272 { | 1434 { |
| 1273 const chrome::HostDesktopType host_desktop_type = | 1435 // TODO(pkasting): This results in greyscale AA for the tab titles. Work |
| 1274 chrome::GetHostDesktopTypeForNativeView(GetWidget()->GetNativeView()); | 1436 // with Mike Reed to fix, or else convert to passing the tabs a memory |
| 1275 const uint8_t inactive_tab_alpha = | 1437 // canvas to paint on and then manually compositing. |
| 1276 (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH) ? | |
| 1277 GetInactiveAlpha(false) : 255; | |
| 1278 ui::CompositingRecorder opacity_recorder(context, size(), | 1438 ui::CompositingRecorder opacity_recorder(context, size(), |
| 1279 inactive_tab_alpha); | 1439 GetInactiveAlpha(false)); |
| 1280 | 1440 |
| 1281 PaintClosingTabs(tab_count(), context); | 1441 PaintClosingTabs(tab_count(), context); |
| 1282 | 1442 |
| 1283 int active_tab_index = -1; | 1443 int active_tab_index = -1; |
| 1284 for (int i = tab_count() - 1; i >= 0; --i) { | 1444 for (int i = tab_count() - 1; i >= 0; --i) { |
| 1285 Tab* tab = tab_at(i); | 1445 Tab* tab = tab_at(i); |
| 1286 if (tab->dragging() && !stacked_layout_) { | 1446 if (tab->dragging() && !stacked_layout_) { |
| 1287 is_dragging = true; | 1447 is_dragging = true; |
| 1288 if (tab->IsActive()) { | 1448 if (tab->IsActive()) { |
| 1289 active_tab = tab; | 1449 active_tab = tab; |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 1312 tab->Paint(context); | 1472 tab->Paint(context); |
| 1313 } | 1473 } |
| 1314 | 1474 |
| 1315 for (int i = tab_count() - 1; i > active_tab_index; --i) { | 1475 for (int i = tab_count() - 1; i > active_tab_index; --i) { |
| 1316 Tab* tab = tab_at(i); | 1476 Tab* tab = tab_at(i); |
| 1317 tab->Paint(context); | 1477 tab->Paint(context); |
| 1318 } | 1478 } |
| 1319 } | 1479 } |
| 1320 } | 1480 } |
| 1321 | 1481 |
| 1322 if (GetWidget()->ShouldWindowContentsBeTransparent()) { | |
| 1323 ui::PaintRecorder recorder(context, size()); | |
| 1324 // Make sure non-active tabs are somewhat transparent. | |
| 1325 SkPaint paint; | |
| 1326 // If there are multiple tabs selected, fade non-selected tabs more to make | |
| 1327 // the selected tabs more noticable. | |
| 1328 uint8_t alpha = GetInactiveAlpha(false); | |
| 1329 paint.setColor(SkColorSetA(SK_ColorWHITE, alpha)); | |
| 1330 paint.setXfermodeMode(SkXfermode::kDstIn_Mode); | |
| 1331 paint.setStyle(SkPaint::kFill_Style); | |
| 1332 | |
| 1333 gfx::Rect bounds(GetLocalBounds()); | |
| 1334 // The tab graphics include some shadows at the top, plus a 1 pixel top | |
| 1335 // stroke. Exclude this region when trying to make tabs transparent as it's | |
| 1336 // transparent enough already, and drawing in this region can overlap the | |
| 1337 // avatar button, leading to visual artifacts. Also exclude the toolbar | |
| 1338 // overlap region at the bottom. | |
| 1339 gfx::Insets tab_insets(GetLayoutInsets(TAB)); | |
| 1340 bounds.Inset(0, tab_insets.top(), 0, tab_insets.bottom()); | |
| 1341 recorder.canvas()->DrawRect(bounds, paint); | |
| 1342 } | |
| 1343 | |
| 1344 // Now selected but not active. We don't want these dimmed if using native | 1482 // Now selected but not active. We don't want these dimmed if using native |
| 1345 // frame, so they're painted after initial pass. | 1483 // frame, so they're painted after initial pass. |
| 1346 for (size_t i = 0; i < selected_tabs.size(); ++i) | 1484 for (size_t i = 0; i < selected_tabs.size(); ++i) |
| 1347 selected_tabs[i]->Paint(context); | 1485 selected_tabs[i]->Paint(context); |
| 1348 | 1486 |
| 1349 // Next comes the active tab. | 1487 // Next comes the active tab. |
| 1350 if (active_tab && !is_dragging) | 1488 if (active_tab && !is_dragging) |
| 1351 active_tab->Paint(context); | 1489 active_tab->Paint(context); |
| 1352 | 1490 |
| 1353 // Paint the New Tab button. | 1491 // Paint the New Tab button. |
| 1354 newtab_button_->Paint(context); | 1492 const bool md = ui::MaterialDesignController::IsModeMaterial(); |
| 1493 if (md && (newtab_button_->state() != views::CustomButton::STATE_PRESSED)) { | |
| 1494 // Match the inactive tab opacity for non-pressed states. See comments in | |
| 1495 // NewTabButton::PaintFill() for why we don't do this for the pressed state. | |
| 1496 ui::CompositingRecorder opacity_recorder(context, size(), | |
| 1497 GetInactiveAlpha(true)); | |
| 1498 newtab_button_->Paint(context); | |
| 1499 } else { | |
| 1500 newtab_button_->Paint(context); | |
| 1501 } | |
| 1355 | 1502 |
| 1356 // And the dragged tabs. | 1503 // And the dragged tabs. |
| 1357 for (size_t i = 0; i < tabs_dragging.size(); ++i) | 1504 for (size_t i = 0; i < tabs_dragging.size(); ++i) |
| 1358 tabs_dragging[i]->Paint(context); | 1505 tabs_dragging[i]->Paint(context); |
| 1359 | 1506 |
| 1360 // If the active tab is being dragged, it goes last. | 1507 // If the active tab is being dragged, it goes last. |
| 1361 if (active_tab && is_dragging) | 1508 if (active_tab && is_dragging) |
| 1362 active_tab->Paint(context); | 1509 active_tab->Paint(context); |
| 1510 | |
| 1511 if (md) { | |
| 1512 ui::PaintRecorder recorder(context, size()); | |
| 1513 gfx::Canvas* canvas = recorder.canvas(); | |
| 1514 if (active_tab) { | |
| 1515 canvas->sk_canvas()->clipRect( | |
| 1516 gfx::RectToSkRect(active_tab->GetMirroredBounds()), | |
| 1517 SkRegion::kDifference_Op); | |
| 1518 } | |
| 1519 BrowserView::Paint1pxHorizontalLine( | |
| 1520 canvas, SkColorSetA(SK_ColorBLACK, 0x40), GetLocalBounds(), true); | |
| 1521 } | |
| 1363 } | 1522 } |
| 1364 | 1523 |
| 1365 const char* TabStrip::GetClassName() const { | 1524 const char* TabStrip::GetClassName() const { |
| 1366 static const char kViewClassName[] = "TabStrip"; | 1525 static const char kViewClassName[] = "TabStrip"; |
| 1367 return kViewClassName; | 1526 return kViewClassName; |
| 1368 } | 1527 } |
| 1369 | 1528 |
| 1370 gfx::Size TabStrip::GetPreferredSize() const { | 1529 gfx::Size TabStrip::GetPreferredSize() const { |
| 1371 int needed_tab_width; | 1530 int needed_tab_width; |
| 1372 if (touch_layout_ || adjust_layout_) { | 1531 if (touch_layout_ || adjust_layout_) { |
| (...skipping 1318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2691 ConvertPointToViewAndGetEventHandler(this, newtab_button_, point); | 2850 ConvertPointToViewAndGetEventHandler(this, newtab_button_, point); |
| 2692 if (view) | 2851 if (view) |
| 2693 return view; | 2852 return view; |
| 2694 } | 2853 } |
| 2695 Tab* tab = FindTabForEvent(point); | 2854 Tab* tab = FindTabForEvent(point); |
| 2696 if (tab) | 2855 if (tab) |
| 2697 return ConvertPointToViewAndGetEventHandler(this, tab, point); | 2856 return ConvertPointToViewAndGetEventHandler(this, tab, point); |
| 2698 } | 2857 } |
| 2699 return this; | 2858 return this; |
| 2700 } | 2859 } |
| OLD | NEW |