blob: 0bd4be0e8c4e089faff4578bd4b57ba0a2371049 [file] [log] [blame]
// Copyright (c) 2013 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 <atk/atk.h>
#include <stddef.h>
#include "build/build_config.h"
#include "chrome/browser/devtools/devtools_window_testing.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tab_modal_confirm_dialog.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/accessibility/platform/ax_platform_node_base.h"
#include "ui/views/accessibility/view_accessibility.h"
class AuraLinuxAccessibilityInProcessBrowserTest : public InProcessBrowserTest {
protected:
AuraLinuxAccessibilityInProcessBrowserTest()
: ax_mode_setter_(ui::kAXModeComplete) {}
AuraLinuxAccessibilityInProcessBrowserTest(
const AuraLinuxAccessibilityInProcessBrowserTest&) = delete;
AuraLinuxAccessibilityInProcessBrowserTest& operator=(
const AuraLinuxAccessibilityInProcessBrowserTest&) = delete;
void VerifyEmbedRelationships();
private:
ui::testing::ScopedAxModeSetter ax_mode_setter_;
};
IN_PROC_BROWSER_TEST_F(AuraLinuxAccessibilityInProcessBrowserTest,
IndexInParent) {
AtkObject* native_view_accessible =
static_cast<BrowserView*>(browser()->window())->GetNativeViewAccessible();
EXPECT_NE(nullptr, native_view_accessible);
int n_children = atk_object_get_n_accessible_children(native_view_accessible);
for (int i = 0; i < n_children; i++) {
AtkObject* child =
atk_object_ref_accessible_child(native_view_accessible, i);
int index_in_parent = atk_object_get_index_in_parent(child);
ASSERT_NE(-1, index_in_parent);
ASSERT_EQ(i, index_in_parent);
g_object_unref(child);
}
}
class TestTabModalConfirmDialogDelegate : public TabModalConfirmDialogDelegate {
public:
explicit TestTabModalConfirmDialogDelegate(content::WebContents* contents)
: TabModalConfirmDialogDelegate(contents) {}
TestTabModalConfirmDialogDelegate(const TestTabModalConfirmDialogDelegate&) =
delete;
TestTabModalConfirmDialogDelegate& operator=(
const TestTabModalConfirmDialogDelegate&) = delete;
std::u16string GetTitle() override { return u"Dialog Title"; }
std::u16string GetDialogMessage() override { return std::u16string(); }
};
// Open a tab-modal dialog and test IndexInParent with the modal dialog.
IN_PROC_BROWSER_TEST_F(AuraLinuxAccessibilityInProcessBrowserTest,
IndexInParentWithModal) {
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
AtkObject* native_view_accessible =
browser_view->GetWidget()->GetRootView()->GetNativeViewAccessible();
EXPECT_NE(nullptr, native_view_accessible);
// The root view has a child that is a client role for Chromium.
int n_children = atk_object_get_n_accessible_children(native_view_accessible);
ASSERT_EQ(1, n_children);
AtkObject* client =
atk_object_ref_accessible_child(native_view_accessible, 0);
ASSERT_EQ(0, atk_object_get_index_in_parent(client));
// Opens a tab-modal dialog.
content::WebContents* contents = browser_view->GetActiveWebContents();
auto delegate = std::make_unique<TestTabModalConfirmDialogDelegate>(contents);
TabModalConfirmDialog* dialog =
TabModalConfirmDialog::Create(std::move(delegate), contents);
// The root view still has one child that is a dialog role since if it has a
// modal dialog it hides the rest of the children.
n_children = atk_object_get_n_accessible_children(native_view_accessible);
ASSERT_EQ(1, n_children);
AtkObject* dialog_node =
atk_object_ref_accessible_child(native_view_accessible, 0);
ASSERT_EQ(0, atk_object_get_index_in_parent(dialog_node));
// The client has an invalid value for the index in parent since it's hidden
// by the dialog.
ASSERT_EQ(-1, atk_object_get_index_in_parent(client));
dialog->CloseDialog();
// It has a valid value for the client after the dialog is closed.
ASSERT_EQ(0, atk_object_get_index_in_parent(client));
g_object_unref(client);
g_object_unref(dialog_node);
}
static AtkObject* FindParentFrame(AtkObject* object) {
while (object) {
if (atk_object_get_role(object) == ATK_ROLE_FRAME)
return object;
object = atk_object_get_parent(object);
}
return nullptr;
}
void AuraLinuxAccessibilityInProcessBrowserTest::VerifyEmbedRelationships() {
AtkObject* native_view_accessible =
static_cast<BrowserView*>(browser()->window())->GetNativeViewAccessible();
EXPECT_NE(nullptr, native_view_accessible);
AtkObject* window = FindParentFrame(native_view_accessible);
EXPECT_NE(nullptr, window);
AtkRelationSet* relations = atk_object_ref_relation_set(window);
ASSERT_TRUE(atk_relation_set_contains(relations, ATK_RELATION_EMBEDS));
AtkRelation* embeds_relation =
atk_relation_set_get_relation_by_type(relations, ATK_RELATION_EMBEDS);
EXPECT_NE(nullptr, embeds_relation);
GPtrArray* targets = atk_relation_get_target(embeds_relation);
EXPECT_NE(nullptr, targets);
EXPECT_EQ(1u, targets->len);
AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targets, 0));
EXPECT_NE(nullptr, target);
content::WebContents* active_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_EQ(target, active_web_contents->GetRenderWidgetHostView()
->GetNativeViewAccessible());
g_object_unref(relations);
relations = atk_object_ref_relation_set(target);
ASSERT_TRUE(atk_relation_set_contains(relations, ATK_RELATION_EMBEDDED_BY));
AtkRelation* embedded_by_relation = atk_relation_set_get_relation_by_type(
relations, ATK_RELATION_EMBEDDED_BY);
EXPECT_NE(nullptr, embedded_by_relation);
targets = atk_relation_get_target(embedded_by_relation);
EXPECT_NE(nullptr, targets);
EXPECT_EQ(1u, targets->len);
target = static_cast<AtkObject*>(g_ptr_array_index(targets, 0));
ASSERT_EQ(target, window);
g_object_unref(relations);
}
IN_PROC_BROWSER_TEST_F(AuraLinuxAccessibilityInProcessBrowserTest,
EmbeddedRelationship) {
// Force the creation of the document's native object which sets up the
// relationship.
content::WebContents* active_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_NE(nullptr, active_web_contents->GetRenderWidgetHostView()
->GetNativeViewAccessible());
GURL url(url::kAboutBlankURL);
ASSERT_TRUE(AddTabAtIndex(0, url, ui::PAGE_TRANSITION_LINK));
EXPECT_EQ(2, browser()->tab_strip_model()->count());
EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
VerifyEmbedRelationships();
browser()->tab_strip_model()->ActivateTabAt(1);
EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
VerifyEmbedRelationships();
browser()->tab_strip_model()->ActivateTabAt(0);
EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
VerifyEmbedRelationships();
}
// Tests that the embedded relationship is set on the main web contents when
// the DevTools is opened.
// This fails on Linux : http://crbug.com/1223047
#if BUILDFLAG(IS_LINUX)
#define MAYBE_EmbeddedRelationshipWithDevTools \
DISABLED_EmbeddedRelationshipWithDevTools
#else
#define MAYBE_EmbeddedRelationshipWithDevTools EmbeddedRelationshipWithDevTools
#endif
IN_PROC_BROWSER_TEST_F(AuraLinuxAccessibilityInProcessBrowserTest,
MAYBE_EmbeddedRelationshipWithDevTools) {
// Force the creation of the document's native object which sets up the
// relationship.
content::WebContents* active_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_NE(nullptr, active_web_contents->GetRenderWidgetHostView()
->GetNativeViewAccessible());
EXPECT_EQ(1, browser()->tab_strip_model()->count());
EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
// Opens DevTools docked.
DevToolsWindow* devtools =
DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), true);
VerifyEmbedRelationships();
// Closes the DevTools window.
DevToolsWindowTesting::CloseDevToolsWindowSync(devtools);
VerifyEmbedRelationships();
// Opens DevTools in a separate window.
devtools = DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), false);
VerifyEmbedRelationships();
// Closes the DevTools window.
DevToolsWindowTesting::CloseDevToolsWindowSync(devtools);
VerifyEmbedRelationships();
}
// Tests that it doesn't have DCHECK() error when GetIndexInParent() is called
// with the WebView.
IN_PROC_BROWSER_TEST_F(AuraLinuxAccessibilityInProcessBrowserTest,
GetIndexInParent) {
content::WebContents* active_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_NE(nullptr, active_web_contents->GetRenderWidgetHostView()
->GetNativeViewAccessible());
EXPECT_EQ(1, browser()->tab_strip_model()->count());
EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
views::WebView* webview = browser_view->contents_web_view();
gfx::NativeViewAccessible accessible =
webview->GetViewAccessibility().GetNativeObject();
// Gets the index in its parents for the WebView.
absl::optional<int> index =
static_cast<ui::AXPlatformNodeBase*>(
ui::AXPlatformNode::FromNativeViewAccessible(accessible))
->GetIndexInParent();
// As the WebView is not exposed in the child list when it has the web
// content, it doesn't have the index in its parent.
EXPECT_EQ(false, index.has_value());
}