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

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: Resync 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 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
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 }
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