Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds screenshot options to context menu and commands #27083

Open
wants to merge 56 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
c48e0dc
adds screenshot feature and flag
jonathansampson Dec 28, 2024
c7bdfa2
adds context menu screenshot options
jonathansampson Dec 28, 2024
24ed995
addresses flaky assumption in unit tests
jonathansampson Dec 28, 2024
9b4e8d4
exposes functions to commander
jonathansampson Dec 28, 2024
f812ee8
adds unit tests for context-menu/feature-flag
jonathansampson Dec 29, 2024
369d926
refactored into TabHelper pattern
jonathansampson Jan 2, 2025
6ad78d1
minor presubmit fixes
jonathansampson Jan 2, 2025
70e9ef2
removes unnecessary /tabs/ subdirectory
jonathansampson Jan 4, 2025
f7e56b5
removes unnecessary /ui/views/ subdirectory
jonathansampson Jan 4, 2025
9300f5b
removes unnecessary /components/ directory
jonathansampson Jan 4, 2025
4888cf4
fixes dates and header guards
jonathansampson Jan 4, 2025
3a95846
presubmit fixes
jonathansampson Jan 4, 2025
2619097
revert remnant changes to brave_ui_* files
jonathansampson Jan 4, 2025
d20e649
cleanup "command" remnants
jonathansampson Jan 4, 2025
ed0d8db
more consistent naming
jonathansampson Jan 4, 2025
8b38e36
adopting more consistently-used pattern
jonathansampson Jan 4, 2025
4361207
provides an enabled-state method
jonathansampson Jan 4, 2025
1762d1d
presubmit cleanup
jonathansampson Jan 4, 2025
80c5bcf
cleanup
jonathansampson Jan 4, 2025
5acd2b8
drop reliance on browser_finder
jonathansampson Jan 4, 2025
4d09da3
refactors into a tab feature
jonathansampson Jan 4, 2025
00c0ba3
updates macro for feature inclusion
jonathansampson Jan 4, 2025
9b80751
removes complex multi-line /* ... */ comment
jonathansampson Jan 5, 2025
432e9e1
conditionally enable the tab feature
jonathansampson Jan 5, 2025
843c25e
more accurate conditional method name
jonathansampson Jan 6, 2025
79791e8
resolves omission of parameter names
jonathansampson Jan 6, 2025
3629f1c
improves screenshot utilities
jonathansampson Jan 6, 2025
b481e8f
refactors to use browser reference
jonathansampson Jan 6, 2025
b07749b
more accurate feature description
jonathansampson Jan 6, 2025
465f96c
various simplifications
jonathansampson Jan 6, 2025
087983a
moves screenshot strings to own file
jonathansampson Jan 6, 2025
7d62a4a
Don't show the submenu within devtools
jonathansampson Jan 6, 2025
e0b19f4
refactors devtools code into distinct helper
jonathansampson Jan 6, 2025
c62a514
pesubmit fixes
jonathansampson Jan 7, 2025
e5cf97c
avoid forward declarations per style guide
jonathansampson Jan 7, 2025
6a799aa
Skip autocomplete classifier on empty selection
jonathansampson Jan 7, 2025
39e05b5
adds context-menu related unittests for screenshots
jonathansampson Jan 7, 2025
99521cc
cleanup and simplify unit tests
jonathansampson Jan 7, 2025
025eccb
dependency cleanup
jonathansampson Jan 7, 2025
476f49b
moves to strategy-based screenshotting
jonathansampson Jan 9, 2025
bfd9bb2
Simplifies clip-indicating member
jonathansampson Jan 10, 2025
debb5b7
Update screenshots_tab_feature.cc
jonathansampson Jan 10, 2025
6947a0e
adds some comments around screenshot limitations
jonathansampson Jan 10, 2025
cd3fe53
minor note changes
jonathansampson Jan 11, 2025
360dc12
removes unused includes
jonathansampson Jan 12, 2025
af98f54
clean up build.gn deps
jonathansampson Jan 13, 2025
8e5bed9
uses explicit/intentional targets
jonathansampson Jan 13, 2025
5ccd6b4
uses debug logs
jonathansampson Jan 14, 2025
8dbbfb4
typo-correction to resolve build
jonathansampson Jan 16, 2025
8d43dbe
addressing minor feedback items
jonathansampson Jan 18, 2025
10153c9
adds GitHub Issue reference
jonathansampson Jan 18, 2025
ed6df8d
removes unused include
jonathansampson Jan 18, 2025
16b8367
removes explicit targets
jonathansampson Jan 22, 2025
1862009
clean up tests
jonathansampson Jan 22, 2025
773a835
filenames and classnames should match
jonathansampson Jan 22, 2025
6a44374
presubmit fixes
jonathansampson Jan 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/brave_command_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@

