Skip to content

Commit

Permalink
Added TextRecognitionBrowserTest browser test
Browse files Browse the repository at this point in the history
This test extract "brave" text from test image.
  • Loading branch information
simonhong committed Jan 13, 2023
1 parent 58f54ea commit 8e18d4a
Show file tree
Hide file tree
Showing 9 changed files with 250 additions and 49 deletions.
8 changes: 8 additions & 0 deletions browser/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,8 @@ source_set("ui") {

if (enable_text_recognition) {
sources += [
"views/text_recognition_dialog_tracker.cc",
"views/text_recognition_dialog_tracker.h",
"views/text_recognition_dialog_view.cc",
"views/text_recognition_dialog_view.h",
]
Expand Down Expand Up @@ -801,16 +803,22 @@ source_set("browser_tests") {
]

deps = [
"//brave/app:command_ids",
"//brave/browser/ui",
"//brave/components/constants",
"//chrome/browser",
"//chrome/browser/devtools:test_support",
"//chrome/browser/profiles:profile",
"//chrome/browser/ui",
"//chrome/test:test_support",
"//chrome/test:test_support_ui",
"//components/javascript_dialogs",
"//components/prefs",
"//content/test:test_support",
]

if (enable_text_recognition) {
sources += [ "text_recognition_browsertest.cc" ]
}
}
}
150 changes: 150 additions & 0 deletions browser/ui/text_recognition_browsertest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/* Copyright (c) 2023 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 <memory>

#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "brave/app/brave_command_ids.h"
#include "brave/browser/ui/browser_dialogs.h"
#include "brave/browser/ui/views/text_recognition_dialog_tracker.h"
#include "brave/browser/ui/views/text_recognition_dialog_view.h"
#include "brave/components/constants/brave_paths.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "net/dns/mock_host_resolver.h"

namespace {

constexpr char kEmbeddedTestServerDirectory[] = "text_recognition";

} // namespace

class TextRecognitionBrowserTest : public InProcessBrowserTest {
public:
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
content::SetupCrossSiteRedirector(embedded_test_server());

brave::RegisterPathProvider();
base::FilePath test_data_dir;
base::PathService::Get(brave::DIR_TEST_DATA, &test_data_dir);
test_data_dir = test_data_dir.AppendASCII(kEmbeddedTestServerDirectory);
embedded_test_server()->ServeFilesFromDirectory(test_data_dir);

ASSERT_TRUE(embedded_test_server()->Start());
image_html_url_ = embedded_test_server()->GetURL("a.com", "/image.html");
}

void OnGetTextFromImage(const std::vector<std::string>& text) {
// Test image has "brave" text.
EXPECT_EQ("brave", text[0]);
run_loop_->Quit();
}

void OnGetImageForTextCopy(base::WeakPtr<content::WebContents> web_contents,
const SkBitmap& image) {
if (!web_contents)
return;

brave::ShowTextRecognitionDialog(web_contents.get(), image);
}

void WaitUntil(base::RepeatingCallback<bool()> condition) {
if (condition.Run())
return;

base::RepeatingTimer scheduler;
scheduler.Start(FROM_HERE, base::Milliseconds(100),
base::BindLambdaForTesting([this, &condition]() {
if (condition.Run())
run_loop_->Quit();
}));
Run();
}

void Run() {
run_loop_ = std::make_unique<base::RunLoop>();
run_loop()->Run();
}

base::RunLoop* run_loop() const { return run_loop_.get(); }

GURL image_html_url_;
std::unique_ptr<base::RunLoop> run_loop_;
};

IN_PROC_BROWSER_TEST_F(TextRecognitionBrowserTest, TextRecognitionTest) {
content::ContextMenuParams params;
params.media_type = blink::mojom::ContextMenuDataMediaType::kImage;

// kImage type can have copy text from image menu entry.
{
TestRenderViewContextMenu menu(*browser()
->tab_strip_model()
->GetActiveWebContents()
->GetPrimaryMainFrame(),
params);
menu.Init();

EXPECT_TRUE(menu.IsItemPresent(IDC_CONTENT_CONTEXT_COPY_TEXT_FROM_IMAGE));
}

// Other type should not have.
params.media_type = blink::mojom::ContextMenuDataMediaType::kVideo;
{
TestRenderViewContextMenu menu(*browser()
->tab_strip_model()
->GetActiveWebContents()
->GetPrimaryMainFrame(),
params);
menu.Init();

EXPECT_FALSE(menu.IsItemPresent(IDC_CONTENT_CONTEXT_COPY_TEXT_FROM_IMAGE));
}

content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), image_html_url_));
ASSERT_TRUE(WaitForLoadStop(contents));

// Using (10, 10) position will be fine because test image is set at (0, 0).
browser()
->tab_strip_model()
->GetActiveWebContents()
->GetPrimaryMainFrame()
->GetImageAt(
10, 10,
base::BindOnce(&TextRecognitionBrowserTest::OnGetImageForTextCopy,
base::Unretained(this), contents->GetWeakPtr()));
TextRecognitionDialogTracker::CreateForWebContents(contents);
auto* dialog_tracker =
TextRecognitionDialogTracker::FromWebContents(contents);

// Wait till text recognition dialog is launched.
WaitUntil(base::BindLambdaForTesting(
[&]() { return !!dialog_tracker->active_dialog(); }));

TextRecognitionDialogView* text_recognition_dialog =
static_cast<TextRecognitionDialogView*>(
dialog_tracker->active_dialog()->widget_delegate());

// OnGetTextFromImage() verifies extracted text from test image.
text_recognition_dialog->on_get_text_callback_for_test_ = base::BindOnce(
&TextRecognitionBrowserTest::OnGetTextFromImage, base::Unretained(this));

Run();
}
29 changes: 29 additions & 0 deletions browser/ui/views/text_recognition_dialog_tracker.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* Copyright (c) 2023 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/ui/views/text_recognition_dialog_tracker.h"

TextRecognitionDialogTracker::TextRecognitionDialogTracker(
content::WebContents* web_contents)
: content::WebContentsUserData<TextRecognitionDialogTracker>(
*web_contents) {}

TextRecognitionDialogTracker::~TextRecognitionDialogTracker() = default;

void TextRecognitionDialogTracker::SetActiveDialog(views::Widget* widget) {
DCHECK(!active_dialog_ && !observation_.IsObserving());
active_dialog_ = widget;
observation_.Observe(widget);
}

void TextRecognitionDialogTracker::OnWidgetDestroying(views::Widget* widget) {
DCHECK_EQ(active_dialog_, widget);
DCHECK(observation_.IsObservingSource(widget));

observation_.Reset();
active_dialog_ = nullptr;
}

WEB_CONTENTS_USER_DATA_KEY_IMPL(TextRecognitionDialogTracker);
43 changes: 43 additions & 0 deletions browser/ui/views/text_recognition_dialog_tracker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* Copyright (c) 2023 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_UI_VIEWS_TEXT_RECOGNITION_DIALOG_TRACKER_H_
#define BRAVE_BROWSER_UI_VIEWS_TEXT_RECOGNITION_DIALOG_TRACKER_H_

#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "content/public/browser/web_contents_user_data.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"

// Tracks whether text recognition dialog is active or not for WebContents.
class TextRecognitionDialogTracker
: public content::WebContentsUserData<TextRecognitionDialogTracker>,
public views::WidgetObserver {
public:
TextRecognitionDialogTracker(const TextRecognitionDialogTracker&) = delete;
TextRecognitionDialogTracker& operator=(const TextRecognitionDialogTracker&) =
delete;
~TextRecognitionDialogTracker() override;

void SetActiveDialog(views::Widget* widget);

views::Widget* active_dialog() { return active_dialog_; }

private:
friend class content::WebContentsUserData<TextRecognitionDialogTracker>;
explicit TextRecognitionDialogTracker(content::WebContents* web_contents);

// views::WidgetObserver overrides
void OnWidgetDestroying(views::Widget* widget) override;

raw_ptr<views::Widget> active_dialog_ = nullptr;
base::ScopedObservation<views::Widget, views::WidgetObserver> observation_{
this};

WEB_CONTENTS_USER_DATA_KEY_DECL();
};

#endif // BRAVE_BROWSER_UI_VIEWS_TEXT_RECOGNITION_DIALOG_TRACKER_H_
54 changes: 6 additions & 48 deletions browser/ui/views/text_recognition_dialog_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,73 +6,27 @@
#include "brave/browser/ui/views/text_recognition_dialog_view.h"

#include <memory>
#include <utility>

#include "base/bind.h"
#include "base/scoped_observation.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "brave/browser/ui/views/text_recognition_dialog_tracker.h"
#include "brave/components/l10n/common/localization_util.h"
#include "brave/components/text_recognition/browser/text_recognition.h"
#include "brave/grit/brave_generated_resources.h"
#include "components/constrained_window/constrained_window_views.h"
#include "content/public/browser/web_contents_user_data.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/layout/flex_layout.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
#include "ui/views/window/dialog_client_view.h"

namespace {

// Tracks whether text recognition dialog is active or not for WebContents.
class TextRecognitionDialogTracker
: public content::WebContentsUserData<TextRecognitionDialogTracker>,
public views::WidgetObserver {
public:
TextRecognitionDialogTracker(const TextRecognitionDialogTracker&) = delete;
TextRecognitionDialogTracker& operator=(const TextRecognitionDialogTracker&) =
delete;
~TextRecognitionDialogTracker() override = default;

void SetActiveDialog(views::Widget* widget) {
DCHECK(!active_dialog_ && !observation_.IsObserving());
active_dialog_ = widget;
observation_.Observe(widget);
}

views::Widget* active_dialog() { return active_dialog_; }

private:
friend class content::WebContentsUserData<TextRecognitionDialogTracker>;
explicit TextRecognitionDialogTracker(content::WebContents* web_contents)
: content::WebContentsUserData<TextRecognitionDialogTracker>(
*web_contents) {}

// views::WidgetObserver overrides
void OnWidgetDestroying(views::Widget* widget) override {
DCHECK_EQ(active_dialog_, widget);
DCHECK(observation_.IsObservingSource(widget));
observation_.Reset();
active_dialog_ = nullptr;
}

raw_ptr<views::Widget> active_dialog_ = nullptr;
base::ScopedObservation<views::Widget, views::WidgetObserver> observation_{
this};

WEB_CONTENTS_USER_DATA_KEY_DECL();
};

WEB_CONTENTS_USER_DATA_KEY_IMPL(TextRecognitionDialogTracker);

} // namespace

namespace brave {

void ShowTextRecognitionDialog(content::WebContents* web_contents,
Expand Down Expand Up @@ -148,6 +102,10 @@ void TextRecognitionDialogView::OnGetTextFromImage(
const std::vector<std::string>& text) {
UpdateContents(text);
AdjustWidgetSize();

if (on_get_text_callback_for_test_) {
std::move(on_get_text_callback_for_test_).Run(text);
}
}

void TextRecognitionDialogView::UpdateContents(
Expand Down
6 changes: 6 additions & 0 deletions browser/ui/views/text_recognition_dialog_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <string>
#include <vector>

#include "base/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/base/metadata/metadata_header_macros.h"
Expand All @@ -34,6 +35,8 @@ class TextRecognitionDialogView : public views::DialogDelegateView {
void StartExtractingText(const SkBitmap& image);

private:
FRIEND_TEST_ALL_PREFIXES(TextRecognitionBrowserTest, TextRecognitionTest);

void OnGetTextFromImage(const std::vector<std::string>& text);

// Show |text| in this dialog and copy it to clipboard.
Expand All @@ -42,6 +45,9 @@ class TextRecognitionDialogView : public views::DialogDelegateView {

raw_ptr<views::Label> header_label_ = nullptr;
raw_ptr<views::ScrollView> scroll_view_ = nullptr;

base::OnceCallback<void(const std::vector<std::string>&)>
on_get_text_callback_for_test_;
base::WeakPtrFactory<TextRecognitionDialogView> weak_factory_{this};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,11 @@ void BraveRenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
#if BUILDFLAG(ENABLE_TEXT_RECOGNITION)
void BraveRenderViewContextMenu::CopyTextFromImage() {
RenderFrameHost* frame_host = GetRenderFrameHost();
if (frame_host)
if (frame_host) {
frame_host->GetImageAt(params_.x, params_.y,
base::BindOnce(OnGetImageForTextCopy,
source_web_contents_->GetWeakPtr()));
}
}
#endif

Expand Down
6 changes: 6 additions & 0 deletions test/data/text_recognition/image.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<img src="image.png">
</body>
</html>
Binary file added test/data/text_recognition/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 8e18d4a

Please sign in to comment.