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.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 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 117 const char kTabCloseButtonName[] = "TabCloseButton"; | 117 const char kTabCloseButtonName[] = "TabCloseButton"; |
| 118 | 118 |
| 119 //////////////////////////////////////////////////////////////////////////////// | 119 //////////////////////////////////////////////////////////////////////////////// |
| 120 // ImageCacheEntryMetadata | 120 // ImageCacheEntryMetadata |
| 121 // | 121 // |
| 122 // All metadata necessary to uniquely identify a cached image. | 122 // All metadata necessary to uniquely identify a cached image. |
| 123 struct ImageCacheEntryMetadata { | 123 struct ImageCacheEntryMetadata { |
| 124 ImageCacheEntryMetadata(int resource_id, | 124 ImageCacheEntryMetadata(int resource_id, |
| 125 SkColor fill_color, | 125 SkColor fill_color, |
| 126 SkColor stroke_color, | 126 SkColor stroke_color, |
| 127 bool use_fill_and_stroke_images, | |
| 127 ui::ScaleFactor scale_factor, | 128 ui::ScaleFactor scale_factor, |
| 128 const gfx::Size& size); | 129 const gfx::Size& size); |
| 129 | 130 |
| 130 ~ImageCacheEntryMetadata(); | 131 ~ImageCacheEntryMetadata(); |
| 131 | 132 |
| 132 bool operator==(const ImageCacheEntryMetadata& rhs) const; | 133 bool operator==(const ImageCacheEntryMetadata& rhs) const; |
| 133 | 134 |
| 134 int resource_id; // Only needed by pre-MD | 135 int resource_id; // Only needed by pre-MD |
| 135 SkColor fill_color; // Both colors only needed by MD | 136 SkColor fill_color; // Both colors only needed by MD |
| 136 SkColor stroke_color; | 137 SkColor stroke_color; |
| 138 bool use_fill_and_stroke_images; | |
| 137 ui::ScaleFactor scale_factor; | 139 ui::ScaleFactor scale_factor; |
| 138 gfx::Size size; | 140 gfx::Size size; |
| 139 }; | 141 }; |
| 140 | 142 |
| 141 ImageCacheEntryMetadata::ImageCacheEntryMetadata(int resource_id, | 143 ImageCacheEntryMetadata::ImageCacheEntryMetadata( |
| 142 SkColor fill_color, | 144 int resource_id, |
| 143 SkColor stroke_color, | 145 SkColor fill_color, |
| 144 ui::ScaleFactor scale_factor, | 146 SkColor stroke_color, |
| 145 const gfx::Size& size) | 147 bool use_fill_and_stroke_images, |
| 148 ui::ScaleFactor scale_factor, | |
| 149 const gfx::Size& size) | |
| 146 : resource_id(resource_id), | 150 : resource_id(resource_id), |
| 147 fill_color(fill_color), | 151 fill_color(fill_color), |
| 148 stroke_color(stroke_color), | 152 stroke_color(stroke_color), |
| 153 use_fill_and_stroke_images(use_fill_and_stroke_images), | |
| 149 scale_factor(scale_factor), | 154 scale_factor(scale_factor), |
| 150 size(size) { | 155 size(size) { |
| 151 DCHECK_NE(ui::SCALE_FACTOR_NONE, scale_factor); | 156 DCHECK_NE(ui::SCALE_FACTOR_NONE, scale_factor); |
| 152 | 157 |
| 153 // Some fields are only relevant for pre-MD vs. MD. Erase the irrelevant ones | 158 // Some fields are only relevant for pre-MD vs. MD. Erase the irrelevant ones |
| 154 // so they don't cause incorrect cache misses. | 159 // so they don't cause incorrect cache misses. |
| 155 // TODO(pkasting): Remove |resource_id| field when non-MD code is deleted. | 160 // TODO(pkasting): Remove |resource_id| field when non-MD code is deleted. |
| 156 if (ui::MaterialDesignController::IsModeMaterial()) | 161 if (ui::MaterialDesignController::IsModeMaterial()) |
| 157 resource_id = 0; | 162 resource_id = 0; |
| 158 else | 163 else |
| 159 fill_color = stroke_color = SK_ColorTRANSPARENT; | 164 fill_color = stroke_color = SK_ColorTRANSPARENT; |
| 160 } | 165 } |
| 161 | 166 |
| 162 ImageCacheEntryMetadata::~ImageCacheEntryMetadata() {} | 167 ImageCacheEntryMetadata::~ImageCacheEntryMetadata() {} |
| 163 | 168 |
| 164 bool ImageCacheEntryMetadata::operator==( | 169 bool ImageCacheEntryMetadata::operator==( |
| 165 const ImageCacheEntryMetadata& rhs) const { | 170 const ImageCacheEntryMetadata& rhs) const { |
| 166 return resource_id == rhs.resource_id && fill_color == rhs.fill_color && | 171 return resource_id == rhs.resource_id && fill_color == rhs.fill_color && |
| 167 stroke_color == rhs.stroke_color && scale_factor == rhs.scale_factor && | 172 stroke_color == rhs.stroke_color && |
| 168 size == rhs.size; | 173 use_fill_and_stroke_images == rhs.use_fill_and_stroke_images && |
| 174 scale_factor == rhs.scale_factor && size == rhs.size; | |
| 169 } | 175 } |
| 170 | 176 |
| 171 //////////////////////////////////////////////////////////////////////////////// | 177 //////////////////////////////////////////////////////////////////////////////// |
| 172 // ImageCacheEntry and cache management | 178 // ImageCacheEntry and cache management |
| 173 // | 179 // |
| 174 // A cached image and the metadata used to generate it. | 180 // A cached image and the metadata used to generate it. |
| 175 struct ImageCacheEntry { | 181 struct ImageCacheEntry { |
| 176 ImageCacheEntry(const ImageCacheEntryMetadata& metadata, | 182 ImageCacheEntry(const ImageCacheEntryMetadata& metadata, |
| 177 const gfx::ImageSkia& image); | 183 const gfx::ImageSkia& fill_image, |
| 184 const gfx::ImageSkia& stroke_image); | |
| 178 ~ImageCacheEntry(); | 185 ~ImageCacheEntry(); |
| 179 | 186 |
| 180 ImageCacheEntryMetadata metadata; | 187 ImageCacheEntryMetadata metadata; |
| 181 gfx::ImageSkia image; | 188 gfx::ImageSkia fill_image; |
| 189 gfx::ImageSkia stroke_image; | |
| 182 }; | 190 }; |
| 183 | 191 |
| 184 ImageCacheEntry::ImageCacheEntry(const ImageCacheEntryMetadata& metadata, | 192 ImageCacheEntry::ImageCacheEntry(const ImageCacheEntryMetadata& metadata, |
| 185 const gfx::ImageSkia& image) | 193 const gfx::ImageSkia& fill_image, |
| 186 : metadata(metadata), image(image) {} | 194 const gfx::ImageSkia& stroke_image) |
| 195 : metadata(metadata), fill_image(fill_image), stroke_image(stroke_image) {} | |
| 187 | 196 |
| 188 ImageCacheEntry::~ImageCacheEntry() {} | 197 ImageCacheEntry::~ImageCacheEntry() {} |
| 189 | 198 |
| 190 typedef std::list<ImageCacheEntry> ImageCache; | 199 typedef std::list<ImageCacheEntry> ImageCache; |
| 191 | 200 |
| 192 // As the majority of the tabs are inactive, and painting tabs is slowish, | 201 // As the majority of the tabs are inactive, and painting tabs is slowish, |
| 193 // we cache a handful of the inactive tab backgrounds here. | 202 // we cache a handful of the inactive tab backgrounds here. |
| 194 static ImageCache* g_image_cache = nullptr; | 203 static ImageCache* g_image_cache = nullptr; |
| 195 | 204 |
| 196 struct TabImages { | 205 struct TabImages { |
| (...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 538 void OnGestureEvent(ui::GestureEvent* event) override { | 547 void OnGestureEvent(ui::GestureEvent* event) override { |
| 539 // Consume all gesture events here so that the parent (Tab) does not | 548 // Consume all gesture events here so that the parent (Tab) does not |
| 540 // start consuming gestures. | 549 // start consuming gestures. |
| 541 ImageButton::OnGestureEvent(event); | 550 ImageButton::OnGestureEvent(event); |
| 542 event->SetHandled(); | 551 event->SetHandled(); |
| 543 } | 552 } |
| 544 | 553 |
| 545 const char* GetClassName() const override { return kTabCloseButtonName; } | 554 const char* GetClassName() const override { return kTabCloseButtonName; } |
| 546 | 555 |
| 547 private: | 556 private: |
| 548 // Returns the rectangular bounds of parent tab's visible region in the | |
| 549 // local coordinate space of |this|. | |
| 550 gfx::Rect GetTabBounds() const { | |
| 551 gfx::Path tab_mask; | |
| 552 tab_->GetHitTestMask(&tab_mask); | |
| 553 | |
| 554 gfx::RectF tab_bounds_f(gfx::SkRectToRectF(tab_mask.getBounds())); | |
| 555 views::View::ConvertRectToTarget(tab_, this, &tab_bounds_f); | |
| 556 return gfx::ToEnclosingRect(tab_bounds_f); | |
| 557 } | |
| 558 | |
| 559 // Returns the rectangular bounds of the tab close button in the local | |
| 560 // coordinate space of |this|, not including clipped regions on the top | |
| 561 // or bottom of the button. |tab_bounds| is the rectangular bounds of | |
| 562 // the parent tab's visible region in the local coordinate space of |this|. | |
| 563 gfx::Rect GetTabCloseButtonBounds(const gfx::Rect& tab_bounds) const { | |
| 564 gfx::Rect button_bounds(GetContentsBounds()); | |
| 565 button_bounds.set_x(GetMirroredXForRect(button_bounds)); | |
| 566 | |
| 567 int top_overflow = tab_bounds.y() - button_bounds.y(); | |
| 568 int bottom_overflow = button_bounds.bottom() - tab_bounds.bottom(); | |
| 569 if (top_overflow > 0) | |
| 570 button_bounds.set_y(tab_bounds.y()); | |
| 571 else if (bottom_overflow > 0) | |
| 572 button_bounds.set_height(button_bounds.height() - bottom_overflow); | |
| 573 | |
| 574 return button_bounds; | |
| 575 } | |
| 576 | |
| 577 // views::MaskedTargeterDelegate: | 557 // views::MaskedTargeterDelegate: |
| 578 View* TargetForRect(View* root, const gfx::Rect& rect) override { | 558 View* TargetForRect(View* root, const gfx::Rect& rect) override { |
| 579 CHECK_EQ(root, this); | 559 CHECK_EQ(root, this); |
| 580 | 560 |
| 581 if (!views::UsePointBasedTargeting(rect)) | 561 if (!views::UsePointBasedTargeting(rect)) |
| 582 return ViewTargeterDelegate::TargetForRect(root, rect); | 562 return ViewTargeterDelegate::TargetForRect(root, rect); |
| 583 | 563 |
| 584 // Ignore the padding set on the button. | 564 // Ignore the padding set on the button. |
| 585 gfx::Rect contents_bounds = GetContentsBounds(); | 565 gfx::Rect contents_bounds = GetContentsBounds(); |
| 586 contents_bounds.set_x(GetMirroredXForRect(contents_bounds)); | 566 contents_bounds.set_x(GetMirroredXForRect(contents_bounds)); |
| 587 | 567 |
| 588 #if defined(USE_AURA) | 568 #if defined(USE_AURA) |
| 589 // Include the padding in hit-test for touch events. | 569 // Include the padding in hit-test for touch events. |
| 590 // TODO(pkasting): It seems like touch events would generate rects rather | 570 // TODO(pkasting): It seems like touch events would generate rects rather |
| 591 // than points and thus use the TargetForRect() call above. If this is | 571 // than points and thus use the TargetForRect() call above. If this is |
| 592 // reached, it may be from someone calling GetEventHandlerForPoint() while a | 572 // reached, it may be from someone calling GetEventHandlerForPoint() while a |
| 593 // touch happens to be occurring. In such a case, maybe we don't want this | 573 // touch happens to be occurring. In such a case, maybe we don't want this |
| 594 // code to run? It's possible this block should be removed, or maybe this | 574 // code to run? It's possible this block should be removed, or maybe this |
| 595 // whole function deleted. | 575 // whole function deleted. |
| 596 if (aura::Env::GetInstance()->is_touch_down()) | 576 if (aura::Env::GetInstance()->is_touch_down()) |
| 597 contents_bounds = GetLocalBounds(); | 577 contents_bounds = GetLocalBounds(); |
| 598 #endif | 578 #endif |
| 599 | 579 |
| 600 return contents_bounds.Intersects(rect) ? this : parent(); | 580 return contents_bounds.Intersects(rect) ? this : parent(); |
| 601 } | 581 } |
| 602 | 582 |
| 603 // We need to define this so hit-testing won't include the border region. | 583 // We need to define this so hit-testing won't include the border region. |
| 604 bool GetHitTestMask(gfx::Path* mask) const override { | 584 bool GetHitTestMask(gfx::Path* mask) const override { |
| 605 DCHECK(mask); | 585 gfx::Rect button_bounds(GetContentsBounds()); |
| 606 mask->reset(); | 586 button_bounds.set_x(GetMirroredXForRect(button_bounds)); |
| 587 mask->addRect(gfx::RectToSkRect(button_bounds)); | |
| 607 | 588 |
| 608 // The parent tab may be partially occluded by another tab if we are | 589 // Clip against the tab mask in case the close button is party occluded due |
| 609 // in stacked tab mode, which means that the tab close button may also | 590 // to stacking tabs. |
| 610 // be partially occluded. Define the hit test mask of the tab close | 591 // TODO(pkasting): Does this actually improve event targeting over using the |
| 611 // button to be the intersection of the parent tab's visible bounds | 592 // full close button bounds? |
| 612 // and the bounds of the tab close button. | 593 gfx::Path clip; |
| 613 gfx::Rect tab_bounds(GetTabBounds()); | 594 tab_->GetHitTestMask(&clip); |
| 614 gfx::Rect button_bounds(GetTabCloseButtonBounds(tab_bounds)); | 595 gfx::Point origin; |
| 615 gfx::Rect intersection(gfx::IntersectRects(tab_bounds, button_bounds)); | 596 ConvertPointToTarget(tab_, this, &origin); |
| 616 | 597 clip.offset(SkIntToScalar(origin.x()), SkIntToScalar(origin.y())); |
| 617 if (!intersection.IsEmpty()) { | 598 Op(*mask, clip, kIntersect_SkPathOp, mask); |
| 618 mask->addRect(RectToSkRect(intersection)); | 599 return !mask->isEmpty(); |
| 619 return true; | |
| 620 } | |
| 621 | |
| 622 return false; | |
| 623 } | |
| 624 | |
| 625 bool DoesIntersectRect(const View* target, | |
| 626 const gfx::Rect& rect) const override { | |
| 627 CHECK_EQ(target, this); | |
| 628 | |
| 629 // If the request is not made in response to a gesture, use the | |
| 630 // default implementation. | |
| 631 if (views::UsePointBasedTargeting(rect)) | |
| 632 return MaskedTargeterDelegate::DoesIntersectRect(target, rect); | |
| 633 | |
| 634 // The hit test request is in response to a gesture. Return false if any | |
| 635 // part of the tab close button is hidden from the user. | |
| 636 // TODO(tdanderson): Consider always returning the intersection if the | |
| 637 // non-rectangular shape of the tab can be accounted for. | |
| 638 gfx::Rect tab_bounds(GetTabBounds()); | |
| 639 gfx::Rect button_bounds(GetTabCloseButtonBounds(tab_bounds)); | |
| 640 if (!tab_bounds.Contains(button_bounds)) | |
| 641 return false; | |
| 642 | |
| 643 return MaskedTargeterDelegate::DoesIntersectRect(target, rect); | |
| 644 } | 600 } |
| 645 | 601 |
| 646 Tab* tab_; | 602 Tab* tab_; |
| 647 | 603 |
| 648 DISALLOW_COPY_AND_ASSIGN(TabCloseButton); | 604 DISALLOW_COPY_AND_ASSIGN(TabCloseButton); |
| 649 }; | 605 }; |
| 650 | 606 |
| 651 //////////////////////////////////////////////////////////////////////////////// | 607 //////////////////////////////////////////////////////////////////////////////// |
| 652 // ThrobberView | 608 // ThrobberView |
| 653 // | 609 // |
| (...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1028 // Tab, views::MaskedTargeterDelegate overrides: | 984 // Tab, views::MaskedTargeterDelegate overrides: |
| 1029 | 985 |
| 1030 bool Tab::GetHitTestMask(gfx::Path* mask) const { | 986 bool Tab::GetHitTestMask(gfx::Path* mask) const { |
| 1031 const float scale = GetWidget()->GetCompositor()->device_scale_factor(); | 987 const float scale = GetWidget()->GetCompositor()->device_scale_factor(); |
| 1032 // When the window is maximized we don't want to shave off the edges or top | 988 // When the window is maximized we don't want to shave off the edges or top |
| 1033 // shadow of the tab, such that the user can click anywhere along the top | 989 // shadow of the tab, such that the user can click anywhere along the top |
| 1034 // edge of the screen to select a tab. Ditto for immersive fullscreen. | 990 // edge of the screen to select a tab. Ditto for immersive fullscreen. |
| 1035 const views::Widget* widget = GetWidget(); | 991 const views::Widget* widget = GetWidget(); |
| 1036 const bool extend_to_top = | 992 const bool extend_to_top = |
| 1037 widget && (widget->IsMaximized() || widget->IsFullscreen()); | 993 widget && (widget->IsMaximized() || widget->IsFullscreen()); |
| 1038 *mask = GetBorderPath(scale, true, extend_to_top, size()); | 994 auto border_getter = base::Bind(&GetBorderPath, scale, true, extend_to_top); |
|
sky
2016/08/04 23:42:08
tricky
| |
| 995 *mask = border_getter.Run(size()); | |
| 1039 | 996 |
| 1040 // It is possible for a portion of the tab to be occluded if tabs are | 997 // Clip the hittest mask if necessary for stacked tabs. This is primarily so |
| 1041 // stacked, so modify the hit test mask to only include the visible | 998 // we can use the clipped mask to clip the close button mask. |
| 1042 // region of the tab. | 999 // TODO(pkasting): Would it improve event targeting to do this clipping when |
| 1043 gfx::Rect clip; | 1000 // not stacking tabs as well? |
| 1044 controller_->ShouldPaintTab(this, &clip); | 1001 gfx::Path clip; |
| 1045 if (clip.size().GetArea()) { | 1002 controller_->ShouldPaintTab(this, border_getter, &clip); |
| 1046 SkRect intersection(mask->getBounds()); | 1003 Op(*mask, clip, kDifference_SkPathOp, mask); |
| 1047 mask->reset(); | 1004 return !mask->isEmpty(); |
| 1048 if (!intersection.intersect(RectToSkRect(clip))) | |
| 1049 return false; | |
| 1050 mask->addRect(intersection); | |
| 1051 } | |
| 1052 return true; | |
| 1053 } | 1005 } |
| 1054 | 1006 |
| 1055 //////////////////////////////////////////////////////////////////////////////// | 1007 //////////////////////////////////////////////////////////////////////////////// |
| 1056 // Tab, views::View overrides: | 1008 // Tab, views::View overrides: |
| 1057 | 1009 |
| 1058 void Tab::ViewHierarchyChanged(const ViewHierarchyChangedDetails& details) { | 1010 void Tab::ViewHierarchyChanged(const ViewHierarchyChangedDetails& details) { |
| 1059 // If this hierarchy changed has resulted in us being part of a widget | 1011 // If this hierarchy changed has resulted in us being part of a widget |
| 1060 // hierarchy for the first time, we can now get at the theme provider, and | 1012 // hierarchy for the first time, we can now get at the theme provider, and |
| 1061 // should recalculate the button color. | 1013 // should recalculate the button color. |
| 1062 if (details.is_add) | 1014 if (details.is_add) |
| 1063 OnButtonColorMaybeChanged(); | 1015 OnButtonColorMaybeChanged(); |
| 1064 } | 1016 } |
| 1065 | 1017 |
| 1066 void Tab::OnPaint(gfx::Canvas* canvas) { | 1018 void Tab::OnPaint(gfx::Canvas* canvas) { |
| 1067 // Don't paint if we're narrower than we can render correctly. (This should | 1019 // Don't paint if we're narrower than we can render correctly. (This should |
| 1068 // only happen during animations). | 1020 // only happen during animations). |
| 1069 if (width() < GetMinimumInactiveSize().width() && !data().pinned) | 1021 if (width() < GetMinimumInactiveSize().width() && !data().pinned) |
| 1070 return; | 1022 return; |
| 1071 | 1023 |
| 1072 gfx::Rect clip; | 1024 gfx::Path clip; |
| 1073 if (!controller_->ShouldPaintTab(this, &clip)) | 1025 if (!controller_->ShouldPaintTab( |
| 1026 this, base::Bind(&GetBorderPath, canvas->image_scale(), true, false), | |
| 1027 &clip)) | |
| 1074 return; | 1028 return; |
| 1075 if (!clip.IsEmpty()) { | |
| 1076 canvas->Save(); | |
| 1077 canvas->ClipRect(clip); | |
| 1078 } | |
| 1079 | 1029 |
| 1080 if (controller_->IsImmersiveStyle()) | 1030 if (controller_->IsImmersiveStyle()) |
| 1081 PaintImmersiveTab(canvas); | 1031 PaintImmersiveTab(canvas); |
| 1082 else | 1032 else |
| 1083 PaintTab(canvas); | 1033 PaintTab(canvas, clip); |
| 1084 | |
| 1085 if (!clip.IsEmpty()) | |
| 1086 canvas->Restore(); | |
| 1087 } | 1034 } |
| 1088 | 1035 |
| 1089 void Tab::Layout() { | 1036 void Tab::Layout() { |
| 1090 const gfx::Rect lb = GetContentsBounds(); | 1037 const gfx::Rect lb = GetContentsBounds(); |
| 1091 showing_icon_ = ShouldShowIcon(); | 1038 showing_icon_ = ShouldShowIcon(); |
| 1092 // See comments in IconCapacity(). | 1039 // See comments in IconCapacity(). |
| 1093 const int extra_padding = | 1040 const int extra_padding = |
| 1094 (controller_->ShouldHideCloseButtonForInactiveTabs() || | 1041 (controller_->ShouldHideCloseButtonForInactiveTabs() || |
| 1095 (IconCapacity() < 3)) ? 0 : kExtraLeftPaddingToBalanceCloseButtonPadding; | 1042 (IconCapacity() < 3)) ? 0 : kExtraLeftPaddingToBalanceCloseButtonPadding; |
| 1096 const int start = lb.x() + extra_padding; | 1043 const int start = lb.x() + extra_padding; |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1363 | 1310 |
| 1364 if (data().blocked == old.blocked) | 1311 if (data().blocked == old.blocked) |
| 1365 return; | 1312 return; |
| 1366 | 1313 |
| 1367 if (data().blocked) | 1314 if (data().blocked) |
| 1368 StartPulse(); | 1315 StartPulse(); |
| 1369 else | 1316 else |
| 1370 StopPulse(); | 1317 StopPulse(); |
| 1371 } | 1318 } |
| 1372 | 1319 |
| 1373 void Tab::PaintTab(gfx::Canvas* canvas) { | 1320 void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) { |
| 1374 const int kActiveTabFillId = IDR_THEME_TOOLBAR; | 1321 const int kActiveTabFillId = IDR_THEME_TOOLBAR; |
| 1375 const bool has_custom_image = | 1322 const bool has_custom_image = |
| 1376 GetThemeProvider()->HasCustomImage(kActiveTabFillId); | 1323 GetThemeProvider()->HasCustomImage(kActiveTabFillId); |
| 1377 const int y_offset = -GetYInsetForActiveTabBackground(); | 1324 const int y_offset = -GetYInsetForActiveTabBackground(); |
| 1378 if (IsActive()) { | 1325 if (IsActive()) { |
| 1379 PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId, | 1326 PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, |
| 1380 has_custom_image, y_offset); | 1327 has_custom_image, y_offset); |
| 1381 } else { | 1328 } else { |
| 1382 PaintInactiveTabBackground(canvas); | 1329 PaintInactiveTabBackground(canvas, clip); |
| 1383 | 1330 |
| 1384 const double throb_value = GetThrobValue(); | 1331 const double throb_value = GetThrobValue(); |
| 1385 if (throb_value > 0) { | 1332 if (throb_value > 0) { |
| 1386 canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff), | 1333 canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff), |
| 1387 GetLocalBounds()); | 1334 GetLocalBounds()); |
| 1388 PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId, | 1335 PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, |
| 1389 has_custom_image, y_offset); | 1336 has_custom_image, y_offset); |
| 1390 canvas->Restore(); | 1337 canvas->Restore(); |
| 1391 } | 1338 } |
| 1392 } | 1339 } |
| 1393 | 1340 |
| 1394 if (showing_icon_) | 1341 if (showing_icon_) |
| 1395 PaintIcon(canvas); | 1342 PaintIcon(canvas); |
| 1396 } | 1343 } |
| 1397 | 1344 |
| 1398 void Tab::PaintImmersiveTab(gfx::Canvas* canvas) { | 1345 void Tab::PaintImmersiveTab(gfx::Canvas* canvas) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1432 canvas->FillRect(right_eye_rect, kEyeColor); | 1379 canvas->FillRect(right_eye_rect, kEyeColor); |
| 1433 // The second part parts the remaining |eye_width| on the left. | 1380 // The second part parts the remaining |eye_width| on the left. |
| 1434 int left_eye_width = eye_offset + eye_width - bar_rect.width(); | 1381 int left_eye_width = eye_offset + eye_width - bar_rect.width(); |
| 1435 gfx::Rect left_eye_rect( | 1382 gfx::Rect left_eye_rect( |
| 1436 bar_rect.x(), 0, left_eye_width, kImmersiveBarHeight); | 1383 bar_rect.x(), 0, left_eye_width, kImmersiveBarHeight); |
| 1437 canvas->FillRect(left_eye_rect, kEyeColor); | 1384 canvas->FillRect(left_eye_rect, kEyeColor); |
| 1438 } | 1385 } |
| 1439 } | 1386 } |
| 1440 } | 1387 } |
| 1441 | 1388 |
| 1442 void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) { | 1389 void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas, |
| 1390 const gfx::Path& clip) { | |
| 1443 bool has_custom_image; | 1391 bool has_custom_image; |
| 1444 int fill_id = controller_->GetBackgroundResourceId(&has_custom_image); | 1392 int fill_id = controller_->GetBackgroundResourceId(&has_custom_image); |
| 1445 | 1393 |
| 1446 // If the theme is providing a custom background image, then its top edge | 1394 // If the theme is providing a custom background image, then its top edge |
| 1447 // should be at the top of the tab. Otherwise, we assume that the background | 1395 // should be at the top of the tab. Otherwise, we assume that the background |
| 1448 // image is a composited foreground + frame image. Note that if the theme is | 1396 // image is a composited foreground + frame image. Note that if the theme is |
| 1449 // only providing a custom frame image, |has_custom_image| will be true, but | 1397 // only providing a custom frame image, |has_custom_image| will be true, but |
| 1450 // we should use the |background_offset_| here. | 1398 // we should use the |background_offset_| here. |
| 1451 const ui::ThemeProvider* tp = GetThemeProvider(); | 1399 const ui::ThemeProvider* tp = GetThemeProvider(); |
| 1452 const int y_offset = tp->HasCustomImage(fill_id) ? | 1400 const int y_offset = tp->HasCustomImage(fill_id) ? |
| 1453 -GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT) : background_offset_.y(); | 1401 -GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT) : background_offset_.y(); |
| 1454 | 1402 |
| 1455 // We only cache the image when it's the default image and we're not hovered, | 1403 // We only cache the image when it's the default image and we're not hovered, |
| 1456 // to avoid caching a background image that isn't the same for all tabs. | 1404 // to avoid caching a background image that isn't the same for all tabs. |
| 1457 if (has_custom_image || hover_controller_.ShouldDraw()) { | 1405 if (has_custom_image || hover_controller_.ShouldDraw()) { |
| 1458 PaintTabBackgroundUsingFillId(canvas, false, fill_id, has_custom_image, | 1406 PaintTabBackgroundUsingFillId(canvas, canvas, false, fill_id, |
| 1459 y_offset); | 1407 has_custom_image, y_offset); |
| 1460 return; | 1408 return; |
| 1461 } | 1409 } |
| 1462 | 1410 |
| 1411 // For efficiency, we don't use separate fill and stroke images unless we | |
| 1412 // really need to clip the stroke and not the fill (for stacked tabs). This | |
| 1413 // saves memory and avoids an extra image draw at the cost of recalculating | |
| 1414 // the images when MaySetClip() toggles. | |
| 1415 const bool use_fill_and_stroke_images = | |
| 1416 controller_->MaySetClip() && | |
| 1417 ui::MaterialDesignController::IsModeMaterial(); | |
| 1418 | |
| 1463 const ImageCacheEntryMetadata metadata( | 1419 const ImageCacheEntryMetadata metadata( |
| 1464 fill_id, tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB), | 1420 fill_id, tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB), |
| 1465 controller_->GetToolbarTopSeparatorColor(), | 1421 controller_->GetToolbarTopSeparatorColor(), use_fill_and_stroke_images, |
| 1466 ui::GetSupportedScaleFactor(canvas->image_scale()), size()); | 1422 ui::GetSupportedScaleFactor(canvas->image_scale()), size()); |
| 1467 auto it = std::find_if( | 1423 auto it = std::find_if( |
| 1468 g_image_cache->begin(), g_image_cache->end(), | 1424 g_image_cache->begin(), g_image_cache->end(), |
| 1469 [&metadata](const ImageCacheEntry& e) { return e.metadata == metadata; }); | 1425 [&metadata](const ImageCacheEntry& e) { return e.metadata == metadata; }); |
| 1470 if (it == g_image_cache->end()) { | 1426 if (it == g_image_cache->end()) { |
| 1471 gfx::Canvas tmp_canvas(size(), canvas->image_scale(), false); | 1427 gfx::Canvas tmp_canvas(size(), canvas->image_scale(), false); |
| 1472 PaintTabBackgroundUsingFillId(&tmp_canvas, false, fill_id, false, y_offset); | 1428 if (use_fill_and_stroke_images) { |
| 1473 g_image_cache->emplace_front(metadata, | 1429 gfx::Canvas tmp_fill_canvas(size(), canvas->image_scale(), false); |
| 1474 gfx::ImageSkia(tmp_canvas.ExtractImageRep())); | 1430 PaintTabBackgroundUsingFillId(&tmp_fill_canvas, &tmp_canvas, false, |
| 1431 fill_id, false, y_offset); | |
| 1432 g_image_cache->emplace_front( | |
| 1433 metadata, gfx::ImageSkia(tmp_fill_canvas.ExtractImageRep()), | |
| 1434 gfx::ImageSkia(tmp_canvas.ExtractImageRep())); | |
| 1435 } else { | |
| 1436 PaintTabBackgroundUsingFillId(&tmp_canvas, &tmp_canvas, false, fill_id, | |
| 1437 false, y_offset); | |
| 1438 g_image_cache->emplace_front( | |
| 1439 metadata, gfx::ImageSkia(), | |
| 1440 gfx::ImageSkia(tmp_canvas.ExtractImageRep())); | |
| 1441 } | |
| 1475 if (g_image_cache->size() > kMaxImageCacheSize) | 1442 if (g_image_cache->size() > kMaxImageCacheSize) |
| 1476 g_image_cache->pop_back(); | 1443 g_image_cache->pop_back(); |
| 1477 it = g_image_cache->begin(); | 1444 it = g_image_cache->begin(); |
| 1478 } | 1445 } |
| 1479 canvas->DrawImageInt(it->image, 0, 0); | 1446 |
| 1447 gfx::ScopedCanvas scoped_canvas( | |
| 1448 use_fill_and_stroke_images ? canvas : nullptr); | |
| 1449 if (use_fill_and_stroke_images) { | |
| 1450 canvas->DrawImageInt(it->fill_image, 0, 0); | |
| 1451 canvas->sk_canvas()->clipPath(clip, SkRegion::kDifference_Op, true); | |
| 1452 } | |
| 1453 canvas->DrawImageInt(it->stroke_image, 0, 0); | |
| 1480 } | 1454 } |
| 1481 | 1455 |
| 1482 void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* canvas, | 1456 void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* fill_canvas, |
| 1457 gfx::Canvas* stroke_canvas, | |
| 1483 bool is_active, | 1458 bool is_active, |
| 1484 int fill_id, | 1459 int fill_id, |
| 1485 bool has_custom_image, | 1460 bool has_custom_image, |
| 1486 int y_offset) { | 1461 int y_offset) { |
| 1487 const ui::ThemeProvider* tp = GetThemeProvider(); | 1462 const ui::ThemeProvider* tp = GetThemeProvider(); |
| 1488 const SkColor toolbar_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR); | 1463 const SkColor toolbar_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR); |
| 1489 gfx::ImageSkia* fill_image = tp->GetImageSkiaNamed(fill_id); | 1464 gfx::ImageSkia* fill_image = tp->GetImageSkiaNamed(fill_id); |
| 1490 // The tab image needs to be lined up with the background image | 1465 // The tab image needs to be lined up with the background image |
| 1491 // so that it feels partially transparent. These offsets represent the tab | 1466 // so that it feels partially transparent. These offsets represent the tab |
| 1492 // position within the frame background image. | 1467 // position within the frame background image. |
| 1493 const int x_offset = GetMirroredX() + background_offset_.x(); | 1468 const int x_offset = GetMirroredX() + background_offset_.x(); |
| 1494 | 1469 |
| 1495 const SkScalar kMinHoverRadius = 16; | 1470 const SkScalar kMinHoverRadius = 16; |
| 1496 const SkScalar radius = | 1471 const SkScalar radius = |
| 1497 std::max(SkFloatToScalar(width() / 4.f), kMinHoverRadius); | 1472 std::max(SkFloatToScalar(width() / 4.f), kMinHoverRadius); |
| 1498 const bool draw_hover = !is_active && hover_controller_.ShouldDraw(); | 1473 const bool draw_hover = !is_active && hover_controller_.ShouldDraw(); |
| 1499 SkPoint hover_location(gfx::PointToSkPoint(hover_controller_.location())); | 1474 SkPoint hover_location(gfx::PointToSkPoint(hover_controller_.location())); |
| 1500 const SkColor hover_color = | 1475 const SkColor hover_color = |
| 1501 SkColorSetA(toolbar_color, hover_controller_.GetAlpha()); | 1476 SkColorSetA(toolbar_color, hover_controller_.GetAlpha()); |
| 1502 | 1477 |
| 1503 if (ui::MaterialDesignController::IsModeMaterial()) { | 1478 if (ui::MaterialDesignController::IsModeMaterial()) { |
| 1504 gfx::ScopedCanvas scoped_canvas(canvas); | 1479 gfx::Path fill; |
| 1505 const float scale = canvas->UndoDeviceScaleFactor(); | 1480 SkPaint paint; |
| 1481 paint.setAntiAlias(true); | |
| 1506 | 1482 |
| 1507 // Draw the fill. | 1483 // Draw the fill. |
| 1508 gfx::Path fill = GetFillPath(scale, size()); | |
| 1509 SkPaint paint; | |
| 1510 paint.setAntiAlias(true); | |
| 1511 { | 1484 { |
| 1512 gfx::ScopedCanvas clip_scoper(canvas); | 1485 gfx::ScopedCanvas scoped_fill_canvas(fill_canvas); |
| 1513 canvas->ClipPath(fill, true); | 1486 const float scale = fill_canvas->UndoDeviceScaleFactor(); |
| 1514 if (has_custom_image) { | 1487 |
| 1515 gfx::ScopedCanvas scale_scoper(canvas); | 1488 fill = GetFillPath(scale, size()); |
| 1516 canvas->sk_canvas()->scale(scale, scale); | 1489 { |
| 1517 canvas->TileImageInt(*fill_image, x_offset, y_offset, 0, 0, width(), | 1490 gfx::ScopedCanvas clip_scoper(fill_canvas); |
| 1518 height()); | 1491 fill_canvas->ClipPath(fill, true); |
| 1519 } else { | 1492 if (has_custom_image) { |
| 1520 paint.setColor( | 1493 gfx::ScopedCanvas scale_scoper(fill_canvas); |
| 1521 is_active ? toolbar_color | 1494 fill_canvas->sk_canvas()->scale(scale, scale); |
| 1522 : tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB)); | 1495 fill_canvas->TileImageInt(*fill_image, x_offset, y_offset, 0, 0, |
| 1523 canvas->DrawRect(gfx::ScaleToEnclosingRect(GetLocalBounds(), scale), | 1496 width(), height()); |
| 1524 paint); | 1497 } else { |
| 1525 } | 1498 paint.setColor( |
| 1526 if (draw_hover) { | 1499 is_active ? toolbar_color |
| 1527 hover_location.scale(SkFloatToScalar(scale)); | 1500 : tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB)); |
| 1528 DrawHighlight(canvas, hover_location, radius * scale, hover_color); | 1501 fill_canvas->DrawRect( |
| 1502 gfx::ScaleToEnclosingRect(GetLocalBounds(), scale), paint); | |
| 1503 } | |
| 1504 if (draw_hover) { | |
| 1505 hover_location.scale(SkFloatToScalar(scale)); | |
| 1506 DrawHighlight(fill_canvas, hover_location, radius * scale, | |
| 1507 hover_color); | |
| 1508 } | |
| 1529 } | 1509 } |
| 1530 } | 1510 } |
| 1531 | 1511 |
| 1532 // Draw the stroke. | 1512 // Draw the stroke. |
| 1533 gfx::Path stroke = GetBorderPath(scale, false, false, size()); | 1513 { |
| 1534 Op(stroke, fill, kDifference_SkPathOp, &stroke); | 1514 gfx::ScopedCanvas scoped_stroke_canvas(stroke_canvas); |
| 1535 if (!is_active) { | 1515 const float scale = stroke_canvas->UndoDeviceScaleFactor(); |
| 1536 // Clip out the bottom line; this will be drawn for us by | 1516 |
| 1537 // TabStrip::PaintChildren(). | 1517 gfx::Path stroke = GetBorderPath(scale, false, false, size()); |
| 1538 canvas->ClipRect(gfx::RectF(width() * scale, height() * scale - 1)); | 1518 Op(stroke, fill, kDifference_SkPathOp, &stroke); |
| 1519 if (!is_active) { | |
| 1520 // Clip out the bottom line; this will be drawn for us by | |
| 1521 // TabStrip::PaintChildren(). | |
| 1522 stroke_canvas->ClipRect(gfx::RectF(width() * scale, | |
| 1523 height() * scale - 1)); | |
| 1524 } | |
| 1525 paint.setColor(controller_->GetToolbarTopSeparatorColor()); | |
| 1526 stroke_canvas->DrawPath(stroke, paint); | |
| 1539 } | 1527 } |
| 1540 paint.setColor(controller_->GetToolbarTopSeparatorColor()); | |
| 1541 canvas->DrawPath(stroke, paint); | |
| 1542 } else { | 1528 } else { |
| 1529 gfx::Canvas* canvas = stroke_canvas; | |
| 1543 if (draw_hover) { | 1530 if (draw_hover) { |
| 1544 // Draw everything to a temporary canvas so we can extract an image for | 1531 // Draw everything to a temporary canvas so we can extract an image for |
| 1545 // use in masking the hover glow. | 1532 // use in masking the hover glow. |
| 1546 gfx::Canvas background_canvas(size(), canvas->image_scale(), false); | 1533 gfx::Canvas background_canvas(size(), canvas->image_scale(), false); |
| 1547 PaintTabFill(&background_canvas, fill_image, x_offset, y_offset, size(), | 1534 PaintTabFill(&background_canvas, fill_image, x_offset, y_offset, size(), |
| 1548 is_active); | 1535 is_active); |
| 1549 gfx::ImageSkia background_image(background_canvas.ExtractImageRep()); | 1536 gfx::ImageSkia background_image(background_canvas.ExtractImageRep()); |
| 1550 canvas->DrawImageInt(background_image, 0, 0); | 1537 canvas->DrawImageInt(background_image, 0, 0); |
| 1551 | 1538 |
| 1552 gfx::Canvas hover_canvas(size(), canvas->image_scale(), false); | 1539 gfx::Canvas hover_canvas(size(), canvas->image_scale(), false); |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1809 gfx::Rect Tab::GetImmersiveBarRect() const { | 1796 gfx::Rect Tab::GetImmersiveBarRect() const { |
| 1810 // The main bar is as wide as the normal tab's horizontal top line. | 1797 // The main bar is as wide as the normal tab's horizontal top line. |
| 1811 // This top line of the tab extends a few pixels left and right of the | 1798 // This top line of the tab extends a few pixels left and right of the |
| 1812 // center image due to pixels in the rounded corner images. | 1799 // center image due to pixels in the rounded corner images. |
| 1813 const int kBarPadding = 1; | 1800 const int kBarPadding = 1; |
| 1814 int main_bar_left = g_active_images.l_width - kBarPadding; | 1801 int main_bar_left = g_active_images.l_width - kBarPadding; |
| 1815 int main_bar_right = width() - g_active_images.r_width + kBarPadding; | 1802 int main_bar_right = width() - g_active_images.r_width + kBarPadding; |
| 1816 return gfx::Rect( | 1803 return gfx::Rect( |
| 1817 main_bar_left, 0, main_bar_right - main_bar_left, kImmersiveBarHeight); | 1804 main_bar_left, 0, main_bar_right - main_bar_left, kImmersiveBarHeight); |
| 1818 } | 1805 } |
| OLD | NEW |