#define IDC_WINDOW_BRING_ALL_TABS 56320

// Screenshot commands
#define IDC_BRAVE_SCREENSHOT_TOOLS 56321
#define IDC_BRAVE_SCREENSHOTS_START_SELECTION_TO_CLIPBOARD 56322
#define IDC_BRAVE_SCREENSHOTS_START_VIEWPORT_TO_CLIPBOARD 56323
#define IDC_BRAVE_SCREENSHOTS_START_FULLPAGE_TO_CLIPBOARD 56324

// Commands related to split view
#define IDC_NEW_SPLIT_VIEW 56325
#define IDC_TILE_TABS 56326
Expand Down
4 changes: 3 additions & 1 deletion app/brave_generated_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@
<messages fallback_to_english="true">
<!-- Brave Settings WebUI strings -->
<part file="brave_settings_strings.grdp" />
<!-- Brave Screenshots context-menu/settings strings -->
<part file="brave_screenshots_strings.grdp" />

<!--Add new items to the appropriate sections below -->

Expand Down Expand Up @@ -346,7 +348,7 @@ Or change later at <ph name="SETTINGS_EXTENIONS_LINK">$2<ex>brave://settings/ext
Check details
</message>

<!-- Adblock contenxt menu -->
<!-- Adblock context menu -->
<message name="IDS_ADBLOCK_CONTEXT_BLOCK_ELEMENTS" desc="Message for context menu that enables the element picker UI to apply cosmetic filter rules to the page">
Block elements
</message>
Expand Down
31 changes: 31 additions & 0 deletions app/brave_screenshots_strings.grdp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version='1.0' encoding='UTF-8'?>
<grit-part>
<if expr="use_titlecase">
<message name="IDS_IDC_BRAVE_SCREENSHOT_TOOLS" desc="Title for the screenshot submenu">
Screenshot Tools
</message>
<message name="IDS_IDC_BRAVE_SCREENSHOTS_START_SELECTION_TO_CLIPBOARD" desc="Title for option to screenshot a region and copy to clipboard">
Screenshot Selection to Clipboard
</message>
<message name="IDS_IDC_BRAVE_SCREENSHOTS_START_VIEWPORT_TO_CLIPBOARD" desc="Title for option to screenshot the viewport and copy to clipboard">
Screenshot Viewport to Clipboard
</message>
<message name="IDS_IDC_BRAVE_SCREENSHOTS_START_FULLPAGE_TO_CLIPBOARD" desc="Title for option to screenshot the full page and copy to clipboard">
Screenshot Full Page to Clipboard
</message>
</if>
<if expr="not use_titlecase">
<message name="IDS_IDC_BRAVE_SCREENSHOT_TOOLS" desc="Title for the screenshot submenu">
Screenshot tools
</message>
<message name="IDS_IDC_BRAVE_SCREENSHOTS_START_SELECTION_TO_CLIPBOARD" desc="Title for option to screenshot a region and copy to clipboard">
Screenshot selection to clipboard
</message>
<message name="IDS_IDC_BRAVE_SCREENSHOTS_START_VIEWPORT_TO_CLIPBOARD" desc="Title for option to screenshot the viewport and copy to clipboard">
Screenshot viewport to clipboard
</message>
<message name="IDS_IDC_BRAVE_SCREENSHOTS_START_FULLPAGE_TO_CLIPBOARD" desc="Title for option to screenshot the full page and copy to clipboard">
Screenshot full page to clipboard
</message>
</if>
</grit-part>
8 changes: 8 additions & 0 deletions browser/about_flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "base/strings/string_util.h"
#include "brave/browser/brave_browser_features.h"
#include "brave/browser/brave_features_internal_names.h"
#include "brave/browser/brave_screenshots/features.h"
#include "brave/browser/ethereum_remote_client/buildflags/buildflags.h"
#include "brave/browser/ethereum_remote_client/features.h"
#include "brave/browser/ui/brave_ui_features.h"
Expand Down Expand Up @@ -501,6 +502,13 @@
kOsDesktop, \
FEATURE_VALUE_TYPE(features::kBraveNtpSearchWidget), \
}, \
{ \
"brave-screenshots", \
"Screenshot Options", \
"Enables screenshot support via browser commands and context menu.", \
kOsDesktop, \
FEATURE_VALUE_TYPE(brave_screenshots::features::kBraveScreenshots), \
}, \
{ \
"brave-adblock-cname-uncloaking", \
"Enable CNAME uncloaking", \
Expand Down
74 changes: 74 additions & 0 deletions browser/brave_screenshots/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Copyright (c) 2025 The Brave Authors. All rights reserved.
# 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 https://mozilla.org/MPL/2.0/.

import("//brave/browser/brave_screenshots/buildflags/buildflags.gni")

assert(enable_brave_screenshots)

source_set("utils") {
sources = [
"screenshots_utils.cc",
"screenshots_utils.h",
]

deps = [
"//chrome/browser/image_editor",
"//chrome/browser/ui",
"//chrome/browser/ui/browser_window",
"//ui/base/clipboard",
]
}

source_set("strategies") {
sources = [
"strategies/fullpage_strategy.cc",
"strategies/fullpage_strategy.h",
"strategies/screenshot_strategy.h",
"strategies/selection_strategy.cc",
"strategies/selection_strategy.h",
"strategies/viewport_strategy.cc",
"strategies/viewport_strategy.h",
]

deps = [
"//chrome/browser/image_editor",
"//chrome/browser/ui",
]
}

source_set("tabs") {
sources = [
"brave_screenshots_tab_feature.cc",
"brave_screenshots_tab_feature.h",
]

deps = [
":strategies",
":utils",
"//chrome/browser/image_editor",
"//chrome/browser/ui",
]
}

source_set("features") {
sources = [
"features.cc",
"features.h",
]

deps = [ "//base" ]
}

source_set("unit_tests") {
testonly = true
sources = [ "test/brave_screenshots_unittests.cc" ]
deps = [
":features",
"//base",
"//brave/app:command_ids",
"//chrome/test:test_support",
"//testing/gtest",
]
}
96 changes: 96 additions & 0 deletions browser/brave_screenshots/brave_screenshots_tab_feature.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) 2025 The Brave Authors. All rights reserved.
// 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 https://mozilla.org/MPL/2.0/.

