Chrome · Downloads
CVE-2026-87655
Logic Error in Downloads
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
forchrome/browser/ui/views/download/bubble/download_bubble_row_view.cc |
modified | |
TEST_Fchrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc |
modified |
Files Changed
chrome/browser/ui/views/download/bubble/download_bubble_row_view.ccchrome/browser/ui/views/download/bubble/download_bubble_row_view.hchrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
Patch
From 3cfe51aa2838e8a95f78dbc9e82327de5db20870 Mon Sep 17 00:00:00 2001 From: Yaw Frempong <[email protected]> Date: Thu, 30 Jul 2026 07:25:30 -0700 Subject: [PATCH] [Download Bubble] Disable download bubble main page buttons on PiP occlusion DownloadBubbleRowView::OnOcclusionStateChanged() already disables the row's transparent button and quick-action buttons while the bubble is occluded by a picture-in-picture window. Apply the same treatment to the main page buttons so that they behave consistently with the other controls on the row, and add a unit test covering all three button kinds. Reviewed in https://crrev.com/i/9601875 Bug: 514023309 Change-Id: I3d27699cca9f8dc7010d18cdd09431927eb09753 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8169860 Commit-Queue: Yaw Frempong <[email protected]> Reviewed-by: Lily Chen <[email protected]> Cr-Commit-Position: refs/heads/main@{#1671046} --- diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc index a68d3391..f9b8c9c 100644 --- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc +++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc @@ -978,6 +978,9 @@ for (auto& [command, action_button] : quick_actions_) { action_button->SetEnabled(!occluded); } + for (auto& [command, main_page_button] : main_page_buttons_) { + main_page_button->SetEnabled(!occluded); + } } std::u16string_view DownloadBubbleRowView::GetSecondaryLabelTextForTesting() { @@ -1053,6 +1056,13 @@ return it->second; } +views::MdTextButton* DownloadBubbleRowView::GetMainPageButtonForTesting( + DownloadCommands::Command command) { + auto it = main_page_buttons_.find(command); + CHECK(it != main_page_buttons_.end()); + return it->second; +} + void DownloadBubbleRowView::SetInputProtectorForTesting( std::unique_ptr<views::InputEventActivationProtector> input_protector) { input_protector_ = std::move(input_protector); diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h index 6ca1a625..141a7fe 100644 --- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h +++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h @@ -112,6 +112,8 @@ bool IsQuickActionButtonVisibleForTesting(DownloadCommands::Command command); views::ImageButton* GetQuickActionButtonForTesting( DownloadCommands::Command command); + views::MdTextButton* GetMainPageButtonForTesting( + DownloadCommands::Command command); void SetInputProtectorForTesting( std::unique_ptr<views::InputEventActivationProtector> input_protector); diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc b/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc index 9fb3b9a..9b191dfd 100644 --- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc +++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc @@ -26,6 +26,7 @@ #include "ui/events/test/test_event.h" #include "ui/events/types/event_type.h" #include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/button/md_text_button.h" #include "ui/views/test/mock_input_event_activation_protector.h" namespace { @@ -241,4 +242,28 @@ ->OnMousePressed(event); } +// Test that all button controls on the row are disabled while the row is +// occluded by a picture-in-picture window, and re-enabled when it is not. +TEST_F(DownloadBubbleRowViewTest, OcclusionDisablesButtons) { + views::Button* transparent_button = row_view()->transparent_button(); + views::ImageButton* quick_action = + row_view()->GetQuickActionButtonForTesting(DownloadCommands::CANCEL); + views::MdTextButton* main_page_button = + row_view()->GetMainPageButtonForTesting(DownloadCommands::KEEP); + + ASSERT_TRUE(transparent_button->GetEnabled()); + ASSERT_TRUE(quick_action->GetEnabled()); + ASSERT_TRUE(main_page_button->GetEnabled()); + + row_view()->OnOcclusionStateChanged(/*occluded=*/true); + EXPECT_FALSE(transparent_button->GetEnabled()); + EXPECT_FALSE(quick_action->GetEnabled()); + EXPECT_FALSE(main_page_button->GetEnabled()); + + row_view()->OnOcclusionStateChanged(/*occluded=*/false); + EXPECT_TRUE(transparent_button->GetEnabled()); + EXPECT_TRUE(quick_action->GetEnabled()); + EXPECT_TRUE(main_page_button->GetEnabled()); +} + } // namespace
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc b/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
index 9fb3b9a..9b191dfd 100644
--- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view_unittest.cc
@@ -26,6 +26,7 @@
#include "ui/events/test/test_event.h"
#include "ui/events/types/event_type.h"
#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/test/mock_input_event_activation_protector.h"
namespace {
@@ -241,4 +242,28 @@
->OnMousePressed(event);
}
+// Test that all button controls on the row are disabled while the row is
+// occluded by a picture-in-picture window, and re-enabled when it is not.
+TEST_F(DownloadBubbleRowViewTest, OcclusionDisablesButtons) {
+ views::Button* transparent_button = row_view()->transparent_button();
+ views::ImageButton* quick_action =
+ row_view()->GetQuickActionButtonForTesting(DownloadCommands::CANCEL);
+ views::MdTextButton* main_page_button =
+ row_view()->GetMainPageButtonForTesting(DownloadCommands::KEEP);
+
+ ASSERT_TRUE(transparent_button->GetEnabled());
+ ASSERT_TRUE(quick_action->GetEnabled());
+ ASSERT_TRUE(main_page_button->GetEnabled());
+
+ row_view()->OnOcclusionStateChanged(/*occluded=*/true);
+ EXPECT_FALSE(transparent_button->GetEnabled());
+ EXPECT_FALSE(quick_action->GetEnabled());
+ EXPECT_FALSE(main_page_button->GetEnabled());
+
+ row_view()->OnOcclusionStateChanged(/*occluded=*/false);
+ EXPECT_TRUE(transparent_button->GetEnabled());
+ EXPECT_TRUE(quick_action->GetEnabled());
+ EXPECT_TRUE(main_page_button->GetEnabled());
+}
+
} // namespace
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page