summaryrefslogtreecommitdiff
path: root/chromium/chrome/browser/accessibility
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/accessibility')
-rw-r--r--chromium/chrome/browser/accessibility/accessibility_extension_api.cc56
-rw-r--r--chromium/chrome/browser/accessibility/accessibility_extension_api.h13
-rw-r--r--chromium/chrome/browser/accessibility/accessibility_permission_context.cc7
-rw-r--r--chromium/chrome/browser/accessibility/accessibility_ui.cc36
-rw-r--r--chromium/chrome/browser/accessibility/accessibility_ui.h2
-rw-r--r--chromium/chrome/browser/accessibility/caption_controller.cc40
-rw-r--r--chromium/chrome/browser/accessibility/caption_controller.h12
-rw-r--r--chromium/chrome/browser/accessibility/caption_controller_browsertest.cc579
-rw-r--r--chromium/chrome/browser/accessibility/caption_host_impl.cc17
-rw-r--r--chromium/chrome/browser/accessibility/caption_host_impl.h3
-rw-r--r--chromium/chrome/browser/accessibility/image_annotation_browsertest.cc165
11 files changed, 782 insertions, 148 deletions
diff --git a/chromium/chrome/browser/accessibility/accessibility_extension_api.cc b/chromium/chrome/browser/accessibility/accessibility_extension_api.cc
index 528d180500f..6782b42860e 100644
--- a/chromium/chrome/browser/accessibility/accessibility_extension_api.cc
+++ b/chromium/chrome/browser/accessibility/accessibility_extension_api.cc
@@ -58,11 +58,6 @@ namespace {
const char kErrorNotSupported[] = "This API is not supported on this platform.";
-#if defined(OS_CHROMEOS)
-constexpr int kBackButtonWidth = 45;
-constexpr int kBackButtonHeight = 45;
-#endif
-
} // namespace
ExtensionFunction::ResponseAction
@@ -420,57 +415,6 @@ AccessibilityPrivateToggleDictationFunction::Run() {
}
ExtensionFunction::ResponseAction
-AccessibilityPrivateSetSwitchAccessMenuStateFunction::Run() {
- // TODO(anastasi): Remove this function once menu refactor is complete.
- std::unique_ptr<accessibility_private::SetSwitchAccessMenuState::Params>
- params = accessibility_private::SetSwitchAccessMenuState::Params::Create(
- *args_);
- EXTENSION_FUNCTION_VALIDATE(params);
-
- chromeos::AccessibilityManager* manager =
- chromeos::AccessibilityManager::Get();
-
- if (!params->show) {
- manager->HideSwitchAccessMenu();
- return RespondNow(NoArguments());
- }
-
- accessibility_private::ScreenRect elem = std::move(params->element_bounds);
- gfx::Rect element_bounds(elem.left, elem.top, elem.width, elem.height);
- int item_count = params->item_count;
-
- // If we have an item count of 0, the panel is showing only the back button.
- if (item_count == 0) {
- manager->ShowSwitchAccessMenu(element_bounds, kBackButtonWidth,
- kBackButtonHeight,
- true /* back_button_only */);
- return RespondNow(NoArguments());
- }
-
- int padding = 40;
- int item_width = 88;
-
- int item_height;
- if (::switches::IsExperimentalAccessibilitySwitchAccessTextEnabled()) {
- item_height = 85;
- } else {
- item_height = 60;
- }
- // TODO(anastasi): This should be a preference that the user can change.
- int max_cols = 3;
-
- // The number of rows is the number of items divided by the max columns,
- // rounded down.
- int rows = 1 + (item_count - 1) / max_cols;
- int cols = rows == 1 ? item_count : max_cols;
- int width = padding + (item_width * cols);
- int height = padding + (item_height * rows);
-
- manager->ShowSwitchAccessMenu(element_bounds, width, height);
- return RespondNow(NoArguments());
-}
-
-ExtensionFunction::ResponseAction
AccessibilityPrivateForwardKeyEventsToSwitchAccessFunction::Run() {
std::unique_ptr<accessibility_private::ForwardKeyEventsToSwitchAccess::Params>
params =
diff --git a/chromium/chrome/browser/accessibility/accessibility_extension_api.h b/chromium/chrome/browser/accessibility/accessibility_extension_api.h
index 3601324682a..1ea0559c8df 100644
--- a/chromium/chrome/browser/accessibility/accessibility_extension_api.h
+++ b/chromium/chrome/browser/accessibility/accessibility_extension_api.h
@@ -109,8 +109,8 @@ class AccessibilityPrivateOnSelectToSpeakStateChangedFunction
ACCESSIBILITY_PRIVATE_ONSELECTTOSPEAKSTATECHANGED)
};
-// API function that is called when the Autoclick extension finds scrollable
-// bounds.
+// API function that is called when the Accessibility Common extension finds
+// scrollable bounds.
class AccessibilityPrivateOnScrollableBoundsForPointFoundFunction
: public ExtensionFunction {
~AccessibilityPrivateOnScrollableBoundsForPointFoundFunction() override {}
@@ -129,15 +129,6 @@ class AccessibilityPrivateToggleDictationFunction : public ExtensionFunction {
ACCESSIBILITY_PRIVATE_TOGGLEDICTATION)
};
-// API function that is called to show or hide the Switch Access menu.
-class AccessibilityPrivateSetSwitchAccessMenuStateFunction
- : public ExtensionFunction {
- ~AccessibilityPrivateSetSwitchAccessMenuStateFunction() override {}
- ResponseAction Run() override;
- DECLARE_EXTENSION_FUNCTION("accessibilityPrivate.setSwitchAccessMenuState",
- ACCESSIBILITY_PRIVATE_SETSWITCHACCESSMENUSTATE)
-};
-
// API function that requests that key events be forwarded to the Switch
// Access extension.
class AccessibilityPrivateForwardKeyEventsToSwitchAccessFunction
diff --git a/chromium/chrome/browser/accessibility/accessibility_permission_context.cc b/chromium/chrome/browser/accessibility/accessibility_permission_context.cc
index ce2689e3c5b..38fa011f4de 100644
--- a/chromium/chrome/browser/accessibility/accessibility_permission_context.cc
+++ b/chromium/chrome/browser/accessibility/accessibility_permission_context.cc
@@ -7,10 +7,9 @@
AccessibilityPermissionContext::AccessibilityPermissionContext(
content::BrowserContext* browser_context)
- : PermissionContextBase(
- browser_context,
- ContentSettingsType::ACCESSIBILITY_EVENTS,
- blink::mojom::FeaturePolicyFeature::kAccessibilityEvents) {}
+ : PermissionContextBase(browser_context,
+ ContentSettingsType::ACCESSIBILITY_EVENTS,
+ blink::mojom::FeaturePolicyFeature::kNotFound) {}
AccessibilityPermissionContext::~AccessibilityPermissionContext() = default;
diff --git a/chromium/chrome/browser/accessibility/accessibility_ui.cc b/chromium/chrome/browser/accessibility/accessibility_ui.cc
index c77a24e895d..012e421c6e7 100644
--- a/chromium/chrome/browser/accessibility/accessibility_ui.cc
+++ b/chromium/chrome/browser/accessibility/accessibility_ui.cc
@@ -13,6 +13,7 @@
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/json/json_writer.h"
+#include "base/optional.h"
#include "base/strings/pattern.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
@@ -80,6 +81,7 @@ static const char kInternal[] = "internal";
static const char kLabelImages[] = "labelImages";
static const char kNative[] = "native";
static const char kPage[] = "page";
+static const char kPDF[] = "pdf";
static const char kScreenReader[] = "screenreader";
static const char kShowOrRefreshTree[] = "showOrRefreshTree";
static const char kText[] = "text";
@@ -177,6 +179,7 @@ void HandleAccessibilityRequestCallback(
bool text = mode.has_mode(ui::AXMode::kInlineTextBoxes);
bool screenreader = mode.has_mode(ui::AXMode::kScreenReader);
bool html = mode.has_mode(ui::AXMode::kHTML);
+ bool pdf = mode.has_mode(ui::AXMode::kPDF);
// The "native" and "web" flags are disabled if
// --disable-renderer-accessibility is set.
@@ -203,6 +206,9 @@ void HandleAccessibilityRequestCallback(
? (label_images ? kOn : kOff)
: kDisabled);
+ // The "pdf" flag is independent of the others.
+ data.SetString(kPDF, pdf ? kOn : kOff);
+
bool show_internal = pref->GetBoolean(prefs::kShowInternalAccessibilityTree);
data.SetString(kInternal, show_internal ? kOn : kOff);
@@ -367,7 +373,14 @@ void AccessibilityUIObserver::AccessibilityEventReceived(
AccessibilityUIMessageHandler::AccessibilityUIMessageHandler() = default;
-AccessibilityUIMessageHandler::~AccessibilityUIMessageHandler() = default;
+AccessibilityUIMessageHandler::~AccessibilityUIMessageHandler() {
+ if (!observer_)
+ return;
+ content::WebContents* web_contents = observer_->web_contents();
+ if (!web_contents)
+ return;
+ StopRecording(web_contents);
+}
void AccessibilityUIMessageHandler::RegisterMessages() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -641,6 +654,12 @@ void AccessibilityUIMessageHandler::Callback(const std::string& str) {
event_logs_.push_back(str);
}
+void AccessibilityUIMessageHandler::StopRecording(
+ content::WebContents* web_contents) {
+ web_contents->RecordAccessibilityEvents(false, base::nullopt);
+ observer_.reset(nullptr);
+}
+
void AccessibilityUIMessageHandler::RequestAccessibilityEvents(
const base::ListValue* args) {
const base::DictionaryValue* data;
@@ -648,7 +667,7 @@ void AccessibilityUIMessageHandler::RequestAccessibilityEvents(
int process_id = *data->FindIntPath(kProcessIdField);
int routing_id = *data->FindIntPath(kRoutingIdField);
- bool start = *data->FindBoolPath(kStartField);
+ bool start_recording = *data->FindBoolPath(kStartField);
AllowJavascript();
@@ -661,22 +680,17 @@ void AccessibilityUIMessageHandler::RequestAccessibilityEvents(
std::unique_ptr<base::DictionaryValue> result(BuildTargetDescriptor(rvh));
content::WebContents* web_contents =
content::WebContents::FromRenderViewHost(rvh);
- if (start) {
+ if (start_recording) {
if (observer_) {
return;
}
web_contents->RecordAccessibilityEvents(
- base::BindRepeating(&AccessibilityUIMessageHandler::Callback,
- base::Unretained(this)),
- true);
+ true, base::BindRepeating(&AccessibilityUIMessageHandler::Callback,
+ base::Unretained(this)));
observer_ =
std::make_unique<AccessibilityUIObserver>(web_contents, &event_logs_);
} else {
- web_contents->RecordAccessibilityEvents(
- base::BindRepeating(&AccessibilityUIMessageHandler::Callback,
- base::Unretained(this)),
- false);
- observer_.release();
+ StopRecording(web_contents);
std::string event_logs_str;
for (std::string log : event_logs_) {
diff --git a/chromium/chrome/browser/accessibility/accessibility_ui.h b/chromium/chrome/browser/accessibility/accessibility_ui.h
index e7ead6ef86f..906b24117cd 100644
--- a/chromium/chrome/browser/accessibility/accessibility_ui.h
+++ b/chromium/chrome/browser/accessibility/accessibility_ui.h
@@ -21,6 +21,7 @@ class ListValue;
namespace content {
struct AXEventNotificationDetails;
+class WebContents;
} // namespace content
namespace user_prefs {
@@ -68,6 +69,7 @@ class AccessibilityUIMessageHandler : public content::WebUIMessageHandler {
void RequestNativeUITree(const base::ListValue* args);
void RequestAccessibilityEvents(const base::ListValue* args);
void Callback(const std::string&);
+ void StopRecording(content::WebContents* web_contents);
DISALLOW_COPY_AND_ASSIGN(AccessibilityUIMessageHandler);
};
diff --git a/chromium/chrome/browser/accessibility/caption_controller.cc b/chromium/chrome/browser/accessibility/caption_controller.cc
index b18fa01155d..b84de71e2af 100644
--- a/chromium/chrome/browser/accessibility/caption_controller.cc
+++ b/chromium/chrome/browser/accessibility/caption_controller.cc
@@ -53,15 +53,6 @@ void CaptionController::RegisterProfilePrefs(
registry->RegisterFilePathPref(prefs::kSODAPath, base::FilePath());
}
-// static
-void CaptionController::InitOffTheRecordPrefs(Profile* off_the_record_profile) {
- DCHECK(off_the_record_profile->IsOffTheRecord());
- off_the_record_profile->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled,
- false);
- off_the_record_profile->GetPrefs()->SetFilePath(prefs::kSODAPath,
- base::FilePath());
-}
-
void CaptionController::Init() {
// Hidden behind a feature flag.
if (!base::FeatureList::IsEnabled(media::kLiveCaption))
@@ -107,7 +98,8 @@ void CaptionController::UpdateSpeechRecognitionServiceEnabled() {
base::BindOnce(&component_updater::SODAComponentInstallerPolicy::
UpdateSODAComponentOnDemand));
} else {
- // TODO(evliu): Unregister SODA component.
+ // Do nothing. The SODA component will be uninstalled and removed from the
+ // device on the next start up.
}
}
@@ -147,32 +139,42 @@ void CaptionController::UpdateAccessibilityCaptionHistograms() {
}
void CaptionController::OnBrowserAdded(Browser* browser) {
- if (browser->profile() != profile_)
+ if (browser->profile() != profile_ &&
+ browser->profile()->GetOriginalProfile() != profile_) {
return;
+ }
+ DCHECK(!caption_bubble_controllers_.count(browser));
caption_bubble_controllers_[browser] =
CaptionBubbleController::Create(browser);
caption_bubble_controllers_[browser]->UpdateCaptionStyle(caption_style_);
}
void CaptionController::OnBrowserRemoved(Browser* browser) {
- if (browser->profile() != profile_)
+ if (browser->profile() != profile_ &&
+ browser->profile()->GetOriginalProfile() != profile_) {
return;
+ }
DCHECK(caption_bubble_controllers_.count(browser));
caption_bubble_controllers_.erase(browser);
}
-void CaptionController::DispatchTranscription(
+bool CaptionController::DispatchTranscription(
content::WebContents* web_contents,
const chrome::mojom::TranscriptionResultPtr& transcription_result) {
Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
- if (!browser)
- return;
- if (!caption_bubble_controllers_.count(browser))
- return;
- caption_bubble_controllers_[browser]->OnTranscription(transcription_result,
- web_contents);
+ if (!browser || !caption_bubble_controllers_.count(browser))
+ return false;
+ return caption_bubble_controllers_[browser]->OnTranscription(
+ transcription_result, web_contents);
+}
+
+CaptionBubbleController*
+CaptionController::GetCaptionBubbleControllerForBrowser(Browser* browser) {
+ if (!browser || !caption_bubble_controllers_.count(browser))
+ return nullptr;
+ return caption_bubble_controllers_[browser].get();
}
void CaptionController::UpdateCaptionStyle() {
diff --git a/chromium/chrome/browser/accessibility/caption_controller.h b/chromium/chrome/browser/accessibility/caption_controller.h
index 78e3ee77cdf..274b46ab8bf 100644
--- a/chromium/chrome/browser/accessibility/caption_controller.h
+++ b/chromium/chrome/browser/accessibility/caption_controller.h
@@ -62,19 +62,21 @@ class CaptionController : public BrowserListObserver, public KeyedService {
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
- // Off the record profiles will default to having the feature disabled.
- static void InitOffTheRecordPrefs(Profile* off_the_record_profile);
-
void Init();
// Routes a transcription to the CaptionBubbleController that belongs to the
- // appropriate browser.
- void DispatchTranscription(
+ // appropriate browser. Returns whether the transcription result was routed
+ // successfully. Transcriptions will halt if this returns false.
+ bool DispatchTranscription(
content::WebContents* web_contents,
const chrome::mojom::TranscriptionResultPtr& transcription_result);
+ CaptionBubbleController* GetCaptionBubbleControllerForBrowser(
+ Browser* browser);
+
private:
friend class CaptionControllerFactory;
+ friend class CaptionControllerTest;
// BrowserListObserver:
void OnBrowserAdded(Browser* browser) override;
diff --git a/chromium/chrome/browser/accessibility/caption_controller_browsertest.cc b/chromium/chrome/browser/accessibility/caption_controller_browsertest.cc
new file mode 100644
index 00000000000..5b46895bc04
--- /dev/null
+++ b/chromium/chrome/browser/accessibility/caption_controller_browsertest.cc
@@ -0,0 +1,579 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/accessibility/caption_controller.h"
+
+#include "base/files/file_path.h"
+#include "build/build_config.h"
+#include "chrome/browser/accessibility/caption_controller_factory.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_window.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/caption_bubble_controller.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/sync_preferences/pref_service_syncable.h"
+#include "content/public/test/browser_test.h"
+#include "media/base/media_switches.h"
+
+namespace captions {
+
+// Blocks until a new profile is created.
+void UnblockOnProfileCreation(base::RunLoop* run_loop,
+ Profile* profile,
+ Profile::CreateStatus status) {
+ if (status == Profile::CREATE_STATUS_INITIALIZED)
+ run_loop->Quit();
+}
+
+Profile* CreateProfile() {
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ base::FilePath profile_path =
+ profile_manager->GenerateNextProfileDirectoryPath();
+ base::RunLoop run_loop;
+ profile_manager->CreateProfileAsync(
+ profile_path, base::Bind(&UnblockOnProfileCreation, &run_loop),
+ base::string16(), std::string());
+ run_loop.Run();
+ return profile_manager->GetProfileByPath(profile_path);
+}
+
+class CaptionControllerTest : public InProcessBrowserTest {
+ public:
+ CaptionControllerTest() = default;
+ ~CaptionControllerTest() override = default;
+ CaptionControllerTest(const CaptionControllerTest&) = delete;
+ CaptionControllerTest& operator=(const CaptionControllerTest&) = delete;
+
+ // InProcessBrowserTest overrides:
+ void SetUp() override {
+ scoped_feature_list_.InitAndEnableFeature(media::kLiveCaption);
+ InProcessBrowserTest::SetUp();
+ }
+
+ void SetLiveCaptionEnabled(bool enabled) {
+ browser()->profile()->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled,
+ enabled);
+ }
+
+ CaptionController* GetController() {
+ return GetControllerForBrowser(browser());
+ }
+
+ CaptionController* GetControllerForBrowser(Browser* browser) {
+ return GetControllerForProfile(browser->profile());
+ }
+
+ CaptionController* GetControllerForProfile(Profile* profile) {
+ return CaptionControllerFactory::GetForProfile(profile);
+ }
+
+ CaptionBubbleController* GetBubbleController() {
+ return GetBubbleControllerForBrowser(browser());
+ }
+
+ CaptionBubbleController* GetBubbleControllerForBrowser(Browser* browser) {
+ return GetControllerForBrowser(browser)
+ ->GetCaptionBubbleControllerForBrowser(browser);
+ }
+
+ bool DispatchTranscription(std::string text) {
+ return DispatchTranscriptionToBrowser(text, browser());
+ }
+
+ bool DispatchTranscriptionToBrowser(std::string text, Browser* browser) {
+ return DispatchTranscriptionToBrowserForProfile(text, browser,
+ browser->profile());
+ }
+
+ bool DispatchTranscriptionToBrowserForProfile(std::string text,
+ Browser* browser,
+ Profile* profile) {
+ return GetControllerForProfile(profile)->DispatchTranscription(
+ browser->tab_strip_model()->GetActiveWebContents(),
+ chrome::mojom::TranscriptionResult::New(text, true /* is_final */));
+ }
+
+ int NumBubbleControllers() {
+ return NumBubbleControllersForProfile(browser()->profile());
+ }
+
+ int NumBubbleControllersForProfile(Profile* profile) {
+ return GetControllerForProfile(profile)->caption_bubble_controllers_.size();
+ }
+
+ bool IsWidgetVisible() { return IsWidgetVisibleOnBrowser(browser()); }
+
+ bool IsWidgetVisibleOnBrowser(Browser* browser) {
+ return GetBubbleControllerForBrowser(browser)->IsWidgetVisibleForTesting();
+ }
+
+ std::string GetBubbleLabelText() {
+ return GetBubbleLabelTextOnBrowser(browser());
+ }
+
+ std::string GetBubbleLabelTextOnBrowser(Browser* browser) {
+ return GetBubbleControllerForBrowser(browser)
+ ->GetBubbleLabelTextForTesting();
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest, ProfilePrefsAreRegistered) {
+ EXPECT_FALSE(
+ browser()->profile()->GetPrefs()->GetBoolean(prefs::kLiveCaptionEnabled));
+ EXPECT_EQ(base::FilePath(),
+ browser()->profile()->GetPrefs()->GetFilePath(prefs::kSODAPath));
+}
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest,
+ ProfilePrefsAreRegistered_Incognito) {
+ // Set live caption enabled on the regular profile.
+ SetLiveCaptionEnabled(true);
+ EXPECT_TRUE(
+ browser()->profile()->GetPrefs()->GetBoolean(prefs::kLiveCaptionEnabled));
+ EXPECT_EQ(base::FilePath(),
+ browser()->profile()->GetPrefs()->GetFilePath(prefs::kSODAPath));
+
+ // Ensure that live caption is also enabled in the incognito profile.
+ Profile* incognito_profile = browser()->profile()->GetPrimaryOTRProfile();
+ EXPECT_TRUE(
+ incognito_profile->GetPrefs()->GetBoolean(prefs::kLiveCaptionEnabled));
+ EXPECT_EQ(base::FilePath(),
+ browser()->profile()->GetPrefs()->GetFilePath(prefs::kSODAPath));
+}
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest, LiveCaptionEnabledChanged) {
+ EXPECT_EQ(nullptr, GetBubbleController());
+ EXPECT_EQ(0, NumBubbleControllers());
+
+ SetLiveCaptionEnabled(true);
+ EXPECT_NE(nullptr, GetBubbleController());
+ EXPECT_EQ(1, NumBubbleControllers());
+
+ SetLiveCaptionEnabled(false);
+ EXPECT_EQ(nullptr, GetBubbleController());
+ EXPECT_EQ(0, NumBubbleControllers());
+}
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest,
+ LiveCaptionEnabledChanged_BubbleVisible) {
+ SetLiveCaptionEnabled(true);
+ // Make the bubble visible by dispatching a transcription.
+ DispatchTranscription(
+ "In Switzerland it is illegal to own just one guinea pig.");
+// The CaptionBubbleController is currently only implemented in Views.
+#if defined(TOOLKIT_VIEWS)
+ EXPECT_TRUE(IsWidgetVisible());
+#else
+ EXPECT_FALSE(IsWidgetVisible());
+#endif
+
+ SetLiveCaptionEnabled(false);
+ EXPECT_EQ(nullptr, GetBubbleController());
+ EXPECT_EQ(0, NumBubbleControllers());
+}
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnBrowserAdded) {
+ EXPECT_EQ(0, NumBubbleControllers());
+
+ // Add a new browser and then enable live caption. Test that a caption bubble
+ // controller is created.
+ CreateBrowser(browser()->profile());
+ SetLiveCaptionEnabled(true);
+ EXPECT_EQ(2, NumBubbleControllers());
+
+ // Add a new browser and test that a caption bubble controller is created.
+ CreateBrowser(browser()->profile());
+ EXPECT_EQ(3, NumBubbleControllers());
+
+ // Disable live caption. Add a new browser and test that a caption bubble
+ // controller is not created.
+ SetLiveCaptionEnabled(false);
+ CreateBrowser(browser()->profile());
+ EXPECT_EQ(0, NumBubbleControllers());
+}
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnBrowserAdded_Incognito) {
+ EXPECT_EQ(0, NumBubbleControllers());
+
+ // Add a new incognito browser and then enable live caption. Test that a
+ // caption bubble controller is created in each browser (incognito and
+ // regular).
+ CreateIncognitoBrowser();
+ SetLiveCaptionEnabled(true);
+ EXPECT_EQ(2, NumBubbleControllers());
+
+ // Add a new incognito browser and test that a caption bubble controller is
+ // created.
+ CreateIncognitoBrowser();
+ EXPECT_EQ(3, NumBubbleControllers());
+
+ // Disable live caption. Add a new incognito browser and test that a caption
+ // bubble controller is not created.
+ SetLiveCaptionEnabled(false);
+ CreateIncognitoBrowser();
+ EXPECT_EQ(0, NumBubbleControllers());
+}
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnBrowserRemoved) {
+ CaptionController* controller = GetController();
+ Browser* browser1 = browser();
+ // Add 3 browsers.
+ Browser* browser2 = CreateBrowser(browser()->profile());
+ Browser* browser3 = CreateBrowser(browser()->profile());
+ Browser* browser4 = CreateBrowser(browser()->profile());
+
+ SetLiveCaptionEnabled(true);
+ EXPECT_EQ(4, NumBubbleControllers());
+
+ // Close browser4 and test that the caption bubble controller was destroyed.
+ browser4->window()->Close();
+ ui_test_utils::WaitForBrowserToClose();
+ EXPECT_EQ(nullptr,
+ controller->GetCaptionBubbleControllerForBrowser(browser4));
+ EXPECT_EQ(3, NumBubbleControllers());
+
+ // Make the bubble on browser3 visible by dispatching a transcription.
+ DispatchTranscriptionToBrowser(
+ "If you lift a kangaroo's tail off the ground it can't hop.", browser3);
+// The CaptionBubbleController is currently only implemented in Views.
+#if defined(TOOLKIT_VIEWS)
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser3));
+#else
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(browser3));
+#endif
+ browser3->window()->Close();
+ ui_test_utils::WaitForBrowserToClose();
+ EXPECT_EQ(nullptr,
+ controller->GetCaptionBubbleControllerForBrowser(browser3));
+ EXPECT_EQ(2, NumBubbleControllers());
+
+ // Make the bubble on browser2 visible by dispatching a transcription.
+ DispatchTranscriptionToBrowser(
+ "A lion's roar can be heard from 5 miles away.", browser2);
+// The CaptionBubbleController is currently only implemented in Views.
+#if defined(TOOLKIT_VIEWS)
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser2));
+#else
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(browser2));
+#endif
+
+ // Close all browsers and verify that the caption bubbles are destroyed on
+ // the two remaining browsers.
+ chrome::CloseAllBrowsers();
+ ui_test_utils::WaitForBrowserToClose();
+ ui_test_utils::WaitForBrowserToClose();
+ EXPECT_EQ(nullptr,
+ controller->GetCaptionBubbleControllerForBrowser(browser2));
+ EXPECT_EQ(nullptr,
+ controller->GetCaptionBubbleControllerForBrowser(browser1));
+}
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnBrowserRemoved_Incognito) {
+ CaptionController* controller = GetController();
+ Browser* incognito_browser1 = CreateIncognitoBrowser();
+ Browser* incognito_browser2 = CreateIncognitoBrowser();
+
+ SetLiveCaptionEnabled(true);
+ // There is 1 regular browser and 2 incognito browsers.
+ EXPECT_EQ(3, NumBubbleControllers());
+
+ // Close incognito_browser2 and test that the caption bubble controller was
+ // destroyed.
+ incognito_browser2->window()->Close();
+ ui_test_utils::WaitForBrowserToClose();
+ EXPECT_EQ(nullptr, controller->GetCaptionBubbleControllerForBrowser(
+ incognito_browser2));
+ EXPECT_EQ(2, NumBubbleControllers());
+
+ // Make the bubble on incognito_browser1 visible by dispatching a
+ // transcription.
+ DispatchTranscriptionToBrowser(
+ "If you lift a kangaroo's tail off the ground it can't hop.",
+ incognito_browser1);
+// The CaptionBubbleController is currently only implemented in Views.
+#if defined(TOOLKIT_VIEWS)
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(incognito_browser1));
+#else
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(incognito_browser1));
+#endif
+ incognito_browser1->window()->Close();
+ ui_test_utils::WaitForBrowserToClose();
+ EXPECT_EQ(nullptr, controller->GetCaptionBubbleControllerForBrowser(
+ incognito_browser1));
+ EXPECT_EQ(1, NumBubbleControllers());
+}
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest, DispatchTranscription) {
+ bool success = DispatchTranscription("A baby spider is called a spiderling.");
+ EXPECT_FALSE(success);
+ EXPECT_EQ(0, NumBubbleControllers());
+
+ SetLiveCaptionEnabled(true);
+ success = DispatchTranscription(
+ "A baby octopus is about the size of a flea when it is born.");
+ EXPECT_TRUE(success);
+// The CaptionBubbleController is currently only implemented in Views.
+#if defined(TOOLKIT_VIEWS)
+ EXPECT_TRUE(IsWidgetVisible());
+ EXPECT_EQ("A baby octopus is about the size of a flea when it is born.",
+ GetBubbleLabelText());
+#else
+ EXPECT_FALSE(IsWidgetVisible());
+#endif
+
+ SetLiveCaptionEnabled(false);
+ success = DispatchTranscription(
+ "Approximately 10-20% of power outages in the US are caused by "
+ "squirrels.");
+ EXPECT_FALSE(success);
+ EXPECT_EQ(0, NumBubbleControllers());
+}
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest,
+ DispatchTranscription_MultipleBrowsers) {
+ Browser* browser1 = browser();
+ Browser* browser2 = CreateBrowser(browser()->profile());
+ Browser* incognito_browser = CreateIncognitoBrowser();
+ SetLiveCaptionEnabled(true);
+
+ // Dispatch transcription routes the transcription to the right browser.
+ bool success = DispatchTranscriptionToBrowser(
+ "Honeybees can recognize human faces.", browser1);
+ EXPECT_TRUE(success);
+// The CaptionBubbleController is currently only implemented in Views.
+#if defined(TOOLKIT_VIEWS)
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser1));
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(browser2));
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(incognito_browser));
+ EXPECT_EQ("Honeybees can recognize human faces.",
+ GetBubbleLabelTextOnBrowser(browser1));
+ EXPECT_EQ("", GetBubbleLabelTextOnBrowser(browser2));
+ EXPECT_EQ("", GetBubbleLabelTextOnBrowser(incognito_browser));
+#else
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(browser1));
+#endif
+
+ success = DispatchTranscriptionToBrowser(
+ "A blue whale's heart is the size of a small car.", browser2);
+ EXPECT_TRUE(success);
+// The CaptionBubbleController is currently only implemented in Views.
+#if defined(TOOLKIT_VIEWS)
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser1));
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser2));
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(incognito_browser));
+ EXPECT_EQ("A blue whale's heart is the size of a small car.",
+ GetBubbleLabelTextOnBrowser(browser2));
+ EXPECT_EQ("Honeybees can recognize human faces.",
+ GetBubbleLabelTextOnBrowser(browser1));
+ EXPECT_EQ("", GetBubbleLabelTextOnBrowser(incognito_browser));
+#else
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(browser2));
+#endif
+
+ success = DispatchTranscriptionToBrowser(
+ "Squirrels forget where they hide about half of their nuts.",
+ incognito_browser);
+ EXPECT_TRUE(success);
+// The CaptionBubbleController is currently only implemented in Views.
+#if defined(TOOLKIT_VIEWS)
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser1));
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser2));
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(incognito_browser));
+ EXPECT_EQ("A blue whale's heart is the size of a small car.",
+ GetBubbleLabelTextOnBrowser(browser2));
+ EXPECT_EQ("Honeybees can recognize human faces.",
+ GetBubbleLabelTextOnBrowser(browser1));
+ EXPECT_EQ("Squirrels forget where they hide about half of their nuts.",
+ GetBubbleLabelTextOnBrowser(incognito_browser));
+#else
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(incognito_browser));
+#endif
+}
+
+#if !defined(OS_CHROMEOS) // No multi-profile on ChromeOS.
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest,
+ LiveCaptionEnabledChanged_MultipleProfiles) {
+ Profile* profile1 = browser()->profile();
+ Profile* profile2 = CreateProfile();
+ CreateBrowser(profile2);
+
+ // The profiles start with no caption bubble controllers.
+ EXPECT_EQ(0, NumBubbleControllersForProfile(profile1));
+ EXPECT_EQ(0, NumBubbleControllersForProfile(profile2));
+
+ // Enable live caption on profile1.
+ SetLiveCaptionEnabled(true);
+ EXPECT_EQ(1, NumBubbleControllersForProfile(profile1));
+ EXPECT_EQ(0, NumBubbleControllersForProfile(profile2));
+
+ // Enable live caption on profile2.
+ profile2->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, true);
+ EXPECT_EQ(1, NumBubbleControllersForProfile(profile1));
+ EXPECT_EQ(1, NumBubbleControllersForProfile(profile2));
+
+ // Disable live caption on profile1.
+ SetLiveCaptionEnabled(false);
+ EXPECT_EQ(0, NumBubbleControllersForProfile(profile1));
+ EXPECT_EQ(1, NumBubbleControllersForProfile(profile2));
+
+ // Disable live caption on profile2.
+ profile2->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, false);
+ EXPECT_EQ(0, NumBubbleControllersForProfile(profile1));
+ EXPECT_EQ(0, NumBubbleControllersForProfile(profile2));
+}
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest, OnBrowserAdded_MultipleProfiles) {
+ Profile* profile1 = browser()->profile();
+ Profile* profile2 = CreateProfile();
+
+ // Enable live caption on both profiles.
+ SetLiveCaptionEnabled(true);
+ profile2->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, true);
+
+ // Add a new browser to profile1. Test that there are caption bubble
+ // controllers on all of the existing browsers.
+ CreateBrowser(profile1);
+ EXPECT_EQ(2, NumBubbleControllersForProfile(profile1));
+ EXPECT_EQ(0, NumBubbleControllersForProfile(profile2));
+
+ // Add a new browser to profile 2. Test that a caption bubble controller is
+ // created in profile2 and not in profile1.
+ Browser* profile2_browser2 = CreateBrowser(profile2);
+ EXPECT_NE(
+ nullptr,
+ GetControllerForProfile(profile2)->GetCaptionBubbleControllerForBrowser(
+ profile2_browser2));
+ EXPECT_EQ(
+ nullptr,
+ GetControllerForProfile(profile1)->GetCaptionBubbleControllerForBrowser(
+ profile2_browser2));
+ EXPECT_EQ(2, NumBubbleControllersForProfile(profile1));
+ EXPECT_EQ(1, NumBubbleControllersForProfile(profile2));
+
+ // Disable live caption on profile1. Add a new browser to both profiles, and
+ // test that a caption bubble controller is only created on profile2.
+ SetLiveCaptionEnabled(false);
+ EXPECT_EQ(0, NumBubbleControllersForProfile(profile1));
+ EXPECT_EQ(1, NumBubbleControllersForProfile(profile2));
+ CreateBrowser(profile1);
+ CreateBrowser(profile2);
+ EXPECT_EQ(0, NumBubbleControllersForProfile(profile1));
+ EXPECT_EQ(2, NumBubbleControllersForProfile(profile2));
+}
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest,
+ OnBrowserRemoved_MultipleProfiles) {
+ Profile* profile1 = browser()->profile();
+ Profile* profile2 = CreateProfile();
+ Browser* browser1 = browser();
+ Browser* browser2 = CreateBrowser(profile2);
+ CaptionController* controller1 = GetControllerForProfile(profile1);
+ CaptionController* controller2 = GetControllerForProfile(profile2);
+
+ // Enable live caption on both profiles.
+ SetLiveCaptionEnabled(true);
+ profile2->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, true);
+ EXPECT_EQ(1, NumBubbleControllersForProfile(profile1));
+ EXPECT_EQ(1, NumBubbleControllersForProfile(profile2));
+
+ // Close browser2 and test that the caption bubble controller was destroyed.
+ browser2->window()->Close();
+ ui_test_utils::WaitForBrowserToClose();
+ EXPECT_EQ(nullptr,
+ controller2->GetCaptionBubbleControllerForBrowser(browser2));
+ EXPECT_EQ(1, NumBubbleControllersForProfile(profile1));
+ EXPECT_EQ(0, NumBubbleControllersForProfile(profile2));
+
+ // Make the bubble on incognito_browser1 visible by dispatching a
+ // transcription.
+ DispatchTranscriptionToBrowser(
+ "If you lift a kangaroo's tail off the ground it can't hop.", browser1);
+// The CaptionBubbleController is currently only implemented in Views.
+#if defined(TOOLKIT_VIEWS)
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser1));
+#else
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(browser1));
+#endif
+ browser1->window()->Close();
+ ui_test_utils::WaitForBrowserToClose();
+ EXPECT_EQ(nullptr,
+ controller1->GetCaptionBubbleControllerForBrowser(browser1));
+ EXPECT_EQ(0, NumBubbleControllersForProfile(profile1));
+ EXPECT_EQ(0, NumBubbleControllersForProfile(profile2));
+}
+
+IN_PROC_BROWSER_TEST_F(CaptionControllerTest,
+ DispatchTranscription_MultipleProfiles) {
+ Profile* profile1 = browser()->profile();
+ Profile* profile2 = CreateProfile();
+ Browser* browser1 = browser();
+ Browser* browser2 = CreateBrowser(profile2);
+
+ // Enable live caption on both profiles.
+ SetLiveCaptionEnabled(true);
+ profile2->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, true);
+
+ // Dispatch transcription routes the transcription to the right browser on the
+ // right profile.
+ bool success = DispatchTranscriptionToBrowserForProfile(
+ "Only female mosquitos bite.", browser1, profile1);
+ EXPECT_TRUE(success);
+// The CaptionBubbleController is currently only implemented in Views.
+#if defined(TOOLKIT_VIEWS)
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser1));
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(browser2));
+ EXPECT_EQ("Only female mosquitos bite.",
+ GetBubbleLabelTextOnBrowser(browser1));
+ EXPECT_EQ("", GetBubbleLabelTextOnBrowser(browser2));
+#else
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(browser1));
+#endif
+
+ success = DispatchTranscriptionToBrowserForProfile(
+ "Mosquitos were around at the time of the dinosaurs.", browser2,
+ profile2);
+ EXPECT_TRUE(success);
+// The CaptionBubbleController is currently only implemented in Views.
+#if defined(TOOLKIT_VIEWS)
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser1));
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser2));
+ EXPECT_EQ("Only female mosquitos bite.",
+ GetBubbleLabelTextOnBrowser(browser1));
+ EXPECT_EQ("Mosquitos were around at the time of the dinosaurs.",
+ GetBubbleLabelTextOnBrowser(browser2));
+#else
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(browser1));
+#endif
+
+ // Dispatch transcription returns false for browsers on different profiles.
+ success = DispatchTranscriptionToBrowserForProfile(
+ "There are over 3000 species of mosquitos.", browser1, profile2);
+ EXPECT_FALSE(success);
+// The CaptionBubbleController is currently only implemented in Views.
+#if defined(TOOLKIT_VIEWS)
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser1));
+ EXPECT_TRUE(IsWidgetVisibleOnBrowser(browser2));
+ EXPECT_EQ("Only female mosquitos bite.",
+ GetBubbleLabelTextOnBrowser(browser1));
+ EXPECT_EQ("Mosquitos were around at the time of the dinosaurs.",
+ GetBubbleLabelTextOnBrowser(browser2));
+#else
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(browser1));
+ EXPECT_FALSE(IsWidgetVisibleOnBrowser(browser2));
+#endif
+}
+
+#endif // !defined (OS_CHROMEOS)
+
+} // namespace captions
diff --git a/chromium/chrome/browser/accessibility/caption_host_impl.cc b/chromium/chrome/browser/accessibility/caption_host_impl.cc
index f16d93d566a..deaa6ec6554 100644
--- a/chromium/chrome/browser/accessibility/caption_host_impl.cc
+++ b/chromium/chrome/browser/accessibility/caption_host_impl.cc
@@ -40,21 +40,28 @@ CaptionHostImpl::CaptionHostImpl(content::RenderFrameHost* frame_host)
CaptionHostImpl::~CaptionHostImpl() = default;
void CaptionHostImpl::OnTranscription(
- chrome::mojom::TranscriptionResultPtr transcription_result) {
- if (!frame_host_)
+ chrome::mojom::TranscriptionResultPtr transcription_result,
+ OnTranscriptionCallback reply) {
+ if (!frame_host_) {
+ std::move(reply).Run(false);
return;
+ }
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(frame_host_);
if (!web_contents) {
frame_host_ = nullptr;
+ std::move(reply).Run(false);
return;
}
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
- if (!profile)
+ if (!profile) {
+ std::move(reply).Run(false);
return;
- CaptionControllerFactory::GetForProfile(profile)->DispatchTranscription(
- web_contents, transcription_result);
+ }
+ std::move(reply).Run(
+ CaptionControllerFactory::GetForProfile(profile)->DispatchTranscription(
+ web_contents, transcription_result));
}
void CaptionHostImpl::RenderFrameDeleted(content::RenderFrameHost* frame_host) {
diff --git a/chromium/chrome/browser/accessibility/caption_host_impl.h b/chromium/chrome/browser/accessibility/caption_host_impl.h
index 0445179620f..3e3615e6c2d 100644
--- a/chromium/chrome/browser/accessibility/caption_host_impl.h
+++ b/chromium/chrome/browser/accessibility/caption_host_impl.h
@@ -38,7 +38,8 @@ class CaptionHostImpl : public chrome::mojom::CaptionHost,
// chrome::mojom::CaptionHost:
void OnTranscription(
- chrome::mojom::TranscriptionResultPtr transcription_result) override;
+ chrome::mojom::TranscriptionResultPtr transcription_result,
+ OnTranscriptionCallback reply) override;
// content::WebContentsObserver:
void RenderFrameDeleted(content::RenderFrameHost* frame_host) override;
diff --git a/chromium/chrome/browser/accessibility/image_annotation_browsertest.cc b/chromium/chrome/browser/accessibility/image_annotation_browsertest.cc
index e979f31f2e4..70fbc9c17e3 100644
--- a/chromium/chrome/browser/accessibility/image_annotation_browsertest.cc
+++ b/chromium/chrome/browser/accessibility/image_annotation_browsertest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <map>
+
#include "base/bind_helpers.h"
#include "base/check.h"
#include "base/feature_list.h"
@@ -34,13 +36,14 @@
#include "services/image_annotation/public/mojom/image_annotation.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/accessibility_features.h"
#include "ui/accessibility/ax_enum_util.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_tree.h"
#include "url/gurl.h"
constexpr base::FilePath::CharType kDocRoot[] =
- FILE_PATH_LITERAL("chrome/test/data/accessibility");
+ FILE_PATH_LITERAL("chrome/test/data");
namespace {
@@ -49,8 +52,13 @@ void DescribeNodesWithAnnotations(const ui::AXNode& node,
std::string annotation =
node.GetStringAttribute(ax::mojom::StringAttribute::kImageAnnotation);
if (!annotation.empty()) {
- descriptions->push_back(ui::ToString(node.data().role) + std::string(" ") +
- annotation);
+ std::string role_str = ui::ToString(node.data().role);
+ std::string name =
+ node.GetStringAttribute(ax::mojom::StringAttribute::kName);
+ if (!name.empty() && node.data().role != ax::mojom::Role::kRootWebArea)
+ descriptions->push_back(role_str + " " + name + " " + annotation);
+ else
+ descriptions->push_back(role_str + " " + annotation);
}
for (const auto* child : node.children())
DescribeNodesWithAnnotations(*child, descriptions);
@@ -58,10 +66,11 @@ void DescribeNodesWithAnnotations(const ui::AXNode& node,
std::vector<std::string> DescribeNodesWithAnnotations(
const ui::AXTreeUpdate& tree_update) {
- ui::AXTree tree(tree_update);
std::vector<std::string> descriptions;
- DCHECK(tree.root());
- DescribeNodesWithAnnotations(*tree.root(), &descriptions);
+ if (tree_update.root_id) {
+ ui::AXTree tree(tree_update);
+ DescribeNodesWithAnnotations(*tree.root(), &descriptions);
+ }
return descriptions;
}
@@ -87,6 +96,11 @@ class FakeAnnotator : public image_annotation::mojom::Annotator {
return_label_results_ = label;
}
+ static void AddCustomLabelResultMapping(const std::string& filename,
+ const std::string& label) {
+ custom_label_result_mapping_[filename] = label;
+ }
+
static void SetReturnErrorCode(
image_annotation::mojom::AnnotateImageError error_code) {
return_error_code_ = error_code;
@@ -114,19 +128,25 @@ class FakeAnnotator : public image_annotation::mojom::Annotator {
return;
}
- // Use the filename to create an annotation string.
- // Adds some trailing whitespace and punctuation to check that clean-up
- // happens correctly when combining annotation strings.
+ // Use the filename to create annotation strings. Check a map from filename
+ // to desired label, otherwise just construct a string based on the
+ // filename. Adds some trailing whitespace and punctuation to check that
+ // clean-up happens correctly when combining annotation strings.
std::string image_filename = GURL(image_id).ExtractFileName();
+ std::string label_text;
+ if (base::Contains(custom_label_result_mapping_, image_filename)) {
+ label_text = custom_label_result_mapping_[image_filename];
+ } else {
+ label_text = image_filename + " '" + description_language_tag + "' Label";
+ }
+ std::string ocr_text = image_filename + " Annotation . ";
+
image_annotation::mojom::AnnotationPtr ocr_annotation =
image_annotation::mojom::Annotation::New(
- image_annotation::mojom::AnnotationType::kOcr, 1.0,
- image_filename + " Annotation . ");
-
+ image_annotation::mojom::AnnotationType::kOcr, 1.0, ocr_text);
image_annotation::mojom::AnnotationPtr label_annotation =
image_annotation::mojom::Annotation::New(
- image_annotation::mojom::AnnotationType::kLabel, 1.0,
- image_filename + " '" + description_language_tag + "' Label");
+ image_annotation::mojom::AnnotationType::kLabel, 1.0, label_text);
// Return enabled results as an annotation.
std::vector<image_annotation::mojom::AnnotationPtr> annotations;
@@ -145,6 +165,7 @@ class FakeAnnotator : public image_annotation::mojom::Annotator {
mojo::ReceiverSet<image_annotation::mojom::Annotator> receivers_;
static bool return_ocr_results_;
static bool return_label_results_;
+ static std::map<std::string, std::string> custom_label_result_mapping_;
static base::Optional<image_annotation::mojom::AnnotateImageError>
return_error_code_;
@@ -156,6 +177,8 @@ bool FakeAnnotator::return_ocr_results_ = false;
// static
bool FakeAnnotator::return_label_results_ = false;
// static
+std::map<std::string, std::string> FakeAnnotator::custom_label_result_mapping_;
+// static
base::Optional<image_annotation::mojom::AnnotateImageError>
FakeAnnotator::return_error_code_;
@@ -197,8 +220,10 @@ class ImageAnnotationBrowserTest : public InProcessBrowserTest {
protected:
void SetUp() override {
- scoped_feature_list_.InitAndEnableFeature(
- features::kExperimentalAccessibilityLabels);
+ scoped_feature_list_.InitWithFeatures(
+ std::vector<base::Feature>({features::kExperimentalAccessibilityLabels,
+ features::kAugmentExistingImageLabels}),
+ std::vector<base::Feature>({}));
InProcessBrowserTest::SetUp();
}
@@ -252,8 +277,8 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest,
AnnotateImageInAccessibilityTree) {
FakeAnnotator::SetReturnOcrResults(true);
FakeAnnotator::SetReturnLabelResults(true);
- ui_test_utils::NavigateToURL(browser(),
- https_server_.GetURL("/image_annotation.html"));
+ ui_test_utils::NavigateToURL(
+ browser(), https_server_.GetURL("/accessibility/image_annotation.html"));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
@@ -266,7 +291,8 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest,
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImagesInLinks) {
FakeAnnotator::SetReturnOcrResults(true);
ui_test_utils::NavigateToURL(
- browser(), https_server_.GetURL("/image_annotation_link.html"));
+ browser(),
+ https_server_.GetURL("/accessibility/image_annotation_link.html"));
// Block until the accessibility tree has at least 8 annotations. If
// that never happens, the test will time out.
@@ -296,10 +322,71 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImagesInLinks) {
"image Appears to say: green.png Annotation"));
}
+IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, AugmentImageNames) {
+ FakeAnnotator::SetReturnLabelResults(true);
+ FakeAnnotator::AddCustomLabelResultMapping("frog.jpg", "Tadpole");
+ FakeAnnotator::AddCustomLabelResultMapping("train.png", "Locomotive");
+ FakeAnnotator::AddCustomLabelResultMapping("cloud.png", "Cumulonimbus");
+ FakeAnnotator::AddCustomLabelResultMapping("goat.jpg", "Billy goat");
+ FakeAnnotator::AddCustomLabelResultMapping("dog.jpg", "Puppy");
+
+ ui_test_utils::NavigateToURL(
+ browser(),
+ https_server_.GetURL("/accessibility/image_annotation_augment.html"));
+
+ // Block until the accessibility tree has at least 5 annotations. If
+ // that never happens, the test will time out.
+ content::WebContents* web_contents =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ while (5 > DescribeNodesWithAnnotations(
+ content::GetAccessibilityTreeSnapshot(web_contents))
+ .size()) {
+ content::WaitForAccessibilityTreeToChange(web_contents);
+ }
+
+ ui::AXTreeUpdate ax_tree_update =
+ content::GetAccessibilityTreeSnapshot(web_contents);
+ EXPECT_THAT(DescribeNodesWithAnnotations(ax_tree_update),
+ testing::ElementsAre(
+ "image the Appears to be: Tadpole",
+ "image photo background Appears to be: Locomotive",
+ "image 12345678.jpg Appears to be: Cumulonimbus",
+ "image Sunday, Feb 6, 1966 Appears to be: Billy goat",
+ "image fotografia bianca e nero Appears to be: Puppy"));
+}
+
+IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, AugmentImageNamesInLinks) {
+ FakeAnnotator::SetReturnLabelResults(true);
+ FakeAnnotator::AddCustomLabelResultMapping("frog.jpg", "Tadpole");
+ FakeAnnotator::AddCustomLabelResultMapping("train.png", "Locomotive");
+
+ ui_test_utils::NavigateToURL(
+ browser(), https_server_.GetURL(
+ "/accessibility/image_annotation_augment_links.html"));
+
+ // Block until the accessibility tree has at least 3 annotations. If
+ // that never happens, the test will time out.
+ content::WebContents* web_contents =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ ui::AXTreeUpdate ax_tree_update =
+ content::GetAccessibilityTreeSnapshot(web_contents);
+ while (3 > DescribeNodesWithAnnotations(ax_tree_update).size()) {
+ content::WaitForAccessibilityTreeToChange(web_contents);
+ ax_tree_update = content::GetAccessibilityTreeSnapshot(web_contents);
+ }
+
+ EXPECT_THAT(
+ DescribeNodesWithAnnotations(ax_tree_update),
+ testing::ElementsAre("link photo background Appears to be: Locomotive",
+ "image photo background Appears to be: Locomotive",
+ "image the Appears to be: Tadpole"));
+}
+
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImageDoc) {
FakeAnnotator::SetReturnOcrResults(true);
ui_test_utils::NavigateToURL(
- browser(), https_server_.GetURL("/image_annotation_doc.html"));
+ browser(),
+ https_server_.GetURL("/accessibility/image_annotation_doc.html"));
// Block until the accessibility tree has at least 2 annotations. If
// that never happens, the test will time out.
@@ -323,7 +410,8 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImageDoc) {
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImageUrl) {
FakeAnnotator::SetReturnOcrResults(true);
- ui_test_utils::NavigateToURL(browser(), https_server_.GetURL("/red.png"));
+ ui_test_utils::NavigateToURL(browser(),
+ https_server_.GetURL("/accessibility/red.png"));
// Block until the accessibility tree has at least 2 annotations. If
// that never happens, the test will time out.
@@ -351,7 +439,8 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, NoAnnotationsAvailable) {
FakeAnnotator::SetReturnLabelResults(false);
ui_test_utils::NavigateToURL(
- browser(), https_server_.GetURL("/image_annotation_doc.html"));
+ browser(),
+ https_server_.GetURL("/accessibility/image_annotation_doc.html"));
// Block until the annotation status for the root is empty. If that
// never occurs then the test will time out.
@@ -359,8 +448,9 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, NoAnnotationsAvailable) {
browser()->tab_strip_model()->GetActiveWebContents();
ui::AXTreeUpdate snapshot =
content::GetAccessibilityTreeSnapshot(web_contents);
- while (snapshot.nodes[0].GetImageAnnotationStatus() !=
- ax::mojom::ImageAnnotationStatus::kAnnotationEmpty) {
+ while (snapshot.nodes.empty() ||
+ snapshot.nodes[0].GetImageAnnotationStatus() !=
+ ax::mojom::ImageAnnotationStatus::kAnnotationEmpty) {
content::WaitForAccessibilityTreeToChange(web_contents);
snapshot = content::GetAccessibilityTreeSnapshot(web_contents);
}
@@ -372,7 +462,8 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, AnnotationError) {
image_annotation::mojom::AnnotateImageError::kFailure);
ui_test_utils::NavigateToURL(
- browser(), https_server_.GetURL("/image_annotation_doc.html"));
+ browser(),
+ https_server_.GetURL("/accessibility/image_annotation_doc.html"));
// Block until the annotation status for the root contains an error code. If
// that never occurs then the test will time out.
@@ -380,8 +471,9 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, AnnotationError) {
browser()->tab_strip_model()->GetActiveWebContents();
ui::AXTreeUpdate snapshot =
content::GetAccessibilityTreeSnapshot(web_contents);
- while (snapshot.nodes[0].GetImageAnnotationStatus() !=
- ax::mojom::ImageAnnotationStatus::kAnnotationProcessFailed) {
+ while (snapshot.nodes.empty() ||
+ snapshot.nodes[0].GetImageAnnotationStatus() !=
+ ax::mojom::ImageAnnotationStatus::kAnnotationProcessFailed) {
content::WaitForAccessibilityTreeToChange(web_contents);
snapshot = content::GetAccessibilityTreeSnapshot(web_contents);
}
@@ -390,8 +482,8 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, AnnotationError) {
IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, ImageWithSrcSet) {
FakeAnnotator::SetReturnOcrResults(true);
FakeAnnotator::SetReturnLabelResults(true);
- ui_test_utils::NavigateToURL(browser(),
- https_server_.GetURL("/image_srcset.html"));
+ ui_test_utils::NavigateToURL(
+ browser(), https_server_.GetURL("/accessibility/image_srcset.html"));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
@@ -406,8 +498,8 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest,
FakeAnnotator::SetReturnOcrResults(true);
FakeAnnotator::SetReturnLabelResults(true);
- ui_test_utils::NavigateToURL(browser(),
- https_server_.GetURL("/image_annotation.html"));
+ ui_test_utils::NavigateToURL(
+ browser(), https_server_.GetURL("/accessibility/image_annotation.html"));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WaitForAccessibilityTreeToContainNodeWithName(
@@ -415,8 +507,8 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest,
"Appears to say: red.png Annotation. Appears to be: red.png 'en' Label");
SetAcceptLanguages("fr,en");
- ui_test_utils::NavigateToURL(browser(),
- https_server_.GetURL("/image_annotation.html"));
+ ui_test_utils::NavigateToURL(
+ browser(), https_server_.GetURL("/accessibility/image_annotation.html"));
web_contents = browser()->tab_strip_model()->GetActiveWebContents();
content::WaitForAccessibilityTreeToContainNodeWithName(
web_contents,
@@ -466,8 +558,8 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest,
FakeAnnotator::SetReturnLabelResults(false);
// The following test page should have at least two images on it.
- ui_test_utils::NavigateToURL(browser(),
- https_server_.GetURL("/image_annotation.html"));
+ ui_test_utils::NavigateToURL(
+ browser(), https_server_.GetURL("/accessibility/image_annotation.html"));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
@@ -504,7 +596,8 @@ IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest,
// The following test page should have at least two images on it.
ui_test_utils::NavigateToURL(
- browser(), https_server_.GetURL("/image_annotation_link.html"));
+ browser(),
+ https_server_.GetURL("/accessibility/image_annotation_link.html"));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();