Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(280)

Side by Side Diff: chrome/browser/ui/views/tabs/tab_strip.cc

Issue 1401633003: Implement Material Design for the tabstrip. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Resync Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/ui/views/tabs/tab.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/layout_constants.h" 19 #include "chrome/browser/ui/layout_constants.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h" 20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
21 #include "chrome/browser/ui/view_ids.h" 21 #include "chrome/browser/ui/view_ids.h"
22 #include "chrome/browser/ui/views/frame/browser_view.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
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
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
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 {
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
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
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
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 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/tabs/tab.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698