| 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.h" | 5 #include "chrome/browser/ui/views/tabs/tab.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 }; | 143 }; |
| 144 | 144 |
| 145 //////////////////////////////////////////////////////////////////////////////// | 145 //////////////////////////////////////////////////////////////////////////////// |
| 146 // ImageCacheEntryMetadata | 146 // ImageCacheEntryMetadata |
| 147 // | 147 // |
| 148 // All metadata necessary to uniquely identify a cached image. | 148 // All metadata necessary to uniquely identify a cached image. |
| 149 struct ImageCacheEntryMetadata { | 149 struct ImageCacheEntryMetadata { |
| 150 ImageCacheEntryMetadata(int resource_id, | 150 ImageCacheEntryMetadata(int resource_id, |
| 151 SkColor fill_color, | 151 SkColor fill_color, |
| 152 SkColor stroke_color, | 152 SkColor stroke_color, |
| 153 bool use_fill_and_stroke_images, |
| 153 ui::ScaleFactor scale_factor, | 154 ui::ScaleFactor scale_factor, |
| 154 const gfx::Size& size); | 155 const gfx::Size& size); |
| 155 | 156 |
| 156 ~ImageCacheEntryMetadata(); | 157 ~ImageCacheEntryMetadata(); |
| 157 | 158 |
| 158 bool operator==(const ImageCacheEntryMetadata& rhs) const; | 159 bool operator==(const ImageCacheEntryMetadata& rhs) const; |
| 159 | 160 |
| 160 int resource_id; // Only needed by pre-MD | 161 int resource_id; // Only needed by pre-MD |
| 161 SkColor fill_color; // Both colors only needed by MD | 162 SkColor fill_color; // Both colors only needed by MD |
| 162 SkColor stroke_color; | 163 SkColor stroke_color; |
| 164 bool use_fill_and_stroke_images; |
| 163 ui::ScaleFactor scale_factor; | 165 ui::ScaleFactor scale_factor; |
| 164 gfx::Size size; | 166 gfx::Size size; |
| 165 }; | 167 }; |
| 166 | 168 |
| 167 ImageCacheEntryMetadata::ImageCacheEntryMetadata(int resource_id, | 169 ImageCacheEntryMetadata::ImageCacheEntryMetadata( |
| 168 SkColor fill_color, | 170 int resource_id, |
| 169 SkColor stroke_color, | 171 SkColor fill_color, |
| 170 ui::ScaleFactor scale_factor, | 172 SkColor stroke_color, |
| 171 const gfx::Size& size) | 173 bool use_fill_and_stroke_images, |
| 174 ui::ScaleFactor scale_factor, |
| 175 const gfx::Size& size) |
| 172 : resource_id(resource_id), | 176 : resource_id(resource_id), |
| 173 fill_color(fill_color), | 177 fill_color(fill_color), |
| 174 stroke_color(stroke_color), | 178 stroke_color(stroke_color), |
| 179 use_fill_and_stroke_images(use_fill_and_stroke_images), |
| 175 scale_factor(scale_factor), | 180 scale_factor(scale_factor), |
| 176 size(size) { | 181 size(size) { |
| 177 DCHECK_NE(ui::SCALE_FACTOR_NONE, scale_factor); | 182 DCHECK_NE(ui::SCALE_FACTOR_NONE, scale_factor); |
| 178 | 183 |
| 179 // Some fields are only relevant for pre-MD vs. MD. Erase the irrelevant ones | 184 // Some fields are only relevant for pre-MD vs. MD. Erase the irrelevant ones |
| 180 // so they don't cause incorrect cache misses. | 185 // so they don't cause incorrect cache misses. |
| 181 // TODO(pkasting): Remove |resource_id| field when non-MD code is deleted. | 186 // TODO(pkasting): Remove |resource_id| field when non-MD code is deleted. |
| 182 if (ui::MaterialDesignController::IsModeMaterial()) | 187 if (ui::MaterialDesignController::IsModeMaterial()) |
| 183 resource_id = 0; | 188 resource_id = 0; |
| 184 else | 189 else |
| 185 fill_color = stroke_color = SK_ColorTRANSPARENT; | 190 fill_color = stroke_color = SK_ColorTRANSPARENT; |
| 186 } | 191 } |
| 187 | 192 |
| 188 ImageCacheEntryMetadata::~ImageCacheEntryMetadata() {} | 193 ImageCacheEntryMetadata::~ImageCacheEntryMetadata() {} |
| 189 | 194 |
| 190 bool ImageCacheEntryMetadata::operator==( | 195 bool ImageCacheEntryMetadata::operator==( |
| 191 const ImageCacheEntryMetadata& rhs) const { | 196 const ImageCacheEntryMetadata& rhs) const { |
| 192 return resource_id == rhs.resource_id && fill_color == rhs.fill_color && | 197 return resource_id == rhs.resource_id && fill_color == rhs.fill_color && |
| 193 stroke_color == rhs.stroke_color && scale_factor == rhs.scale_factor && | 198 stroke_color == rhs.stroke_color && |
| 194 size == rhs.size; | 199 use_fill_and_stroke_images == rhs.use_fill_and_stroke_images && |
| 200 scale_factor == rhs.scale_factor && size == rhs.size; |
| 195 } | 201 } |
| 196 | 202 |
| 197 //////////////////////////////////////////////////////////////////////////////// | 203 //////////////////////////////////////////////////////////////////////////////// |
| 198 // ImageCacheEntry and cache management | 204 // ImageCacheEntry and cache management |
| 199 // | 205 // |
| 200 // A cached image and the metadata used to generate it. | 206 // A cached image and the metadata used to generate it. |
| 201 struct ImageCacheEntry { | 207 struct ImageCacheEntry { |
| 202 ImageCacheEntry(const ImageCacheEntryMetadata& metadata, | 208 ImageCacheEntry(const ImageCacheEntryMetadata& metadata, |
| 203 const gfx::ImageSkia& image); | 209 const gfx::ImageSkia& fill_image, |
| 210 const gfx::ImageSkia& stroke_image); |
| 204 ~ImageCacheEntry(); | 211 ~ImageCacheEntry(); |
| 205 | 212 |
| 206 ImageCacheEntryMetadata metadata; | 213 ImageCacheEntryMetadata metadata; |
| 207 gfx::ImageSkia image; | 214 gfx::ImageSkia fill_image; |
| 215 gfx::ImageSkia stroke_image; |
| 208 }; | 216 }; |
| 209 | 217 |
| 210 ImageCacheEntry::ImageCacheEntry(const ImageCacheEntryMetadata& metadata, | 218 ImageCacheEntry::ImageCacheEntry(const ImageCacheEntryMetadata& metadata, |
| 211 const gfx::ImageSkia& image) | 219 const gfx::ImageSkia& fill_image, |
| 212 : metadata(metadata), image(image) {} | 220 const gfx::ImageSkia& stroke_image) |
| 221 : metadata(metadata), fill_image(fill_image), stroke_image(stroke_image) {} |
| 213 | 222 |
| 214 ImageCacheEntry::~ImageCacheEntry() {} | 223 ImageCacheEntry::~ImageCacheEntry() {} |
| 215 | 224 |
| 216 typedef std::list<ImageCacheEntry> ImageCache; | 225 typedef std::list<ImageCacheEntry> ImageCache; |
| 217 | 226 |
| 218 // As the majority of the tabs are inactive, and painting tabs is slowish, | 227 // As the majority of the tabs are inactive, and painting tabs is slowish, |
| 219 // we cache a handful of the inactive tab backgrounds here. | 228 // we cache a handful of the inactive tab backgrounds here. |
| 220 static ImageCache* g_image_cache = nullptr; | 229 static ImageCache* g_image_cache = nullptr; |
| 221 | 230 |
| 222 struct TabImages { | 231 struct TabImages { |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 465 theme_r.height() - toolbar_overlap, false); | 474 theme_r.height() - toolbar_overlap, false); |
| 466 | 475 |
| 467 // Draw center. Instead of masking out the top portion we simply skip over it | 476 // Draw center. Instead of masking out the top portion we simply skip over it |
| 468 // by incrementing by the top padding, since it's a simple rectangle. | 477 // by incrementing by the top padding, since it's a simple rectangle. |
| 469 rect.Inset(g_mask_images.l_width, tab_insets.top(), g_mask_images.r_width, | 478 rect.Inset(g_mask_images.l_width, tab_insets.top(), g_mask_images.r_width, |
| 470 toolbar_overlap); | 479 toolbar_overlap); |
| 471 canvas->TileImageInt(fill_image, rect.x(), rect.y(), g_mask_images.l_width, | 480 canvas->TileImageInt(fill_image, rect.x(), rect.y(), g_mask_images.l_width, |
| 472 tab_insets.top(), rect.width(), rect.height()); | 481 tab_insets.top(), rect.width(), rect.height()); |
| 473 } | 482 } |
| 474 | 483 |
| 475 void PaintTabBackgroundUsingParams(gfx::Canvas* canvas, | 484 void PaintTabBackgroundUsingParams(gfx::Canvas* fill_canvas, |
| 485 gfx::Canvas* stroke_canvas, |
| 476 views::GlowHoverController* hc, | 486 views::GlowHoverController* hc, |
| 477 const PaintBackgroundParams& params) { | 487 const PaintBackgroundParams& params) { |
| 478 const gfx::Rect& rect = params.rect; | 488 const gfx::Rect& rect = params.rect; |
| 479 const SkScalar kMinHoverRadius = 16; | 489 const SkScalar kMinHoverRadius = 16; |
| 480 const SkScalar radius = | 490 const SkScalar radius = |
| 481 std::max(SkFloatToScalar(rect.width() / 4.f), kMinHoverRadius); | 491 std::max(SkFloatToScalar(rect.width() / 4.f), kMinHoverRadius); |
| 482 const bool draw_hover = !params.is_active && hc; | 492 const bool draw_hover = !params.is_active && hc; |
| 483 SkPoint hover_location( | 493 SkPoint hover_location( |
| 484 gfx::PointToSkPoint(draw_hover ? hc->location() : gfx::Point())); | 494 gfx::PointToSkPoint(draw_hover ? hc->location() : gfx::Point())); |
| 485 const SkColor hover_color = | 495 const SkColor hover_color = |
| 486 SkColorSetA(params.toolbar_color, draw_hover ? hc->GetAlpha() : 255); | 496 SkColorSetA(params.toolbar_color, draw_hover ? hc->GetAlpha() : 255); |
| 487 | 497 |
| 488 if (ui::MaterialDesignController::IsModeMaterial()) { | 498 if (ui::MaterialDesignController::IsModeMaterial()) { |
| 489 gfx::ScopedCanvas scoped_canvas(canvas); | 499 gfx::Path fill; |
| 490 const float scale = canvas->UndoDeviceScaleFactor(); | 500 SkPaint paint; |
| 501 paint.setAntiAlias(true); |
| 491 | 502 |
| 492 // Draw the fill. | 503 // Draw the fill. |
| 493 gfx::Path fill = GetFillPath(scale, rect.size()); | |
| 494 SkPaint paint; | |
| 495 paint.setAntiAlias(true); | |
| 496 { | 504 { |
| 497 gfx::ScopedCanvas clip_scoper(canvas); | 505 gfx::ScopedCanvas scoped_canvas(fill_canvas); |
| 498 canvas->ClipPath(fill, true); | 506 const float scale = fill_canvas->UndoDeviceScaleFactor(); |
| 499 if (!params.fill_image.isNull()) { | 507 |
| 500 gfx::ScopedCanvas scale_scoper(canvas); | 508 fill = GetFillPath(scale, rect.size()); |
| 501 canvas->sk_canvas()->scale(scale, scale); | 509 { |
| 502 canvas->TileImageInt(params.fill_image, rect.x(), rect.y(), 0, 0, | 510 gfx::ScopedCanvas clip_scoper(fill_canvas); |
| 503 rect.width(), rect.height()); | 511 fill_canvas->ClipPath(fill, true); |
| 504 } else { | 512 if (!params.fill_image.isNull()) { |
| 505 paint.setColor(params.is_active ? params.toolbar_color | 513 gfx::ScopedCanvas scale_scoper(fill_canvas); |
| 506 : params.background_tab_color); | 514 fill_canvas->sk_canvas()->scale(scale, scale); |
| 507 canvas->DrawRect( | 515 fill_canvas->TileImageInt(params.fill_image, rect.x(), rect.y(), 0, 0, |
| 508 gfx::ScaleToEnclosingRect(gfx::Rect(rect.size()), scale), paint); | 516 rect.width(), rect.height()); |
| 509 } | 517 } else { |
| 510 if (draw_hover) { | 518 paint.setColor(params.is_active ? params.toolbar_color |
| 511 hover_location.scale(SkFloatToScalar(scale)); | 519 : params.background_tab_color); |
| 512 DrawHighlight(canvas, hover_location, radius * scale, hover_color); | 520 fill_canvas->DrawRect( |
| 521 gfx::ScaleToEnclosingRect(gfx::Rect(rect.size()), scale), |
| 522 paint); |
| 523 } |
| 524 if (draw_hover) { |
| 525 hover_location.scale(SkFloatToScalar(scale)); |
| 526 DrawHighlight(fill_canvas, hover_location, radius * scale, |
| 527 hover_color); |
| 528 } |
| 513 } | 529 } |
| 514 } | 530 } |
| 515 | 531 |
| 516 // Draw the stroke. | 532 // Draw the stroke. |
| 517 gfx::Path stroke = GetBorderPath(scale, false, false, rect.size()); | 533 { |
| 518 Op(stroke, fill, kDifference_SkPathOp, &stroke); | 534 gfx::ScopedCanvas scoped_canvas(stroke_canvas); |
| 519 if (!params.is_active) { | 535 const float scale = stroke_canvas->UndoDeviceScaleFactor(); |
| 520 // Clip out the bottom line; this will be drawn for us by | 536 |
| 521 // TabStrip::PaintChildren(). | 537 gfx::Path stroke = GetBorderPath(scale, false, false, rect.size()); |
| 522 canvas->ClipRect(gfx::RectF(rect.width() * scale, | 538 Op(stroke, fill, kDifference_SkPathOp, &stroke); |
| 523 rect.height() * scale - 1)); | 539 if (!params.is_active) { |
| 540 // Clip out the bottom line; this will be drawn for us by |
| 541 // TabStrip::PaintChildren(). |
| 542 stroke_canvas->ClipRect(gfx::RectF(rect.width() * scale, |
| 543 rect.height() * scale - 1)); |
| 544 } |
| 545 paint.setColor(params.stroke_color); |
| 546 stroke_canvas->DrawPath(stroke, paint); |
| 524 } | 547 } |
| 525 paint.setColor(params.stroke_color); | |
| 526 canvas->DrawPath(stroke, paint); | |
| 527 } else { | 548 } else { |
| 549 gfx::Canvas* canvas = stroke_canvas; |
| 528 if (draw_hover) { | 550 if (draw_hover) { |
| 529 // Draw everything to a temporary canvas so we can extract an image for | 551 // Draw everything to a temporary canvas so we can extract an image for |
| 530 // use in masking the hover glow. | 552 // use in masking the hover glow. |
| 531 gfx::Canvas background_canvas(rect.size(), canvas->image_scale(), false); | 553 gfx::Canvas background_canvas(rect.size(), canvas->image_scale(), false); |
| 532 PaintTabFill(&background_canvas, params.fill_image, rect, | 554 PaintTabFill(&background_canvas, params.fill_image, rect, |
| 533 params.is_active); | 555 params.is_active); |
| 534 gfx::ImageSkia background_image(background_canvas.ExtractImageRep()); | 556 gfx::ImageSkia background_image(background_canvas.ExtractImageRep()); |
| 535 canvas->DrawImageInt(background_image, 0, 0); | 557 canvas->DrawImageInt(background_image, 0, 0); |
| 536 | 558 |
| 537 gfx::Canvas hover_canvas(rect.size(), canvas->image_scale(), false); | 559 gfx::Canvas hover_canvas(rect.size(), canvas->image_scale(), false); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 645 void OnGestureEvent(ui::GestureEvent* event) override { | 667 void OnGestureEvent(ui::GestureEvent* event) override { |
| 646 // Consume all gesture events here so that the parent (Tab) does not | 668 // Consume all gesture events here so that the parent (Tab) does not |
| 647 // start consuming gestures. | 669 // start consuming gestures. |
| 648 ImageButton::OnGestureEvent(event); | 670 ImageButton::OnGestureEvent(event); |
| 649 event->SetHandled(); | 671 event->SetHandled(); |
| 650 } | 672 } |
| 651 | 673 |
| 652 const char* GetClassName() const override { return kTabCloseButtonName; } | 674 const char* GetClassName() const override { return kTabCloseButtonName; } |
| 653 | 675 |
| 654 private: | 676 private: |
| 655 // Returns the rectangular bounds of parent tab's visible region in the | |
| 656 // local coordinate space of |this|. | |
| 657 gfx::Rect GetTabBounds() const { | |
| 658 gfx::Path tab_mask; | |
| 659 tab_->GetHitTestMask(&tab_mask); | |
| 660 | |
| 661 gfx::RectF tab_bounds_f(gfx::SkRectToRectF(tab_mask.getBounds())); | |
| 662 views::View::ConvertRectToTarget(tab_, this, &tab_bounds_f); | |
| 663 return gfx::ToEnclosingRect(tab_bounds_f); | |
| 664 } | |
| 665 | |
| 666 // Returns the rectangular bounds of the tab close button in the local | |
| 667 // coordinate space of |this|, not including clipped regions on the top | |
| 668 // or bottom of the button. |tab_bounds| is the rectangular bounds of | |
| 669 // the parent tab's visible region in the local coordinate space of |this|. | |
| 670 gfx::Rect GetTabCloseButtonBounds(const gfx::Rect& tab_bounds) const { | |
| 671 gfx::Rect button_bounds(GetContentsBounds()); | |
| 672 button_bounds.set_x(GetMirroredXForRect(button_bounds)); | |
| 673 | |
| 674 int top_overflow = tab_bounds.y() - button_bounds.y(); | |
| 675 int bottom_overflow = button_bounds.bottom() - tab_bounds.bottom(); | |
| 676 if (top_overflow > 0) | |
| 677 button_bounds.set_y(tab_bounds.y()); | |
| 678 else if (bottom_overflow > 0) | |
| 679 button_bounds.set_height(button_bounds.height() - bottom_overflow); | |
| 680 | |
| 681 return button_bounds; | |
| 682 } | |
| 683 | |
| 684 // views::MaskedTargeterDelegate: | 677 // views::MaskedTargeterDelegate: |
| 685 View* TargetForRect(View* root, const gfx::Rect& rect) override { | 678 View* TargetForRect(View* root, const gfx::Rect& rect) override { |
| 686 CHECK_EQ(root, this); | 679 CHECK_EQ(root, this); |
| 687 | 680 |
| 688 if (!views::UsePointBasedTargeting(rect)) | 681 if (!views::UsePointBasedTargeting(rect)) |
| 689 return ViewTargeterDelegate::TargetForRect(root, rect); | 682 return ViewTargeterDelegate::TargetForRect(root, rect); |
| 690 | 683 |
| 691 // Ignore the padding set on the button. | 684 // Ignore the padding set on the button. |
| 692 gfx::Rect contents_bounds = GetContentsBounds(); | 685 gfx::Rect contents_bounds = GetContentsBounds(); |
| 693 contents_bounds.set_x(GetMirroredXForRect(contents_bounds)); | 686 contents_bounds.set_x(GetMirroredXForRect(contents_bounds)); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 704 // as it will be pointless. | 697 // as it will be pointless. |
| 705 if (aura::Env::GetInstance()->is_touch_down()) | 698 if (aura::Env::GetInstance()->is_touch_down()) |
| 706 contents_bounds = GetLocalBounds(); | 699 contents_bounds = GetLocalBounds(); |
| 707 #endif | 700 #endif |
| 708 | 701 |
| 709 return contents_bounds.Intersects(rect) ? this : parent(); | 702 return contents_bounds.Intersects(rect) ? this : parent(); |
| 710 } | 703 } |
| 711 | 704 |
| 712 // We need to define this so hit-testing won't include the border region. | 705 // We need to define this so hit-testing won't include the border region. |
| 713 bool GetHitTestMask(gfx::Path* mask) const override { | 706 bool GetHitTestMask(gfx::Path* mask) const override { |
| 714 DCHECK(mask); | 707 gfx::Rect button_bounds(GetContentsBounds()); |
| 715 mask->reset(); | 708 button_bounds.set_x(GetMirroredXForRect(button_bounds)); |
| 716 | 709 mask->addRect(gfx::RectToSkRect(button_bounds)); |
| 717 // The parent tab may be partially occluded by another tab if we are | 710 return true; |
| 718 // in stacked tab mode, which means that the tab close button may also | |
| 719 // be partially occluded. Define the hit test mask of the tab close | |
| 720 // button to be the intersection of the parent tab's visible bounds | |
| 721 // and the bounds of the tab close button. | |
| 722 gfx::Rect tab_bounds(GetTabBounds()); | |
| 723 gfx::Rect button_bounds(GetTabCloseButtonBounds(tab_bounds)); | |
| 724 gfx::Rect intersection(gfx::IntersectRects(tab_bounds, button_bounds)); | |
| 725 | |
| 726 if (!intersection.IsEmpty()) { | |
| 727 mask->addRect(RectToSkRect(intersection)); | |
| 728 return true; | |
| 729 } | |
| 730 | |
| 731 return false; | |
| 732 } | |
| 733 | |
| 734 bool DoesIntersectRect(const View* target, | |
| 735 const gfx::Rect& rect) const override { | |
| 736 CHECK_EQ(target, this); | |
| 737 | |
| 738 // If the request is not made in response to a gesture, use the | |
| 739 // default implementation. | |
| 740 if (views::UsePointBasedTargeting(rect)) | |
| 741 return MaskedTargeterDelegate::DoesIntersectRect(target, rect); | |
| 742 | |
| 743 // The hit test request is in response to a gesture. Return false if any | |
| 744 // part of the tab close button is hidden from the user. | |
| 745 // TODO(tdanderson): Consider always returning the intersection if the | |
| 746 // non-rectangular shape of the tab can be accounted for. | |
| 747 gfx::Rect tab_bounds(GetTabBounds()); | |
| 748 gfx::Rect button_bounds(GetTabCloseButtonBounds(tab_bounds)); | |
| 749 if (!tab_bounds.Contains(button_bounds)) | |
| 750 return false; | |
| 751 | |
| 752 return MaskedTargeterDelegate::DoesIntersectRect(target, rect); | |
| 753 } | 711 } |
| 754 | 712 |
| 755 Tab* tab_; | 713 Tab* tab_; |
| 756 | 714 |
| 757 DISALLOW_COPY_AND_ASSIGN(TabCloseButton); | 715 DISALLOW_COPY_AND_ASSIGN(TabCloseButton); |
| 758 }; | 716 }; |
| 759 | 717 |
| 760 //////////////////////////////////////////////////////////////////////////////// | 718 //////////////////////////////////////////////////////////////////////////////// |
| 761 // ThrobberView | 719 // ThrobberView |
| 762 // | 720 // |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1130 const gfx::Point& point, | 1088 const gfx::Point& point, |
| 1131 ui::MenuSourceType source_type) { | 1089 ui::MenuSourceType source_type) { |
| 1132 if (!closing()) | 1090 if (!closing()) |
| 1133 controller_->ShowContextMenuForTab(this, point, source_type); | 1091 controller_->ShowContextMenuForTab(this, point, source_type); |
| 1134 } | 1092 } |
| 1135 | 1093 |
| 1136 //////////////////////////////////////////////////////////////////////////////// | 1094 //////////////////////////////////////////////////////////////////////////////// |
| 1137 // Tab, views::MaskedTargeterDelegate overrides: | 1095 // Tab, views::MaskedTargeterDelegate overrides: |
| 1138 | 1096 |
| 1139 bool Tab::GetHitTestMask(gfx::Path* mask) const { | 1097 bool Tab::GetHitTestMask(gfx::Path* mask) const { |
| 1140 const float scale = GetWidget()->GetCompositor()->device_scale_factor(); | |
| 1141 // When the window is maximized we don't want to shave off the edges or top | 1098 // When the window is maximized we don't want to shave off the edges or top |
| 1142 // shadow of the tab, such that the user can click anywhere along the top | 1099 // shadow of the tab, such that the user can click anywhere along the top |
| 1143 // edge of the screen to select a tab. Ditto for immersive fullscreen. | 1100 // edge of the screen to select a tab. Ditto for immersive fullscreen. |
| 1144 const views::Widget* widget = GetWidget(); | 1101 const views::Widget* widget = GetWidget(); |
| 1145 const bool extend_to_top = | 1102 *mask = GetBorderPath( |
| 1146 widget && (widget->IsMaximized() || widget->IsFullscreen()); | 1103 GetWidget()->GetCompositor()->device_scale_factor(), true, |
| 1147 *mask = GetBorderPath(scale, true, extend_to_top, size()); | 1104 widget && (widget->IsMaximized() || widget->IsFullscreen()), size()); |
| 1148 | |
| 1149 // It is possible for a portion of the tab to be occluded if tabs are | |
| 1150 // stacked, so modify the hit test mask to only include the visible | |
| 1151 // region of the tab. | |
| 1152 gfx::Rect clip; | |
| 1153 controller_->ShouldPaintTab(this, &clip); | |
| 1154 if (clip.size().GetArea()) { | |
| 1155 SkRect intersection(mask->getBounds()); | |
| 1156 mask->reset(); | |
| 1157 if (!intersection.intersect(RectToSkRect(clip))) | |
| 1158 return false; | |
| 1159 mask->addRect(intersection); | |
| 1160 } | |
| 1161 return true; | 1105 return true; |
| 1162 } | 1106 } |
| 1163 | 1107 |
| 1164 //////////////////////////////////////////////////////////////////////////////// | 1108 //////////////////////////////////////////////////////////////////////////////// |
| 1165 // Tab, views::View overrides: | 1109 // Tab, views::View overrides: |
| 1166 | 1110 |
| 1167 void Tab::ViewHierarchyChanged(const ViewHierarchyChangedDetails& details) { | 1111 void Tab::ViewHierarchyChanged(const ViewHierarchyChangedDetails& details) { |
| 1168 // If this hierarchy changed has resulted in us being part of a widget | 1112 // If this hierarchy changed has resulted in us being part of a widget |
| 1169 // hierarchy for the first time, we can now get at the theme provider, and | 1113 // hierarchy for the first time, we can now get at the theme provider, and |
| 1170 // should recalculate the button color. | 1114 // should recalculate the button color. |
| 1171 if (details.is_add) | 1115 if (details.is_add) |
| 1172 OnButtonColorMaybeChanged(); | 1116 OnButtonColorMaybeChanged(); |
| 1173 } | 1117 } |
| 1174 | 1118 |
| 1175 void Tab::OnPaint(gfx::Canvas* canvas) { | 1119 void Tab::OnPaint(gfx::Canvas* canvas) { |
| 1176 // Don't paint if we're narrower than we can render correctly. (This should | 1120 // Don't paint if we're narrower than we can render correctly. (This should |
| 1177 // only happen during animations). | 1121 // only happen during animations). |
| 1178 if (width() < GetMinimumInactiveSize().width() && !data().pinned) | 1122 if (width() < GetMinimumInactiveSize().width() && !data().pinned) |
| 1179 return; | 1123 return; |
| 1180 | 1124 |
| 1181 gfx::Rect clip; | 1125 gfx::Path clip; |
| 1182 if (!controller_->ShouldPaintTab(this, &clip)) | 1126 if (!controller_->ShouldPaintTab( |
| 1127 this, base::Bind(&GetBorderPath, canvas->image_scale(), true, false), |
| 1128 &clip)) |
| 1183 return; | 1129 return; |
| 1184 if (!clip.IsEmpty()) { | |
| 1185 canvas->Save(); | |
| 1186 canvas->ClipRect(clip); | |
| 1187 } | |
| 1188 | 1130 |
| 1189 if (controller_->IsImmersiveStyle()) | 1131 if (controller_->IsImmersiveStyle()) |
| 1190 PaintImmersiveTab(canvas); | 1132 PaintImmersiveTab(canvas); |
| 1191 else | 1133 else |
| 1192 PaintTab(canvas); | 1134 PaintTab(canvas, clip); |
| 1193 | |
| 1194 if (!clip.IsEmpty()) | |
| 1195 canvas->Restore(); | |
| 1196 } | 1135 } |
| 1197 | 1136 |
| 1198 void Tab::Layout() { | 1137 void Tab::Layout() { |
| 1199 const gfx::Rect lb = GetContentsBounds(); | 1138 const gfx::Rect lb = GetContentsBounds(); |
| 1200 showing_icon_ = ShouldShowIcon(); | 1139 showing_icon_ = ShouldShowIcon(); |
| 1201 // See comments in IconCapacity(). | 1140 // See comments in IconCapacity(). |
| 1202 const int extra_padding = | 1141 const int extra_padding = |
| 1203 (controller_->ShouldHideCloseButtonForInactiveTabs() || | 1142 (controller_->ShouldHideCloseButtonForInactiveTabs() || |
| 1204 (IconCapacity() < 3)) ? 0 : kExtraLeftPaddingToBalanceCloseButtonPadding; | 1143 (IconCapacity() < 3)) ? 0 : kExtraLeftPaddingToBalanceCloseButtonPadding; |
| 1205 const int start = lb.x() + extra_padding; | 1144 const int start = lb.x() + extra_padding; |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1474 | 1413 |
| 1475 if (data().blocked == old.blocked) | 1414 if (data().blocked == old.blocked) |
| 1476 return; | 1415 return; |
| 1477 | 1416 |
| 1478 if (data().blocked) | 1417 if (data().blocked) |
| 1479 StartPulse(); | 1418 StartPulse(); |
| 1480 else | 1419 else |
| 1481 StopPulse(); | 1420 StopPulse(); |
| 1482 } | 1421 } |
| 1483 | 1422 |
| 1484 void Tab::PaintTab(gfx::Canvas* canvas) { | 1423 void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) { |
| 1485 const int kActiveTabFillId = IDR_THEME_TOOLBAR; | 1424 const int kActiveTabFillId = IDR_THEME_TOOLBAR; |
| 1486 const bool has_custom_image = | 1425 const bool has_custom_image = |
| 1487 GetThemeProvider()->HasCustomImage(kActiveTabFillId); | 1426 GetThemeProvider()->HasCustomImage(kActiveTabFillId); |
| 1488 const int y_offset = -GetYInsetForActiveTabBackground(); | 1427 const int y_offset = -GetYInsetForActiveTabBackground(); |
| 1489 if (IsActive()) { | 1428 if (IsActive()) { |
| 1490 PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId, | 1429 PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, |
| 1491 has_custom_image, y_offset); | 1430 has_custom_image, y_offset); |
| 1492 } else { | 1431 } else { |
| 1493 PaintInactiveTabBackground(canvas); | 1432 PaintInactiveTabBackground(canvas, clip); |
| 1494 | 1433 |
| 1495 const double throb_value = GetThrobValue(); | 1434 const double throb_value = GetThrobValue(); |
| 1496 if (throb_value > 0) { | 1435 if (throb_value > 0) { |
| 1497 canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff), | 1436 canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff), |
| 1498 GetLocalBounds()); | 1437 GetLocalBounds()); |
| 1499 PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId, | 1438 PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, |
| 1500 has_custom_image, y_offset); | 1439 has_custom_image, y_offset); |
| 1501 canvas->Restore(); | 1440 canvas->Restore(); |
| 1502 } | 1441 } |
| 1503 } | 1442 } |
| 1504 | 1443 |
| 1505 if (showing_icon_) | 1444 if (showing_icon_) |
| 1506 PaintIcon(canvas); | 1445 PaintIcon(canvas); |
| 1507 } | 1446 } |
| 1508 | 1447 |
| 1509 void Tab::PaintImmersiveTab(gfx::Canvas* canvas) { | 1448 void Tab::PaintImmersiveTab(gfx::Canvas* canvas) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1543 canvas->FillRect(right_eye_rect, kEyeColor); | 1482 canvas->FillRect(right_eye_rect, kEyeColor); |
| 1544 // The second part parts the remaining |eye_width| on the left. | 1483 // The second part parts the remaining |eye_width| on the left. |
| 1545 int left_eye_width = eye_offset + eye_width - bar_rect.width(); | 1484 int left_eye_width = eye_offset + eye_width - bar_rect.width(); |
| 1546 gfx::Rect left_eye_rect( | 1485 gfx::Rect left_eye_rect( |
| 1547 bar_rect.x(), 0, left_eye_width, kImmersiveBarHeight); | 1486 bar_rect.x(), 0, left_eye_width, kImmersiveBarHeight); |
| 1548 canvas->FillRect(left_eye_rect, kEyeColor); | 1487 canvas->FillRect(left_eye_rect, kEyeColor); |
| 1549 } | 1488 } |
| 1550 } | 1489 } |
| 1551 } | 1490 } |
| 1552 | 1491 |
| 1553 void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) { | 1492 void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas, |
| 1493 const gfx::Path& clip) { |
| 1554 bool has_custom_image; | 1494 bool has_custom_image; |
| 1555 int fill_id = controller_->GetBackgroundResourceId(&has_custom_image); | 1495 int fill_id = controller_->GetBackgroundResourceId(&has_custom_image); |
| 1556 | 1496 |
| 1557 // If the theme is providing a custom background image, then its top edge | 1497 // If the theme is providing a custom background image, then its top edge |
| 1558 // should be at the top of the tab. Otherwise, we assume that the background | 1498 // should be at the top of the tab. Otherwise, we assume that the background |
| 1559 // image is a composited foreground + frame image. Note that if the theme is | 1499 // image is a composited foreground + frame image. Note that if the theme is |
| 1560 // only providing a custom frame image, |has_custom_image| will be true, but | 1500 // only providing a custom frame image, |has_custom_image| will be true, but |
| 1561 // we should use the |background_offset_| here. | 1501 // we should use the |background_offset_| here. |
| 1562 const ui::ThemeProvider* tp = GetThemeProvider(); | 1502 const ui::ThemeProvider* tp = GetThemeProvider(); |
| 1563 const int y_offset = tp->HasCustomImage(fill_id) ? | 1503 const int y_offset = tp->HasCustomImage(fill_id) ? |
| 1564 -GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT) : background_offset_.y(); | 1504 -GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT) : background_offset_.y(); |
| 1565 | 1505 |
| 1566 // We only cache the image when it's the default image and we're not hovered, | 1506 // We only cache the image when it's the default image and we're not hovered, |
| 1567 // to avoid caching a background image that isn't the same for all tabs. | 1507 // to avoid caching a background image that isn't the same for all tabs. |
| 1568 if (has_custom_image || hover_controller_.ShouldDraw()) { | 1508 if (has_custom_image || hover_controller_.ShouldDraw()) { |
| 1569 PaintTabBackgroundUsingFillId(canvas, false, fill_id, has_custom_image, | 1509 PaintTabBackgroundUsingFillId(canvas, canvas, false, fill_id, |
| 1570 y_offset); | 1510 has_custom_image, y_offset); |
| 1571 return; | 1511 return; |
| 1572 } | 1512 } |
| 1573 | 1513 |
| 1514 // For efficiency, we don't use separate fill and stroke images unless we |
| 1515 // really need to clip the stroke and not the fill (for stacked tabs). This |
| 1516 // saves memory and avoids an extra image draw at the cost of recalculating |
| 1517 // the images when MaySetClip() toggles. |
| 1518 const bool use_fill_and_stroke_images = |
| 1519 controller_->MaySetClip() && |
| 1520 ui::MaterialDesignController::IsModeMaterial(); |
| 1521 |
| 1574 const ImageCacheEntryMetadata metadata( | 1522 const ImageCacheEntryMetadata metadata( |
| 1575 fill_id, tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB), | 1523 fill_id, tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB), |
| 1576 controller_->GetToolbarTopSeparatorColor(), | 1524 controller_->GetToolbarTopSeparatorColor(), use_fill_and_stroke_images, |
| 1577 ui::GetSupportedScaleFactor(canvas->image_scale()), size()); | 1525 ui::GetSupportedScaleFactor(canvas->image_scale()), size()); |
| 1578 auto it = std::find_if( | 1526 auto it = std::find_if( |
| 1579 g_image_cache->begin(), g_image_cache->end(), | 1527 g_image_cache->begin(), g_image_cache->end(), |
| 1580 [&metadata](const ImageCacheEntry& e) { return e.metadata == metadata; }); | 1528 [&metadata](const ImageCacheEntry& e) { return e.metadata == metadata; }); |
| 1581 if (it == g_image_cache->end()) { | 1529 if (it == g_image_cache->end()) { |
| 1582 gfx::Canvas tmp_canvas(size(), canvas->image_scale(), false); | 1530 gfx::Canvas tmp_canvas(size(), canvas->image_scale(), false); |
| 1583 PaintTabBackgroundUsingFillId(&tmp_canvas, false, fill_id, false, y_offset); | 1531 if (use_fill_and_stroke_images) { |
| 1584 g_image_cache->emplace_front(metadata, | 1532 gfx::Canvas tmp_fill_canvas(size(), canvas->image_scale(), false); |
| 1585 gfx::ImageSkia(tmp_canvas.ExtractImageRep())); | 1533 PaintTabBackgroundUsingFillId(&tmp_fill_canvas, &tmp_canvas, false, |
| 1534 fill_id, false, y_offset); |
| 1535 g_image_cache->emplace_front( |
| 1536 metadata, gfx::ImageSkia(tmp_fill_canvas.ExtractImageRep()), |
| 1537 gfx::ImageSkia(tmp_canvas.ExtractImageRep())); |
| 1538 } else { |
| 1539 PaintTabBackgroundUsingFillId(&tmp_canvas, &tmp_canvas, false, fill_id, |
| 1540 false, y_offset); |
| 1541 g_image_cache->emplace_front( |
| 1542 metadata, gfx::ImageSkia(), |
| 1543 gfx::ImageSkia(tmp_canvas.ExtractImageRep())); |
| 1544 } |
| 1586 if (g_image_cache->size() > kMaxImageCacheSize) | 1545 if (g_image_cache->size() > kMaxImageCacheSize) |
| 1587 g_image_cache->pop_back(); | 1546 g_image_cache->pop_back(); |
| 1588 it = g_image_cache->begin(); | 1547 it = g_image_cache->begin(); |
| 1589 } | 1548 } |
| 1590 canvas->DrawImageInt(it->image, 0, 0); | 1549 |
| 1550 gfx::ScopedCanvas scoped_canvas( |
| 1551 use_fill_and_stroke_images ? canvas : nullptr); |
| 1552 if (use_fill_and_stroke_images) { |
| 1553 canvas->DrawImageInt(it->fill_image, 0, 0); |
| 1554 canvas->sk_canvas()->clipPath(clip, SkRegion::kDifference_Op, true); |
| 1555 } |
| 1556 canvas->DrawImageInt(it->stroke_image, 0, 0); |
| 1591 } | 1557 } |
| 1592 | 1558 |
| 1593 void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* canvas, | 1559 void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* fill_canvas, |
| 1560 gfx::Canvas* stroke_canvas, |
| 1594 bool is_active, | 1561 bool is_active, |
| 1595 int fill_id, | 1562 int fill_id, |
| 1596 bool has_custom_image, | 1563 bool has_custom_image, |
| 1597 int y_offset) { | 1564 int y_offset) { |
| 1598 views::GlowHoverController* hc = | 1565 views::GlowHoverController* hc = |
| 1599 hover_controller_.ShouldDraw() ? &hover_controller_ : nullptr; | 1566 hover_controller_.ShouldDraw() ? &hover_controller_ : nullptr; |
| 1600 gfx::ImageSkia* fill_image = | 1567 gfx::ImageSkia* fill_image = |
| 1601 has_custom_image || !ui::MaterialDesignController::IsModeMaterial() | 1568 has_custom_image || !ui::MaterialDesignController::IsModeMaterial() |
| 1602 ? GetThemeProvider()->GetImageSkiaNamed(fill_id) | 1569 ? GetThemeProvider()->GetImageSkiaNamed(fill_id) |
| 1603 : nullptr; | 1570 : nullptr; |
| 1604 // The tab image needs to be lined up with the background image | 1571 // The tab image needs to be lined up with the background image |
| 1605 // so that it feels partially transparent. These offsets represent the tab | 1572 // so that it feels partially transparent. These offsets represent the tab |
| 1606 // position within the frame background image. | 1573 // position within the frame background image. |
| 1607 gfx::Rect rect(GetLocalBounds()); | 1574 gfx::Rect rect(GetLocalBounds()); |
| 1608 rect.Offset(GetMirroredX() + background_offset_.x(), y_offset); | 1575 rect.Offset(GetMirroredX() + background_offset_.x(), y_offset); |
| 1609 PaintBackgroundParams params( | 1576 PaintBackgroundParams params( |
| 1610 is_active, fill_image, has_custom_image, rect, | 1577 is_active, fill_image, has_custom_image, rect, |
| 1611 controller_->GetToolbarTopSeparatorColor(), | 1578 controller_->GetToolbarTopSeparatorColor(), |
| 1612 GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR), | 1579 GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR), |
| 1613 GetThemeProvider()->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB)); | 1580 GetThemeProvider()->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB)); |
| 1614 | 1581 |
| 1615 PaintTabBackgroundUsingParams(canvas, hc, params); | 1582 PaintTabBackgroundUsingParams(fill_canvas, stroke_canvas, hc, params); |
| 1616 } | 1583 } |
| 1617 | 1584 |
| 1618 void Tab::PaintPinnedTabTitleChangedIndicatorAndIcon( | 1585 void Tab::PaintPinnedTabTitleChangedIndicatorAndIcon( |
| 1619 gfx::Canvas* canvas, | 1586 gfx::Canvas* canvas, |
| 1620 const gfx::Rect& favicon_draw_bounds) { | 1587 const gfx::Rect& favicon_draw_bounds) { |
| 1621 // The pinned tab title changed indicator consists of two parts: | 1588 // The pinned tab title changed indicator consists of two parts: |
| 1622 // . a clear (totally transparent) part over the bottom right (or left in rtl) | 1589 // . a clear (totally transparent) part over the bottom right (or left in rtl) |
| 1623 // of the favicon. This is done by drawing the favicon to a canvas, then | 1590 // of the favicon. This is done by drawing the favicon to a canvas, then |
| 1624 // drawing the clear part on top of the favicon. | 1591 // drawing the clear part on top of the favicon. |
| 1625 // . a circle in the bottom right (or left in rtl) of the favicon. | 1592 // . a circle in the bottom right (or left in rtl) of the favicon. |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1854 gfx::Rect Tab::GetImmersiveBarRect() const { | 1821 gfx::Rect Tab::GetImmersiveBarRect() const { |
| 1855 // The main bar is as wide as the normal tab's horizontal top line. | 1822 // The main bar is as wide as the normal tab's horizontal top line. |
| 1856 // This top line of the tab extends a few pixels left and right of the | 1823 // This top line of the tab extends a few pixels left and right of the |
| 1857 // center image due to pixels in the rounded corner images. | 1824 // center image due to pixels in the rounded corner images. |
| 1858 const int kBarPadding = 1; | 1825 const int kBarPadding = 1; |
| 1859 int main_bar_left = g_active_images.l_width - kBarPadding; | 1826 int main_bar_left = g_active_images.l_width - kBarPadding; |
| 1860 int main_bar_right = width() - g_active_images.r_width + kBarPadding; | 1827 int main_bar_right = width() - g_active_images.r_width + kBarPadding; |
| 1861 return gfx::Rect( | 1828 return gfx::Rect( |
| 1862 main_bar_left, 0, main_bar_right - main_bar_left, kImmersiveBarHeight); | 1829 main_bar_left, 0, main_bar_right - main_bar_left, kImmersiveBarHeight); |
| 1863 } | 1830 } |
| OLD | NEW |