From 798830e7cc81ab1fcc48794fbe35ae5e259d9b06 Mon Sep 17 00:00:00 2001 From: win32ss Date: Tue, 3 Sep 2024 00:44:20 -0400 Subject: [PATCH] CR2023 also involved removing the new tab button class and replacing it with a less-capable class covering all three tab-related buttons (new tab, tab search and tab organization) which needs major changes to render a non-rectangular shape. The trapezoidal tab has also been shortened as its canvas has shrunk. --- chrome/browser/ui/tabs/tab_style.cc | 10 +- .../ui/views/frame/tab_strip_region_view.cc | 22 +- .../browser/ui/views/tabs/new_tab_button.cc | 6 +- .../browser/ui/views/tabs/tab_style_views.cc | 301 +++++++++++++----- 4 files changed, 255 insertions(+), 84 deletions(-) diff --git a/chrome/browser/ui/tabs/tab_style.cc b/chrome/browser/ui/tabs/tab_style.cc index c9ff331e372f07..c65e1afe414094 100644 --- a/chrome/browser/ui/tabs/tab_style.cc +++ b/chrome/browser/ui/tabs/tab_style.cc @@ -131,11 +131,13 @@ int GM2TabStyle::GetDragHandleExtension(int height) const { } gfx::Size GM2TabStyle::GetSeparatorSize() const { - if(base::CommandLine::ForCurrentProcess()->HasSwitch("compact-ui")) - return gfx::Size(kGM2SeparatorThickness, + if (base::FeatureList::IsEnabled(features::kSupermiumCustomTabs)) + return gfx::Size(0, 0); + if (base::CommandLine::ForCurrentProcess()->HasSwitch("compact-ui")) + return gfx::Size(kGM2SeparatorThickness, GetLayoutConstant(TAB_SEPARATOR_HEIGHT) * 0.6); - return gfx::Size(kGM2SeparatorThickness, - GetLayoutConstant(TAB_SEPARATOR_HEIGHT)); + return gfx::Size(kGM2SeparatorThickness, + GetLayoutConstant(TAB_SEPARATOR_HEIGHT)); } gfx::Insets GM2TabStyle::GetSeparatorMargins() const { diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view.cc b/chrome/browser/ui/views/frame/tab_strip_region_view.cc index 950f465b0e0def..3e43937f1f91d0 100644 --- a/chrome/browser/ui/views/frame/tab_strip_region_view.cc +++ b/chrome/browser/ui/views/frame/tab_strip_region_view.cc @@ -179,16 +179,30 @@ TabStripRegionView::TabStripRegionView(std::unique_ptr tab_strip) } if (ShouldShowNewTabButton(browser)) { - std::unique_ptr tab_strip_control_button = + if (features::IsChromeRefresh2023()) { + std::unique_ptr tab_strip_control_button = std::make_unique( tab_strip_->controller(), base::BindRepeating(&TabStrip::NewTabButtonPressed, base::Unretained(tab_strip_)), - vector_icons::kAddChromeRefreshIcon); - tab_strip_control_button->SetProperty(views::kElementIdentifierKey, + kAddIcon); + tab_strip_control_button->SetProperty(views::kElementIdentifierKey, kNewTabButtonElementId); - new_tab_button_ = AddChildView(std::move(tab_strip_control_button)); + new_tab_button_ = AddChildView(std::move(tab_strip_control_button)); + + } else { + std::unique_ptr new_tab_button = + std::make_unique( + tab_strip_, base::BindRepeating(&TabStrip::NewTabButtonPressed, + base::Unretained(tab_strip_))); + new_tab_button->SetImageVerticalAlignment( + views::ImageButton::ALIGN_BOTTOM); + new_tab_button->SetEventTargeter( + std::make_unique(new_tab_button.get())); + + new_tab_button_ = AddChildView(std::move(new_tab_button)); + } new_tab_button_->SetTooltipText( l10n_util::GetStringUTF16(IDS_TOOLTIP_NEW_TAB)); diff --git a/chrome/browser/ui/views/tabs/new_tab_button.cc b/chrome/browser/ui/views/tabs/new_tab_button.cc index 6effffb723c69a..3c5d3a1915081b 100644 --- a/chrome/browser/ui/views/tabs/new_tab_button.cc +++ b/chrome/browser/ui/views/tabs/new_tab_button.cc @@ -169,9 +169,9 @@ SkPath NewTabButton::GetBorderPath(const gfx::Point& origin, radius); } } else { - SkPoint pts [] = {SkPoint(0.0, 8.0), SkPoint(24.0, 8.0), SkPoint(30.0, 20.0), SkPoint(6.0, 20.0)}; - path.moveTo(origin.x() * 1.10, SkScalar(8.0)); - path.addPoly(pts, 4, true); + SkPoint pts [] = {SkPoint(4.0, 8.0), SkPoint(22.0, 8.0), SkPoint(28.0, 20.0), SkPoint(10.0, 20.0)}; + path.moveTo(origin.x() * 1.10, SkScalar(8.0)); + path.addPoly(pts, 4, true); } return path; } diff --git a/chrome/browser/ui/views/tabs/tab_style_views.cc b/chrome/browser/ui/views/tabs/tab_style_views.cc index 03cc305687e40c..bd529c325c83d0 100644 --- a/chrome/browser/ui/views/tabs/tab_style_views.cc +++ b/chrome/browser/ui/views/tabs/tab_style_views.cc @@ -7,9 +7,13 @@ #include #include +#include "base/command_line.h" +#include "base/logging.h" +#include "base/files/file_util.h" #include "base/i18n/rtl.h" #include "base/memory/raw_ptr.h" #include "base/numerics/safe_conversions.h" +#include "base/path_service.h" #include "base/strings/strcat.h" #include "cc/paint/paint_record.h" #include "cc/paint/paint_shader.h" @@ -27,6 +31,7 @@ #include "chrome/browser/ui/views/tabs/tab_group_underline.h" #include "chrome/browser/ui/views/tabs/tab_slot_controller.h" #include "chrome/browser/ui/views/tabs/tab_slot_view.h" +#include "chrome/common/chrome_paths.h" #include "chrome/grit/theme_resources.h" #include "components/tab_groups/tab_group_visual_data.h" #include "third_party/skia/include/core/SkRRect.h" @@ -205,6 +210,117 @@ GM2TabStyleViews::GM2TabStyleViews(Tab* tab) // repurposing CONTEXT_BUTTON_MD. } +typedef struct DataItem { + int datakey; // index of point on the tab + std::vector values; // +}DataItem; + +bool UserDefinedTabShape(SkPath& path, bool IsActive, bool IsPinned, bool IsFirst, float left, float tab_top) { + int64_t file_size = 0; + base::FilePath userdir; + if(!base::PathService::Get(chrome::DIR_USER_DATA, &userdir)) + return false; // Things are seriously wrong if the user data directory cannot be located. + const base::FilePath userpath = userdir.Append(FILE_PATH_LITERAL("scs")); + base::GetFileSize(userpath, &file_size); + if(!file_size) + return false; + std::vector buf(file_size); + base::ReadFile(userpath, reinterpret_cast(buf.data()), file_size); + std::string bufstr = std::string(reinterpret_cast(buf.data())); + + std::string::size_type sectionstart = bufstr.find("tab"); + std::string::size_type sectionend = bufstr.find("endtab"); + + std::string::size_type fallbacksectionstart = sectionstart; + std::string::size_type fallbacksectionend = sectionend; + + if(IsPinned) { + sectionstart = bufstr.find("pinnedtab"); + sectionend = bufstr.find("endpinnedtab"); + if(sectionstart == std::string::npos || sectionend == std::string::npos) { + sectionstart = fallbacksectionstart; + sectionend = fallbacksectionend; + } + } + + if(IsActive) { + sectionstart = bufstr.find("activetab"); + sectionend = bufstr.find("endactivetab"); + if(sectionstart == std::string::npos || sectionend == std::string::npos) { + sectionstart = fallbacksectionstart; + sectionend = fallbacksectionend; + } + } + else { + sectionstart = bufstr.find("inactivetab"); + sectionend = bufstr.find("endinactivetab"); + if(sectionstart == std::string::npos || sectionend == std::string::npos) { + sectionstart = fallbacksectionstart; + sectionend = fallbacksectionend; + } + } + + if(IsFirst) { + sectionstart = bufstr.find("firsttab"); + sectionend = bufstr.find("endfirsttab"); + if(sectionstart == std::string::npos || sectionend == std::string::npos) { + sectionstart = fallbacksectionstart; + sectionend = fallbacksectionend; + } + } + + if(sectionstart == std::string::npos || sectionend == std::string::npos) + return false; + + sectionstart += std::string("tab").length(); + + std::string sectionContent = bufstr.substr(sectionstart, sectionend - sectionstart); + + std::string::size_type pos = 0; + while ((pos = sectionContent.find("{", pos)) != std::string::npos) { + std::string::size_type endPos = sectionContent.find("}", pos); + if (endPos == std::string::npos) { + break; + } + + std::string dataItemStr = sectionContent.substr(pos + 1, endPos - pos - 1); + std::string::size_type equalPos = dataItemStr.find('='); + + if (equalPos != std::string::npos) { + DataItem dataItem; + std::string key = dataItemStr.substr(0, equalPos); + if(!std::all_of(key.begin(), key.end(), [](char c) {return c >= '0' && c <= '9';})) + break; + dataItem.datakey = std::stoi(key); + std::string valuesStr = dataItemStr.substr(equalPos + 1); + + // Parse the values + std::istringstream valuesStream(valuesStr); + std::string value; + while (std::getline(valuesStream, value, ',')) { + if(!std::all_of(value.begin(), value.end(), [](char c) {return (c >= '0' && c <= '9') || c == '.';})) + break; // No exceptions, so we must verify that there are only integers in the value before continuing. + // If not, the config file is considered to be "compromised" and needs to be replaced or fixed. + // We will not tolerate any unexpected values in the data. + if(value.size() > 6) + break; // Any "unnecessarily large" numbers will also be blocked. + float val = std::stof(value); + + dataItem.values.push_back(val); + } + + if(dataItem.values.size() != 6) + break; // Fail if there is an incorrect quantity of values in the data item. + path.cubicTo(left + dataItem.values.at(0), tab_top + dataItem.values.at(1), left + dataItem.values.at(2), tab_top + dataItem.values.at(3), left + dataItem.values.at(4), + tab_top + dataItem.values.at(5)); + } + + pos = endPos + 1; + } + + return true; +} + SkPath GM2TabStyleViews::GetPath(TabStyle::PathType path_type, float scale, bool force_active, @@ -322,90 +438,112 @@ SkPath GM2TabStyleViews::GetPath(TabStyle::PathType path_type, // stroke width. // Start with the left side of the shape. - path.moveTo(left, extended_bottom); + path.moveTo(left, extended_bottom); + if(!UserDefinedTabShape(path, tab_->controller()->IsActiveTab(tab_), tab_->controller()->IsTabPinned(tab_), + tab_->controller()->IsTabFirst(tab_), left, tab_top)) { + + if (!base::FeatureList::IsEnabled(features::kSupermiumCustomTabs)) { + path.moveTo(left, extended_bottom); + if (tab_left != left) { + // Draw the left edge of the extension. + // ╭─────────╮ + // │ Content │ + // ┏─╯ ╰─┐ + if (tab_bottom != extended_bottom) + path.lineTo(left, tab_bottom); + + // Draw the bottom-left corner. + // ╭─────────╮ + // │ Content │ + // ┌━╝ ╰─┐ + if (extend_left_to_bottom) { + path.lineTo(tab_left, tab_bottom); + } else { + path.lineTo(tab_left - extension_corner_radius, tab_bottom); + path.arcTo(extension_corner_radius, extension_corner_radius, 0, + SkPath::kSmall_ArcSize, SkPathDirection::kCCW, tab_left, + tab_bottom - extension_corner_radius); + } + } - if (tab_left != left) { - // Draw the left edge of the extension. - // ╭─────────╮ - // │ Content │ - // ┏─╯ ╰─┐ - if (tab_bottom != extended_bottom) - path.lineTo(left, tab_bottom); + // Draw the ascender and top-left curve, if present. + if (extend_to_top) { + // ┎─────────╮ + // ┃ Content │ + // ┌─╯ ╰─┐ + path.lineTo(tab_left, tab_top); + } else { + // ╔─────────╮ + // ┃ Content │ + // ┌─╯ ╰─┐ + path.lineTo(tab_left, tab_top + content_corner_radius); + path.arcTo(content_corner_radius, content_corner_radius, 0, + SkPath::kSmall_ArcSize, SkPathDirection::kCW, + tab_left + content_corner_radius, tab_top); + } - // Draw the bottom-left corner. - // ╭─────────╮ - // │ Content │ - // ┌━╝ ╰─┐ - if (extend_left_to_bottom) { - path.lineTo(tab_left, tab_bottom); + // Draw the top crossbar and top-right curve, if present. + if (extend_to_top) { + // ┌━━━━━━━━━┑ + // │ Content │ + // ┌─╯ ╰─┐ + path.lineTo(tab_right, tab_top); } else { - path.lineTo(tab_left - extension_corner_radius, tab_bottom); - path.arcTo(extension_corner_radius, extension_corner_radius, 0, - SkPath::kSmall_ArcSize, SkPathDirection::kCCW, tab_left, - tab_bottom - extension_corner_radius); + // ╭━━━━━━━━━╗ + // │ Content │ + // ┌─╯ ╰─┐ + path.lineTo(tab_right - content_corner_radius, tab_top); + path.arcTo(content_corner_radius, content_corner_radius, 0, + SkPath::kSmall_ArcSize, SkPathDirection::kCW, tab_right, + tab_top + content_corner_radius); } - } - // Draw the ascender and top-left curve, if present. - if (extend_to_top) { - // ┎─────────╮ - // ┃ Content │ - // ┌─╯ ╰─┐ - path.lineTo(tab_left, tab_top); - } else { - // ╔─────────╮ - // ┃ Content │ - // ┌─╯ ╰─┐ - path.lineTo(tab_left, tab_top + content_corner_radius); - path.arcTo(content_corner_radius, content_corner_radius, 0, - SkPath::kSmall_ArcSize, SkPathDirection::kCW, - tab_left + content_corner_radius, tab_top); - } + if (tab_right != right) { + // Draw the descender and bottom-right corner. + // ╭─────────╮ + // │ Content ┃ + // ┌─╯ ╚━┐ + if (extend_right_to_bottom) { + path.lineTo(tab_right, tab_bottom); + } else { + path.lineTo(tab_right, tab_bottom - extension_corner_radius); + path.arcTo(extension_corner_radius, extension_corner_radius, 0, + SkPath::kSmall_ArcSize, SkPathDirection::kCCW, + tab_right + extension_corner_radius, tab_bottom); + } + if (tab_bottom != extended_bottom) + path.lineTo(right, tab_bottom); + } - // Draw the top crossbar and top-right curve, if present. - if (extend_to_top) { - // ┌━━━━━━━━━┑ - // │ Content │ - // ┌─╯ ╰─┐ - path.lineTo(tab_right, tab_top); - } else { - // ╭━━━━━━━━━╗ + // Draw anything remaining: the descender, the bottom right horizontal + // stroke, or the right edge of the extension, depending on which + // conditions fired above. + // ╭─────────╮ // │ Content │ - // ┌─╯ ╰─┐ - path.lineTo(tab_right - content_corner_radius, tab_top); - path.arcTo(content_corner_radius, content_corner_radius, 0, - SkPath::kSmall_ArcSize, SkPathDirection::kCW, tab_right, - tab_top + content_corner_radius); + // ┌─╯ ╰─┓ + path.lineTo(right, extended_bottom); } - - if (tab_right != right) { - // Draw the descender and bottom-right corner. - // ╭─────────╮ - // │ Content ┃ - // ┌─╯ ╚━┐ - if (extend_right_to_bottom) { - path.lineTo(tab_right, tab_bottom); + else { + path.moveTo(left, extended_bottom); + if (extend_to_top) { + // Create the vertical extension by extending the side diagonals until + // they reach the top of the bounds. + path.cubicTo(left, extended_bottom, (((tab_left + 10) + left) / 2), ((tab_top + extended_bottom) / 2), tab_left + 10, + tab_top); + path.lineTo(tab_right - 10, tab_top); + path.cubicTo(tab_right - 10, tab_top, (((tab_right - 10) + right) / 2), ((tab_top + extended_bottom) / 2), right, + extended_bottom); } else { - path.lineTo(tab_right, tab_bottom - extension_corner_radius); - path.arcTo(extension_corner_radius, extension_corner_radius, 0, - SkPath::kSmall_ArcSize, SkPathDirection::kCCW, - tab_right + extension_corner_radius, tab_bottom); + path.cubicTo(left, extended_bottom, (((tab_left + 4) + left) / 2), (((tab_top * 0.5) + extended_bottom) / 2), tab_left + 4, + (tab_top * 0.5)); + path.cubicTo(tab_left + 4, (tab_top * 0.5), tab_left + 4, tab_top * 0.5, tab_right - 4, tab_top * 0.5); + path.cubicTo(tab_right - 4, (tab_top * 0.5), (((tab_right - 4) + right) / 2), (((tab_top * 0.5) + extended_bottom) / 2), right, + extended_bottom); } - if (tab_bottom != extended_bottom) - path.lineTo(right, tab_bottom); - } - - // Draw anything remaining: the descender, the bottom right horizontal - // stroke, or the right edge of the extension, depending on which - // conditions fired above. - // ╭─────────╮ - // │ Content │ - // ┌─╯ ╰─┓ - path.lineTo(right, extended_bottom); - - if (path_type != TabStyle::PathType::kBorder) { - path.close(); + if(!force_active) + path.close(); } + } } // Convert path to be relative to the tab origin. @@ -664,12 +802,16 @@ float GM2TabStyleViews::GetSeparatorOpacity(bool for_layout, const Tab* adjacent_tab = tab_->controller()->GetAdjacentTab(tab_, leading ? -1 : 1); + // The separator should never appear at the end of the tab strip. + if (!adjacent_tab && !leading) + return 0.0f; const Tab* left_tab = leading ? adjacent_tab : tab_.get(); const Tab* right_tab = leading ? tab_.get() : adjacent_tab; const bool adjacent_to_header = right_tab && right_tab->group().has_value() && (!left_tab || left_tab->group() != right_tab->group()); + // If the current tab is selected, default to hiding the separator. Only show // the separator if it's adjacent to other selected tabs. @@ -936,8 +1078,21 @@ void GM2TabStyleViews::PaintTabBackgroundFill( cc::PaintFlags flags; flags.setAntiAlias(true); flags.setColor(GetCurrentTabBackgroundColor(selection_state, hovered)); + if (base::CommandLine::ForCurrentProcess()->HasSwitch("transparent-tabs") && + selection_state != TabStyle::TabSelectionState::kActive) + flags.setAlphaf(0.7f); canvas->DrawRect(gfx::ScaleToEnclosingRect(tab_->GetLocalBounds(), scale), flags); + if ((base::FeatureList::IsEnabled(features::kSupermiumCustomTabs) && + !base::CommandLine::ForCurrentProcess()->HasSwitch("override-tab-outline-default")) || + (!base::FeatureList::IsEnabled(features::kSupermiumCustomTabs) && + base::CommandLine::ForCurrentProcess()->HasSwitch("override-tab-outline-default"))) { + flags.setAlphaf(1.0f); + flags.setColor(SkColorSetRGB(0, 0, 0)); + flags.setStyle(cc::PaintFlags::kStroke_Style); + canvas->DrawPath(fill_path, + flags); + } } if (fill_id.has_value()) {