#include "brave/browser/brave_screenshots/brave_screenshots_tab_feature.h"

#include "base/notreached.h"
#include "brave/browser/brave_screenshots/screenshots_utils.h"
#include "brave/browser/brave_screenshots/strategies/fullpage_strategy.h"
#include "brave/browser/brave_screenshots/strategies/selection_strategy.h"
#include "brave/browser/brave_screenshots/strategies/viewport_strategy.h"
#include "chrome/browser/image_editor/screenshot_flow.h"
#include "chrome/browser/ui/browser.h"
#include "content/public/browser/web_contents.h"

namespace {

// Some screenshots may need to be clipped to avoid the GPU limit.
// See https://crbug.com/1260828. When this happens, we may wish to notify the
// user that only a portion of their page could be captured.
void DisplayScreenshotClippedNotification(base::WeakPtr<Browser> browser) {
// Issue: https://github.com/brave/brave-browser/issues/43369
NOTIMPLEMENTED();
}

} // namespace
namespace brave_screenshots {

BraveScreenshotsTabFeature::BraveScreenshotsTabFeature() {
DVLOG(1) << "BraveScreenshotsTabFeature created";
}

BraveScreenshotsTabFeature::~BraveScreenshotsTabFeature() {
DVLOG(1) << "BraveScreenshotsTabFeature destroyed";
}

void BraveScreenshotsTabFeature::StartScreenshot(Browser* browser,
ScreenshotType type) {
DVLOG(1) << "Called StartScreenshot";
CHECK(browser);

browser_ = browser->AsWeakPtr();
web_contents_ =
browser_->tab_strip_model()->GetActiveWebContents()->GetWeakPtr();

// We've determined the appropriate strategy to use
strategy_ = CreateStrategy(type);

DVLOG(2) << "Starting capture";

strategy_->Capture(
web_contents_.get(),
base::BindOnce(&BraveScreenshotsTabFeature::OnCaptureComplete,
weak_factory_.GetWeakPtr()));
}

std::unique_ptr<BraveScreenshotStrategy>
BraveScreenshotsTabFeature::CreateStrategy(ScreenshotType type) {
switch (type) {
case ScreenshotType::kFullPage:
DVLOG(3) << "Creating FullPageStrategy";
return std::make_unique<FullPageStrategy>();
case ScreenshotType::kSelection:
// Based on image_editor::ScreenshotFlow, which requires a WebContents
DVLOG(3) << "Creating SelectionStrategy";
return std::make_unique<SelectionStrategy>(web_contents_.get());
case ScreenshotType::kViewport:
// Based on image_editor::ScreenshotFlow, which requires a WebContents
DVLOG(3) << "Creating ViewportStrategy";
return std::make_unique<ViewportStrategy>(web_contents_.get());
default:
NOTREACHED();
}
}

void BraveScreenshotsTabFeature::OnCaptureComplete(
const image_editor::ScreenshotCaptureResult& result) {
DVLOG(2) << __func__;

if (result.image.IsEmpty()) {
DVLOG(2) << "Screenshot capture failed";
return;
}

if (strategy_->DidClipScreenshot()) {
DisplayScreenshotClippedNotification(browser_);
}

if (browser_) {
utils::CopyImageToClipboard(result);
utils::DisplayScreenshotBubble(result, browser_);
}
}

} // namespace brave_screenshots
47 changes: 47 additions & 0 deletions browser/brave_screenshots/brave_screenshots_tab_feature.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2025 The Brave Authors. All rights reserved.
// 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 https://mozilla.org/MPL/2.0/.

