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

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

Issue 2210033002: Proper rendering of stacked tabs for MD. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix compile Created 4 years, 4 months 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.h ('k') | chrome/browser/ui/views/tabs/tab_controller.h » ('j') | 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.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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/tabs/tab.h ('k') | chrome/browser/ui/views/tabs/tab_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698