Skip to content

Commit

Permalink
Add shadows to tabs
Browse files Browse the repository at this point in the history
Adds tab painting function for shadows.

In order to paint the tab's (top) shadow above the tab's (previous) bounds rectangle, we must extend the tab (and tabstrip) higher, to the top of the window (usually 8px of space). This is because the Views framework does not allow painting outside a View's bounds.

A hacky alternative would be to pass the PaintInfo from the BrowserView through the TabStrip child to the Tab descendants, so that a canvas can be created that can span the larger window rectangle. Aside from that strategy not done anywhere else in Chromium, it could cause issues if the tabs end up on a different paint layer, as well as paint invalidation and caching issues that would need to be solved.

Close brave/brave-browser#788
  • Loading branch information
petemill committed Sep 27, 2018
1 parent 83fc646 commit ab58135
Show file tree
Hide file tree
Showing 13 changed files with 311 additions and 13 deletions.
4 changes: 4 additions & 0 deletions browser/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ source_set("ui") {
"views/brave_actions/brave_actions_container.h",
"views/frame/brave_browser_view.cc",
"views/frame/brave_browser_view.h",
"views/frame/brave_browser_view_layout.cc",
"views/frame/brave_browser_view_layout.h",
"views/importer/brave_import_lock_dialog_view.cc",
"views/importer/brave_import_lock_dialog_view.h",
"views/location_bar/brave_location_bar_view.cc",
Expand All @@ -50,6 +52,8 @@ source_set("ui") {
"views/tabs/brave_new_tab_button.h",
"views/tabs/brave_tab.cc",
"views/tabs/brave_tab.h",
"views/tabs/brave_tab_strip.cc",
"views/tabs/brave_tab_strip.h",
"views/toolbar/bookmark_button.cc",
"views/toolbar/bookmark_button.h",
"views/toolbar/brave_toolbar_view.cc",
Expand Down
19 changes: 19 additions & 0 deletions browser/ui/views/frame/brave_browser_view_layout.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "brave/browser/ui/views/frame/brave_browser_view_layout.h"
#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"

void BraveBrowserViewLayout::Layout(views::View* host) {
BrowserViewLayout::Layout(host);
// Extend the tab strip to start at the very top
// so that it can draw shadows in the area which is pretending to
// be non-client (i.e. draggable)
if (tab_strip_->visible()) {
gfx::Rect tabstrip_bounds(tab_strip_->bounds());
// set initial position to top
tabstrip_bounds.set_y(tabstrip_bounds.y() -
BrowserNonClientFrameView::kMinimumDragHeight);
// increase height so that bottom is in same position
tabstrip_bounds.set_height(tabstrip_bounds.height() +
BrowserNonClientFrameView::kMinimumDragHeight);
tab_strip_->SetBoundsRect(tabstrip_bounds);
}
}
20 changes: 20 additions & 0 deletions browser/ui/views/frame/brave_browser_view_layout.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef BRAVE_BROWSER_UI_VIEWS_FRAME_BRAVE_BROWSER_VIEW_LAYOUT_H_
#define BRAVE_BROWSER_UI_VIEWS_FRAME_BRAVE_BROWSER_VIEW_LAYOUT_H_

#include "chrome/browser/ui/views/frame/browser_view_layout.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"

class BraveBrowserViewLayout : public BrowserViewLayout {
public:
using BrowserViewLayout::BrowserViewLayout;
// views::LayoutManager overrides:
void Layout(views::View* host) override;
private:
DISALLOW_COPY_AND_ASSIGN(BraveBrowserViewLayout);
};

#endif
68 changes: 67 additions & 1 deletion browser/ui/views/tabs/brave_tab.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,32 @@

#include "brave/browser/ui/views/tabs/brave_tab.h"

#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
#include "chrome/browser/ui/views/tabs/tab_controller.h"
#include "ui/gfx/animation/animation_container.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/skia_paint_util.h"

using namespace chrome_browser_ui_views_tabs_tab_cc;

BraveTab::BraveTab(TabController* controller, gfx::AnimationContainer* container)
: Tab::Tab(controller, container) {
// Reserve more space than parent class since
// Brave tab strip starts at the top, to allow for more shadow
SetBorder(views::CreateEmptyBorder(GetContentsInsets()));
}

gfx::Insets BraveTab::GetContentsInsets() const {
gfx::Insets tab_contents_insets(Tab::GetContentsInsets());
// inset top to reserve space for shadow / drag area
return tab_contents_insets + gfx::Insets(
BrowserNonClientFrameView::kMinimumDragHeight,
0,
0,
0);
}

// Same as Chomium Tab implementation except separators are
// achored to bottom (instead of floating in middle) and rounded ends
void BraveTab::PaintSeparators(gfx::Canvas* canvas) {
Expand All @@ -19,7 +39,6 @@ void BraveTab::PaintSeparators(gfx::Canvas* canvas) {

gfx::ScopedCanvas scoped_canvas(canvas);
const float scale = canvas->UndoDeviceScaleFactor();

const gfx::RectF aligned_bounds =
ScaleAndAlignBounds(bounds(), scale, GetStrokeThickness());
const int corner_radius = GetCornerRadius();
Expand Down Expand Up @@ -55,3 +74,50 @@ void BraveTab::PaintSeparators(gfx::Canvas* canvas) {
canvas->DrawRoundRect(
trailing_separator_bounds, scaled_separator_radius, flags);
}

void BraveTab::PaintTabShadows(gfx::Canvas* canvas, const gfx::Path& fill_path) {
const bool active = IsActive();
const bool hover = !active && hover_controller_.ShouldDraw();
if (active || hover) {
gfx::ScopedCanvas scoped_canvas(canvas);
const float scale = canvas->UndoDeviceScaleFactor();
canvas->sk_canvas()->clipPath(fill_path, SkClipOp::kDifference, true);
std::vector<gfx::ShadowValue> shadows;
double alpha = 100;
double blur = 6;
if (hover) {
double animation_value = hover_controller_.GetAnimationValue();
alpha = animation_value * (alpha * 0.66);
blur = animation_value * blur;
}
gfx::ShadowValue shadow(
gfx::Vector2d(0, 0), blur * scale,
SkColorSetARGB(alpha, 0x00, 0x00, 0x00));
shadows.push_back(shadow.Scale(scale));

cc::PaintFlags shadow_flags;
shadow_flags.setLooper(gfx::CreateShadowDrawLooper(shadows));
shadow_flags.setColor(SK_ColorTRANSPARENT);
canvas->DrawPath(fill_path, shadow_flags);
}
}

void BraveTab::PaintTabBackgroundFill(gfx::Canvas* canvas,
const gfx::Path& fill_path,
bool active,
bool paint_hover_effect,
SkColor active_color,
SkColor inactive_color,
int fill_id,
int y_inset) {
// Insert shadow painting
PaintTabShadows(canvas, fill_path);
Tab::PaintTabBackgroundFill(canvas, fill_path, active, paint_hover_effect,
active_color, inactive_color, fill_id, y_inset);
}

void BraveTab::OnPaint(gfx::Canvas* canvas) {
// apply inset but allow painting outside bounds, for shadow
canvas->Translate(gfx::Vector2d(0, BrowserNonClientFrameView::kMinimumDragHeight));
Tab::OnPaint(canvas);
}
34 changes: 29 additions & 5 deletions browser/ui/views/tabs/brave_tab.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,46 @@

#include "chrome/browser/ui/views/tabs/tab.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/insets.h"

namespace chrome_browser_ui_views_tabs_tab_cc {
class TabController;

const gfx::RectF ScaleAndAlignBounds(const gfx::Rect& bounds,
float scale,
float stroke_thickness);
namespace gfx {
class AnimationContainer;
}

namespace chrome_browser_ui_views_tabs_tab_cc {
// Define methods that we want exposed from
// parent module's anonymous namespace
const gfx::RectF ScaleAndAlignBounds(const gfx::Rect& bounds,
float scale,
float stroke_thickness);
}


// Purposes for this child class:
// - Paint Brave-style Separators
// - Paint Shadows
// - Allow Tab to be inset more on top, so that it can draw shadows in
// window area which is acting as non-client
class BraveTab : public Tab {
public:
using Tab::Tab;
BraveTab(TabController* controller, gfx::AnimationContainer* container);
gfx::Insets GetContentsInsets() const override;
void OnPaint(gfx::Canvas* canvas) override;
private:
// Paints the separator lines on the left and right edge of the tab if in
// material refresh mode.
void PaintSeparators(gfx::Canvas* canvas) override;
void PaintTabShadows(gfx::Canvas* canvas, const gfx::Path& fill_path);
void PaintTabBackgroundFill(gfx::Canvas* canvas,
const gfx::Path& fill_path,
bool active,
bool paint_hover_effect,
SkColor active_color,
SkColor inactive_color,
int fill_id,
int y_inset) override;
DISALLOW_COPY_AND_ASSIGN(BraveTab);
};

Expand Down
24 changes: 24 additions & 0 deletions browser/ui/views/tabs/brave_tab_strip.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "brave/browser/ui/views/tabs/brave_tab_strip.h"

#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
#include "ui/gfx/canvas.h"

void BraveTabStrip::OnPaint(gfx::Canvas* canvas) {
// BraveTabStrip extends to top: 0 of window, TabStrip does not,
// so bump all TabStrip painting down a bit whilst still reserving
// the space for tab shadows.
canvas->Translate(gfx::Vector2d(0, BrowserNonClientFrameView::kMinimumDragHeight));
TabStrip::OnPaint(canvas);
}

void BraveTabStrip::GenerateIdealBounds() {
TabStrip::GenerateIdealBounds();
new_tab_button_bounds_.set_y(BrowserNonClientFrameView::kMinimumDragHeight);
}

bool BraveTabStrip::IsPositionInWindowCaption(const gfx::Point& point) {
// ignore shadow area
return point.y() < BrowserNonClientFrameView::kMinimumDragHeight
? true
: TabStrip::IsPositionInWindowCaption(point);
}
21 changes: 21 additions & 0 deletions browser/ui/views/tabs/brave_tab_strip.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef BRAVE_BROWSER_UI_VIEWS_TABS_BRAVE_TAB_STRIP_H_
#define BRAVE_BROWSER_UI_VIEWS_TABS_BRAVE_TAB_STRIP_H_

#include "chrome/browser/ui/views/tabs/tab_strip.h"

class BraveTabStrip : public TabStrip {
public:
using TabStrip::TabStrip;
bool IsPositionInWindowCaption(const gfx::Point& point) override;
// views::View
void OnPaint(gfx::Canvas* canvas) override;
private:
void GenerateIdealBounds() override;
DISALLOW_COPY_AND_ASSIGN(BraveTabStrip);
};

#endif
40 changes: 40 additions & 0 deletions patches/chrome-browser-ui-views-frame-browser_view.cc.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 64fc254f05e6496de9d724a030d42aa2f4e0a804..8553bcded9b9f73da3dec1e51622d0340391e663 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -77,7 +77,7 @@
#include "chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h"
#include "chrome/browser/ui/views/find_bar_host.h"
#include "chrome/browser/ui/views/frame/app_menu_button.h"
-#include "chrome/browser/ui/views/frame/browser_view_layout.h"
+#include "brave/browser/ui/views/frame/brave_browser_view_layout.h"
#include "chrome/browser/ui/views/frame/browser_view_layout_delegate.h"
#include "chrome/browser/ui/views/frame/contents_layout_manager.h"
#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
@@ -96,7 +96,7 @@
#include "chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.h"
#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
#include "chrome/browser/ui/views/tabs/tab.h"
-#include "chrome/browser/ui/views/tabs/tab_strip.h"
+#include "brave/browser/ui/views/tabs/brave_tab_strip.h"
#include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
#include "chrome/browser/ui/views/toolbar/reload_button.h"
#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
@@ -2345,7 +2345,7 @@ void BrowserView::InitViews() {
BrowserTabStripController* tabstrip_controller =
new BrowserTabStripController(browser_->tab_strip_model(), this);
tabstrip_ =
- new TabStrip(std::unique_ptr<TabStripController>(tabstrip_controller));
+ new BraveTabStrip(std::unique_ptr<TabStripController>(tabstrip_controller));
top_container_->AddChildView(tabstrip_); // Takes ownership.
tabstrip_controller->InitFromModel(tabstrip_);

@@ -2371,7 +2371,7 @@ void BrowserView::InitViews() {
immersive_mode_controller_->Init(this);
immersive_mode_controller_->AddObserver(this);

- auto browser_view_layout = std::make_unique<BrowserViewLayout>();
+ auto browser_view_layout = std::make_unique<BraveBrowserViewLayout>();
browser_view_layout->Init(new BrowserViewLayoutDelegateImpl(this),
browser(),
this,
12 changes: 12 additions & 0 deletions patches/chrome-browser-ui-views-frame-browser_view_layout.h.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.h b/chrome/browser/ui/views/frame/browser_view_layout.h
index 4de4cfe8d18f3d00bb5267b2fac52050d4779d20..5b2989f52c825f36b5feed15f254f6653615dd40 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.h
+++ b/chrome/browser/ui/views/frame/browser_view_layout.h
@@ -37,6 +37,7 @@ class WebContentsModalDialogHost;
// The layout manager used in chrome browser.
class BrowserViewLayout : public views::LayoutManager {
public:
+ friend class BraveBrowserViewLayout;
BrowserViewLayout();
~BrowserViewLayout() override;

17 changes: 13 additions & 4 deletions patches/chrome-browser-ui-views-tabs-tab.cc.patch
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 0dcdb4bebb1286e493d0b85eac586954353e10d1..5fe6861d927b1eb38336b073e8c8c50f8094c620 100644
index 0dcdb4bebb1286e493d0b85eac586954353e10d1..e95283d59bb88ece6e6a3c33b8cf9863c7dfe741 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -76,7 +76,7 @@
Expand All @@ -20,7 +20,16 @@ index 0dcdb4bebb1286e493d0b85eac586954353e10d1..5fe6861d927b1eb38336b073e8c8c50f
constexpr int kTabSeparatorTouchHeight = 24;

// Helper functions ------------------------------------------------------------
@@ -230,7 +230,7 @@ gfx::Path GetRefreshInteriorPath(float scale,
@@ -163,6 +163,8 @@ const gfx::RectF ScaleAndAlignBounds(const gfx::Rect& bounds,
// of one tab's layout bounds is the same as the left edge of the next tab's;
// this way the two tabs' separators will be drawn at the same coordinate.
gfx::RectF aligned_bounds(bounds);
+ // Brave: make sure painting calcs don't consider shadow / window drag area
+ aligned_bounds.set_height(aligned_bounds.height() - BrowserNonClientFrameView::kMinimumDragHeight);
const int corner_radius = Tab::GetCornerRadius();
// Note: This intentionally doesn't subtract TABSTRIP_TOOLBAR_OVERLAP from the
// bottom inset, because we want to pixel-align the bottom of the stroke, not
@@ -230,7 +232,7 @@ gfx::Path GetRefreshInteriorPath(float scale,
bottom_offset *= scale;

const float radius = GetTopCornerRadiusForWidth(bounds.width()) * scale;
Expand All @@ -29,7 +38,7 @@ index 0dcdb4bebb1286e493d0b85eac586954353e10d1..5fe6861d927b1eb38336b073e8c8c50f
const float top_radius = std::max(radius - stroke_thickness, 0.f);

// Compute |extension| as the width outside the separators. This is a fixed
@@ -366,8 +366,8 @@ gfx::Path GetRefreshBorderPath(const gfx::Rect& bounds,
@@ -366,8 +368,8 @@ gfx::Path GetRefreshBorderPath(const gfx::Rect& bounds,
bottom_offset *= scale;

const float top_radius = GetTopCornerRadiusForWidth(bounds.width()) * scale;
Expand All @@ -40,7 +49,7 @@ index 0dcdb4bebb1286e493d0b85eac586954353e10d1..5fe6861d927b1eb38336b073e8c8c50f

// See comments in GetRefreshInteriorPath().
const float extension = Tab::GetCornerRadius() * scale;
@@ -491,6 +491,7 @@ gfx::Path GetBorderPath(float scale,
@@ -491,6 +493,7 @@ gfx::Path GetBorderPath(float scale,
}

} // namespace
Expand Down
20 changes: 19 additions & 1 deletion patches/chrome-browser-ui-views-tabs-tab.h.patch
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 5be5d08990a6133511b9cb16ee660ce17cc907e8..6b55d3e9f733c2fe99ff6cf460def4d12f87b60d 100644
index 5be5d08990a6133511b9cb16ee660ce17cc907e8..6909b3d2936b4c9fef8f23ac05d5a7234a722624 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -56,7 +56,7 @@ class Tab : public gfx::AnimationDelegate,
Expand All @@ -11,6 +11,15 @@ index 5be5d08990a6133511b9cb16ee660ce17cc907e8..6b55d3e9f733c2fe99ff6cf460def4d1

// When the content's width of the tab shrinks to below this size we should
// hide the close button on inactive tabs. Any smaller and they're too easy
@@ -188,7 +188,7 @@ class Tab : public gfx::AnimationDelegate,
int GetWidthOfLargestSelectableRegion() const;

// Returns the insets to use for laying out tab contents.
- gfx::Insets GetContentsInsets() const;
+ virtual gfx::Insets GetContentsInsets() const;

// Returns the horizontal insets to use for laying out tab contents.
static gfx::Insets GetContentsHorizontalInsets();
@@ -235,6 +235,7 @@ class Tab : public gfx::AnimationDelegate,
friend class AlertIndicatorButtonTest;
friend class TabTest;
Expand All @@ -19,6 +28,15 @@ index 5be5d08990a6133511b9cb16ee660ce17cc907e8..6b55d3e9f733c2fe99ff6cf460def4d1
FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabCloseButtonVisibilityWhenStacked);
FRIEND_TEST_ALL_PREFIXES(TabStripTest,
TabCloseButtonVisibilityWhenNotStacked);
@@ -268,7 +269,7 @@ class Tab : public gfx::AnimationDelegate,
const gfx::Path* clip);

// Helper methods for PaintTabBackground.
- void PaintTabBackgroundFill(gfx::Canvas* canvas,
+ virtual void PaintTabBackgroundFill(gfx::Canvas* canvas,
const gfx::Path& fill_path,
bool active,
bool hover,
@@ -284,7 +285,7 @@ class Tab : public gfx::AnimationDelegate,

// Paints the separator lines on the left and right edge of the tab if in
Expand Down
Loading

0 comments on commit ab58135

Please sign in to comment.