#ifndef BRAVE_BROWSER_BRAVE_SCREENSHOTS_BRAVE_SCREENSHOTS_TAB_FEATURE_H_
#define BRAVE_BROWSER_BRAVE_SCREENSHOTS_BRAVE_SCREENSHOTS_TAB_FEATURE_H_

#include <memory>

#include "base/memory/weak_ptr.h"
#include "brave/browser/brave_screenshots/strategies/screenshot_strategy.h"
#include "chrome/browser/image_editor/screenshot_flow.h"
#include "chrome/browser/ui/browser.h"
#include "content/public/browser/web_contents.h"

namespace brave_screenshots {

enum ScreenshotType {
kSelection,
kViewport,
kFullPage,
};

class BraveScreenshotsTabFeature {
public:
BraveScreenshotsTabFeature();
BraveScreenshotsTabFeature(const BraveScreenshotsTabFeature&) = delete;
BraveScreenshotsTabFeature& operator=(const BraveScreenshotsTabFeature&) =
delete;
~BraveScreenshotsTabFeature();

void StartScreenshot(Browser* browser, ScreenshotType type);

private:
void OnCaptureComplete(const image_editor::ScreenshotCaptureResult& result);
std::unique_ptr<BraveScreenshotStrategy> CreateStrategy(ScreenshotType type);
base::WeakPtr<Browser> browser_ = nullptr;
std::unique_ptr<BraveScreenshotStrategy> strategy_ = nullptr;
base::WeakPtr<content::WebContents> web_contents_ = nullptr;
base::WeakPtrFactory<BraveScreenshotsTabFeature> weak_factory_{this};

}; // class BraveScreenshotsTabFeature

} // namespace brave_screenshots

#endif // BRAVE_BROWSER_BRAVE_SCREENSHOTS_BRAVE_SCREENSHOTS_TAB_FEATURE_H_
8 changes: 8 additions & 0 deletions browser/brave_screenshots/buildflags/buildflags.gni
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2025 The Brave Authors. All rights reserved.
# 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 https://mozilla.org/MPL/2.0/.

declare_args() {
enable_brave_screenshots = is_win || is_mac || is_linux
}
17 changes: 17 additions & 0 deletions browser/brave_screenshots/features.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) 2025 The Brave Authors. All rights reserved.
// 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 https://mozilla.org/MPL/2.0/.

#include "brave/browser/brave_screenshots/features.h"

namespace brave_screenshots::features {

BASE_FEATURE(kBraveScreenshots,
"BraveScreenshots",
base::FEATURE_ENABLED_BY_DEFAULT);

bool IsBraveScreenshotsEnabled() {
return base::FeatureList::IsEnabled(kBraveScreenshots);
}
} // namespace brave_screenshots::features
17 changes: 17 additions & 0 deletions browser/brave_screenshots/features.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) 2025 The Brave Authors. All rights reserved.
// 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 https://mozilla.org/MPL/2.0/.

#ifndef BRAVE_BROWSER_BRAVE_SCREENSHOTS_FEATURES_H_
#define BRAVE_BROWSER_BRAVE_SCREENSHOTS_FEATURES_H_

#include "base/feature_list.h"

namespace brave_screenshots::features {
BASE_DECLARE_FEATURE(kBraveScreenshots);

bool IsBraveScreenshotsEnabled();
} // namespace brave_screenshots::features

#endif // BRAVE_BROWSER_BRAVE_SCREENSHOTS_FEATURES_H_
44 changes: 44 additions & 0 deletions browser/brave_screenshots/screenshots_utils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2025 The Brave Authors. All rights reserved.
// 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 https://mozilla.org/MPL/2.0/.

#include "brave/browser/brave_screenshots/screenshots_utils.h"

#include "chrome/browser/image_editor/screenshot_flow.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"

namespace brave_screenshots::utils {

using image_editor::ScreenshotCaptureResult;

void CopyImageToClipboard(const ScreenshotCaptureResult& result) {
DVLOG(2) << __func__;
if (result.image.IsEmpty()) {
DVLOG(2) << "Image is empty";
return;
}

DVLOG(2) << "Writing image to clipboard";
// Copy the image to the user's clipboard
ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste)
.WriteImage(*result.image.ToSkBitmap());
}

void DisplayScreenshotBubble(const ScreenshotCaptureResult& result,
base::WeakPtr<Browser> browser) {
DVLOG(2) << __func__;
if (!browser || result.image.IsEmpty()) {
DVLOG(2) << "Browser is null or image is empty";
return;
}

DVLOG(2) << "Displaying screenshot bubble";
// Leverage the screenshot bubble to show the user the screenshot
browser->window()->ShowScreenshotCapturedBubble(
browser->tab_strip_model()->GetActiveWebContents(), result.image);
}

} // namespace brave_screenshots::utils
Loading
Loading