diff options
author | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-13 21:16:29 +0000 |
---|---|---|
committer | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-13 21:16:29 +0000 |
commit | 3e3c452f5119bc837ebc98af5de8d5d75cd04ce6 (patch) | |
tree | 8e06f820d5562a0e8f7be427bfff37bb9c92fb78 | |
parent | 2436a6b19ebb77226b96b0e37623b9b0785e172c (diff) | |
download | chromium_src-3e3c452f5119bc837ebc98af5de8d5d75cd04ce6.zip chromium_src-3e3c452f5119bc837ebc98af5de8d5d75cd04ce6.tar.gz chromium_src-3e3c452f5119bc837ebc98af5de8d5d75cd04ce6.tar.bz2 |
Add an accessibility mode for editable text fields only.
This refactors the triggering of accessibility mode from a boolean state and
command-line flag to an AccessibilityMode enum that's passed directly
when a new RenderView is created, which is also more readable and avoids the
extra command-line flag.
Adds a new mode that only syncs editable text nodes, and enables this on
Windows 8 so that we can support showing the virtual keyboard when an
editable text field gets focus.
BUG=122061,118641
TEST=Adds new test
Review URL: http://codereview.chromium.org/9939011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132267 0039d316-1c4b-4281-b951-d872f2087c98
26 files changed, 246 insertions, 90 deletions
diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm index 765cec2..26eb400 100644 --- a/chrome/browser/chrome_browser_application_mac.mm +++ b/chrome/browser/chrome_browser_application_mac.mm @@ -505,7 +505,7 @@ void SwizzleInit() { if (TabContentsWrapper* contents = *it) { if (content::RenderViewHost* rvh = contents->web_contents()->GetRenderViewHost()) { - rvh->EnableRendererAccessibility(); + rvh->EnableFullAccessibilityMode(); } } } diff --git a/content/browser/accessibility/browser_accessibility_state_impl.cc b/content/browser/accessibility/browser_accessibility_state_impl.cc index f3b8aaf..b878cdb 100644 --- a/content/browser/accessibility/browser_accessibility_state_impl.cc +++ b/content/browser/accessibility/browser_accessibility_state_impl.cc @@ -4,9 +4,11 @@ #include "content/browser/accessibility/browser_accessibility_state_impl.h" +#include "base/command_line.h" #include "base/memory/singleton.h" #include "base/metrics/histogram.h" #include "base/timer.h" +#include "content/public/common/content_switches.h" #include "ui/gfx/sys_color_change_listener.h" // Update the accessibility histogram 45 seconds after initialization. @@ -26,6 +28,10 @@ BrowserAccessibilityStateImpl* BrowserAccessibilityStateImpl::GetInstance() { BrowserAccessibilityStateImpl::BrowserAccessibilityStateImpl() : BrowserAccessibilityState(), accessibility_enabled_(false) { + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kForceRendererAccessibility)) { + OnAccessibilityEnabledManually(); + } update_histogram_timer_.Start( FROM_HERE, base::TimeDelta::FromSeconds(kAccessibilityHistogramDelaySecs), @@ -37,6 +43,10 @@ BrowserAccessibilityStateImpl::~BrowserAccessibilityStateImpl() { } void BrowserAccessibilityStateImpl::OnScreenReaderDetected() { + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableRendererAccessibility)) { + return; + } accessibility_enabled_ = true; } diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 5a7125c..d47da85 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc @@ -89,7 +89,7 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, RenderViewHostImpl* view_host = static_cast<RenderViewHostImpl*>(RenderWidgetHostImpl::From(host)); view_host->set_save_accessibility_tree_for_testing(true); - view_host->EnableRendererAccessibility(); + view_host->SetAccessibilityMode(AccessibilityModeComplete); // Setup test paths. FilePath dir_test_data; @@ -199,4 +199,3 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, } } while (!(html_file = file_enumerator.Next()).empty()); } - diff --git a/content/browser/accessibility/renderer_accessibility_browsertest.cc b/content/browser/accessibility/renderer_accessibility_browsertest.cc index 76d77fd..e8c5acc 100644 --- a/content/browser/accessibility/renderer_accessibility_browsertest.cc +++ b/content/browser/accessibility/renderer_accessibility_browsertest.cc @@ -35,7 +35,8 @@ class RendererAccessibilityBrowserTest : public InProcessBrowserTest { // Tell the renderer to send an accessibility tree, then wait for the // notification that it's been received. - const WebAccessibility& GetWebAccessibilityTree() { + const WebAccessibility& GetWebAccessibilityTree( + AccessibilityMode accessibility_mode = AccessibilityModeComplete) { ui_test_utils::WindowedNotificationObserver tree_updated_observer( content::NOTIFICATION_RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED, content::NotificationService::AllSources()); @@ -45,7 +46,7 @@ class RendererAccessibilityBrowserTest : public InProcessBrowserTest { RenderWidgetHostImpl::From(host_view->GetRenderWidgetHost()); RenderViewHostImpl* view_host = static_cast<RenderViewHostImpl*>(host); view_host->set_save_accessibility_tree_for_testing(true); - view_host->EnableRendererAccessibility(); + view_host->SetAccessibilityMode(accessibility_mode); tree_updated_observer.Wait(); return view_host->accessibility_tree_for_testing(); } @@ -463,4 +464,51 @@ IN_PROC_BROWSER_TEST_F(RendererAccessibilityBrowserTest, true, GetBoolAttr(textbox, WebAccessibility::ATTR_CAN_SET_VALUE)); } +IN_PROC_BROWSER_TEST_F(RendererAccessibilityBrowserTest, + CrossPlatformEditableTextOnlyMode) { + const char url_str[] = + "data:text/html," + "<!doctype html>" + "<h1>Heading</h1>" + "<input type=text value=text0>" + "<textarea>text1</textarea>" + "<div role=textbox>text2</div>" + "<ul>" + " <li><input type=text value=text3>" + " <li><textarea>text4</textarea>" + " <li><div role=textbox>text5</div>" + " <li><button>button</button>" + "</ul>"; + + GURL url(url_str); + browser()->OpenURL(OpenURLParams( + url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false)); + const WebAccessibility& tree = GetWebAccessibilityTree( + AccessibilityModeEditableTextOnly); + + const WebAccessibility& text0 = tree.children[0]; + EXPECT_EQ(WebAccessibility::ROLE_TEXT_FIELD, text0.role); + EXPECT_STREQ("text0", UTF16ToUTF8(text0.value).c_str()); + + const WebAccessibility& text1 = tree.children[1]; + EXPECT_EQ(WebAccessibility::ROLE_TEXTAREA, text1.role); + EXPECT_STREQ("text1", UTF16ToUTF8(text1.value).c_str()); + + const WebAccessibility& text2 = tree.children[2]; + EXPECT_EQ(WebAccessibility::ROLE_TEXT_FIELD, text2.role); + EXPECT_STREQ("text2", UTF16ToUTF8(text2.value).c_str()); + + const WebAccessibility& text3 = tree.children[3]; + EXPECT_EQ(WebAccessibility::ROLE_TEXT_FIELD, text3.role); + EXPECT_STREQ("text3", UTF16ToUTF8(text3.value).c_str()); + + const WebAccessibility& text4 = tree.children[4]; + EXPECT_EQ(WebAccessibility::ROLE_TEXTAREA, text4.role); + EXPECT_STREQ("text4", UTF16ToUTF8(text4.value).c_str()); + + const WebAccessibility& text5 = tree.children[5]; + EXPECT_EQ(WebAccessibility::ROLE_TEXT_FIELD, text5.role); + EXPECT_STREQ("text5", UTF16ToUTF8(text5.value).c_str()); +} + } // namespace diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 2800992..29724ec 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -279,7 +279,6 @@ RenderProcessHostImpl::RenderProcessHostImpl( ALLOW_THIS_IN_INITIALIZER_LIST(cached_dibs_cleaner_( FROM_HERE, base::TimeDelta::FromSeconds(5), this, &RenderProcessHostImpl::ClearTransportDIBCache)), - accessibility_enabled_(false), is_initialized_(false), id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()), browser_context_(browser_context), @@ -353,14 +352,12 @@ void RenderProcessHostImpl::EnableSendQueue() { is_initialized_ = false; } -bool RenderProcessHostImpl::Init(bool is_accessibility_enabled) { +bool RenderProcessHostImpl::Init() { // calling Init() more than once does nothing, this makes it more convenient // for the view host which may not be sure in some cases if (channel_.get()) return true; - accessibility_enabled_ = is_accessibility_enabled; - CommandLine::StringType renderer_prefix; #if defined(OS_POSIX) // A command prefix is something prepended to the command line of the spawned @@ -615,9 +612,6 @@ void RenderProcessHostImpl::AppendRendererCommandLine( command_line->AppendSwitchASCII(switches::kProcessType, switches::kRendererProcess); - if (accessibility_enabled_) - command_line->AppendSwitch(switches::kEnableAccessibility); - // Now send any options from our own command line we want to propagate. const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); PropagateBrowserCommandLineToRenderer(browser_command_line, command_line); diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index 71a41eb..b1986e7 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h @@ -58,7 +58,7 @@ class CONTENT_EXPORT RenderProcessHostImpl // RenderProcessHost implementation (public portion). virtual void EnableSendQueue() OVERRIDE; - virtual bool Init(bool is_accessibility_enabled) OVERRIDE; + virtual bool Init() OVERRIDE; virtual int GetNextRoutingID() OVERRIDE; virtual void CancelResourceRequests(int render_widget_id) OVERRIDE; virtual void CrossSiteSwapOutACK(const ViewMsg_SwapOut_Params& params) @@ -220,9 +220,6 @@ class CONTENT_EXPORT RenderProcessHostImpl // Used in single-process mode. scoped_ptr<RendererMainThread> in_process_renderer_; - // True if this prcoess should have accessibility enabled; - bool accessibility_enabled_; - // True after Init() has been called. We can't just check channel_ because we // also reset that in the case of process termination. bool is_initialized_; diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index f333925..04de175 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc @@ -18,6 +18,9 @@ #include "base/time.h" #include "base/utf_string_conversions.h" #include "base/values.h" +#if defined(OS_WIN) +#include "base/win/windows_version.h" +#endif #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/cross_site_request_manager.h" #include "content/browser/gpu/gpu_surface_tracker.h" @@ -33,6 +36,7 @@ #include "content/common/swapped_out_messages.h" #include "content/common/view_messages.h" #include "content/port/browser/render_widget_host_view_port.h" +#include "content/public/browser/browser_accessibility_state.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_message_filter.h" #include "content/public/browser/content_browser_client.h" @@ -205,7 +209,7 @@ bool RenderViewHostImpl::CreateRenderView(const string16& frame_name, // initialized it) or may not (we have our own process or the old process // crashed) have been initialized. Calling Init multiple times will be // ignored, so this is safe. - if (!GetProcess()->Init(renderer_accessible())) + if (!GetProcess()->Init()) return false; DCHECK(GetProcess()->HasConnection()); DCHECK(GetProcess()->GetBrowserContext()); @@ -245,6 +249,19 @@ bool RenderViewHostImpl::CreateRenderView(const string16& frame_name, gfx::NativeViewFromId(GetNativeViewId())); #endif params.guest = guest_; + params.accessibility_mode = + BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser() ? + AccessibilityModeComplete : + AccessibilityModeOff; + +#if defined(OS_WIN) + // On Windows 8, always enable accessibility for editable text controls + // so we can show the virtual keyboard when one is enabled. + if (base::win::GetVersion() >= base::win::VERSION_WIN8 && + params.accessibility_mode == AccessibilityModeOff) { + params.accessibility_mode = AccessibilityModeEditableTextOnly; + } +#endif Send(new ViewMsg_New(params)); diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index e6835f0..3a526a3 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -28,7 +28,6 @@ #include "content/common/gpu/gpu_messages.h" #include "content/common/view_messages.h" #include "content/port/browser/render_widget_host_view_port.h" -#include "content/public/browser/browser_accessibility_state.h" #include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" @@ -106,7 +105,6 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderProcessHost* process, hung_renderer_delay_ms_(kHungRendererDelayMs), process_(process), routing_id_(routing_id), - renderer_accessible_(false), surface_id_(0), is_loading_(false), is_hidden_(false), @@ -154,16 +152,6 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderProcessHost* process, // Because the widget initializes as is_hidden_ == false, // tell the process host that we're alive. process_->WidgetRestored(); - - // Enable accessibility if it was manually specified or if it was - // auto-detected. - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kForceRendererAccessibility)) { - BrowserAccessibilityState::GetInstance()->OnAccessibilityEnabledManually(); - EnableRendererAccessibility(); - } else if (BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) { - EnableRendererAccessibility(); - } } RenderWidgetHostImpl::~RenderWidgetHostImpl() { @@ -701,6 +689,10 @@ void RenderWidgetHostImpl::StopHangMonitorTimeout() { // started again shortly, which happens to be the common use case. } +void RenderWidgetHostImpl::EnableFullAccessibilityMode() { + SetAccessibilityMode(AccessibilityModeComplete); +} + void RenderWidgetHostImpl::ForwardMouseEvent(const WebMouseEvent& mouse_event) { TRACE_EVENT2("renderer_host", "RenderWidgetHostImpl::ForwardMouseEvent", "x", mouse_event.x, "y", mouse_event.y); @@ -1519,23 +1511,6 @@ void RenderWidgetHostImpl::Replace(const string16& word) { Send(new ViewMsg_Replace(routing_id_, word)); } -void RenderWidgetHostImpl::EnableRendererAccessibility() { - if (renderer_accessible_) - return; - - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableRendererAccessibility)) { - return; - } - - renderer_accessible_ = true; - - if (process_->HasConnection()) { - // Renderer accessibility wasn't enabled on process launch. Enable it now. - Send(new AccessibilityMsg_Enable(GetRoutingID())); - } -} - void RenderWidgetHostImpl::SetIgnoreInputEvents(bool ignore_input_events) { ignore_input_events_ = ignore_input_events; } @@ -1611,6 +1586,10 @@ void RenderWidgetHostImpl::SetEditCommandsForNextKeyEvent( Send(new ViewMsg_SetEditCommandsForNextKeyEvent(GetRoutingID(), commands)); } +void RenderWidgetHostImpl::SetAccessibilityMode(AccessibilityMode mode) { + Send(new AccessibilityMsg_SetMode(routing_id_, mode)); +} + void RenderWidgetHostImpl::AccessibilityDoDefaultAction(int object_id) { Send(new AccessibilityMsg_DoDefaultAction(GetRoutingID(), object_id)); } diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 2a93e2c..adb71f5 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h @@ -19,6 +19,7 @@ #include "base/string16.h" #include "base/timer.h" #include "build/build_config.h" +#include "content/common/view_message_enums.h" #include "content/public/browser/render_widget_host.h" #include "content/public/common/page_zoom.h" #include "ui/base/ime/text_input_type.h" @@ -94,7 +95,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, virtual bool CopyFromBackingStoreToCGContext(const CGRect& dest_rect, CGContextRef target) OVERRIDE; #endif - virtual void EnableRendererAccessibility() OVERRIDE; + virtual void EnableFullAccessibilityMode() OVERRIDE; virtual void ForwardMouseEvent( const WebKit::WebMouseEvent& mouse_event) OVERRIDE; virtual void ForwardWheelEvent( @@ -123,7 +124,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, void SetView(RenderWidgetHostView* view); int surface_id() const { return surface_id_; } - bool renderer_accessible() { return renderer_accessible_; } bool empty() const { return current_size_.IsEmpty(); } @@ -298,6 +298,9 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, void SetEditCommandsForNextKeyEvent( const std::vector<EditCommand>& commands); + // Send a message to the renderer process to change the accessibility mode. + void SetAccessibilityMode(AccessibilityMode mode); + // Relay a request from assistive technology to perform the default action // on a given node. void AccessibilityDoDefaultAction(int object_id); @@ -550,10 +553,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, // The ID of the corresponding object in the Renderer Instance. int routing_id_; - // True if renderer accessibility is enabled. This should only be set when a - // screenreader is detected as it can potentially slow down Chrome. - bool renderer_accessible_; - // Stores random bits of data for others to associate with this object. base::PropertyBag property_bag_; diff --git a/content/browser/renderer_host/render_widget_host_view_win.cc b/content/browser/renderer_host/render_widget_host_view_win.cc index daeb538..6e749b9 100644 --- a/content/browser/renderer_host/render_widget_host_view_win.cc +++ b/content/browser/renderer_host/render_widget_host_view_win.cc @@ -464,7 +464,8 @@ gfx::NativeViewId RenderWidgetHostViewWin::GetNativeViewId() const { gfx::NativeViewAccessible RenderWidgetHostViewWin::GetNativeViewAccessible() { - if (render_widget_host_ && !render_widget_host_->renderer_accessible()) { + if (render_widget_host_ && + !BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) { // Attempt to detect screen readers by sending an event with our custom id. NotifyWinEvent(EVENT_SYSTEM_ALERT, m_hWnd, kIdCustom, CHILDID_SELF); } @@ -2289,7 +2290,8 @@ LRESULT RenderWidgetHostViewWin::OnGetObject(UINT message, WPARAM wparam, // An MSAA client requestes our custom id. Assume that we have detected an // active windows screen reader. BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected(); - render_widget_host_->EnableRendererAccessibility(); + if (BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) + render_widget_host_->SetAccessibilityMode(AccessibilityModeComplete); // Return with failure. return static_cast<LRESULT>(0L); diff --git a/content/common/accessibility_messages.h b/content/common/accessibility_messages.h index a37329e..4e6dc0d 100644 --- a/content/common/accessibility_messages.h +++ b/content/common/accessibility_messages.h @@ -7,6 +7,7 @@ #include "base/basictypes.h" #include "content/common/content_export.h" +#include "content/common/view_message_enums.h" #include "content/public/common/common_param_traits.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_utils.h" @@ -88,6 +89,7 @@ enum AccessibilityNotification { #endif // CONTENT_COMMON_ACCESSIBILITY_MESSAGES_H_ +IPC_ENUM_TRAITS(AccessibilityMode) IPC_ENUM_TRAITS(AccessibilityNotification) IPC_ENUM_TRAITS(webkit_glue::WebAccessibility::BoolAttribute) @@ -133,8 +135,9 @@ IPC_STRUCT_END() // Messages sent from the browser to the renderer. -// Enable accessibility in the renderer process. -IPC_MESSAGE_ROUTED0(AccessibilityMsg_Enable) +// Change the accessibility mode in the renderer process. +IPC_MESSAGE_ROUTED1(AccessibilityMsg_SetMode, + AccessibilityMode) // Relay a request from assistive technology to set focus to a given node. IPC_MESSAGE_ROUTED1(AccessibilityMsg_SetFocus, diff --git a/content/common/view_message_enums.h b/content/common/view_message_enums.h index 29761b2..772dbca 100644 --- a/content/common/view_message_enums.h +++ b/content/common/view_message_enums.h @@ -5,6 +5,8 @@ #ifndef CONTENT_COMMON_VIEW_MESSAGES_ENUMS_H_ #define CONTENT_COMMON_VIEW_MESSAGES_ENUMS_H_ +#include "ipc/ipc_message_macros.h" + // Values that may be OR'd together to form the 'flags' parameter of a // ViewHostMsg_UpdateRect_Params structure. struct ViewHostMsg_UpdateRect_Flags { @@ -48,4 +50,19 @@ struct ViewMsg_Navigate_Type { }; }; +enum AccessibilityMode { + // WebKit accessibility is off and no accessibility information is + // sent from the renderer to the browser process. + AccessibilityModeOff, + + // WebKit accessibility is on, but only limited information about + // editable text nodes is sent to the browser process. Useful for + // implementing limited UIA on tablets. + AccessibilityModeEditableTextOnly, + + // WebKit accessibility is on, and the full accessibility tree is synced + // to the browser process. Useful for screen readers and magnifiers. + AccessibilityModeComplete, +}; + #endif // CONTENT_COMMON_VIEW_MESSAGES_ENUMS_H_ diff --git a/content/common/view_messages.h b/content/common/view_messages.h index 8d75190..246dc4a 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h @@ -648,6 +648,9 @@ IPC_STRUCT_BEGIN(ViewMsg_New_Params) // Indicates whether this newly created RenderView will be hosted by another // RenderView. IPC_STRUCT_MEMBER(bool, guest) + + // The accessibility mode of the renderer. + IPC_STRUCT_MEMBER(AccessibilityMode, accessibility_mode) IPC_STRUCT_END() // Messages sent from the browser to the renderer. diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h index eec6a6b..c345294 100644 --- a/content/public/browser/render_process_host.h +++ b/content/public/browser/render_process_host.h @@ -61,7 +61,7 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Message::Sender, // be called once before the object can be used, but can be called after // that with no effect. Therefore, if the caller isn't sure about whether // the process has been created, it should just call Init(). - virtual bool Init(bool is_accessibility_enabled) = 0; + virtual bool Init() = 0; // Gets the next available routing id. virtual int GetNextRoutingID() = 0; @@ -242,4 +242,3 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Message::Sender, } // namespace content. #endif // CONTENT_PUBLIC_BROWSER_RENDER_PROCESS_HOST_H_ - diff --git a/content/public/browser/render_widget_host.h b/content/public/browser/render_widget_host.h index 45db575..a3ca330 100644 --- a/content/public/browser/render_widget_host.h +++ b/content/public/browser/render_widget_host.h @@ -208,9 +208,8 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Channel::Sender { CGContextRef target) = 0; #endif - // Enable renderer accessibility. This should only be called when a - // screenreader is detected. - virtual void EnableRendererAccessibility() = 0; + // Send a command to the renderer to turn on full accessibility. + virtual void EnableFullAccessibilityMode() = 0; // Forwards the given message to the renderer. These are called by // the view when it has received a message. diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index 7dbe56c..5e68f10 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc @@ -217,9 +217,6 @@ const char kEnableAcceleratedPainting[] = "enable-accelerated-painting"; // Enable gpu-accelerated SVG/W3C filters. const char kEnableAcceleratedFilters[] = "enable-accelerated-filters"; -// Enables WebKit accessibility within the renderer process. -const char kEnableAccessibility[] = "enable-accessibility"; - // Turns on extremely verbose logging of accessibility events. const char kEnableAccessibilityLogging[] = "enable-accessibility-logging"; diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 3a0d6e4..1f28134 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h @@ -76,7 +76,6 @@ extern const char kDisableXSSAuditor[]; CONTENT_EXPORT extern const char kDomAutomationController[]; CONTENT_EXPORT extern const char kEnableAcceleratedPainting[]; CONTENT_EXPORT extern const char kEnableAcceleratedFilters[]; -extern const char kEnableAccessibility[]; extern const char kEnableAccessibilityLogging[]; extern const char kEnableBrowserPlugin[]; CONTENT_EXPORT extern const char kEnableCompositingForFixedPosition[]; diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index a047050..b1aba00 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc @@ -890,7 +890,8 @@ void RenderThreadImpl::OnCreateNewView(const ViewMsg_New_Params& params) { params.frame_name, params.next_page_id, params.screen_info, - params.guest); + params.guest, + params.accessibility_mode); } GpuChannelHost* RenderThreadImpl::EstablishGpuChannelSync( diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index a1d0806..44b0656 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc @@ -435,7 +435,8 @@ RenderViewImpl::RenderViewImpl( const string16& frame_name, int32 next_page_id, const WebKit::WebScreenInfo& screen_info, - bool guest) + bool guest, + AccessibilityMode accessibility_mode) : RenderWidget(WebKit::WebPopupTypeNone, screen_info), webkit_preferences_(webkit_prefs), send_content_state_immediately_(false), @@ -474,6 +475,7 @@ RenderViewImpl::RenderViewImpl( focused_plugin_id_(-1), #endif guest_(guest), + accessibility_mode_(accessibility_mode), ALLOW_THIS_IN_INITIALIZER_LIST(pepper_delegate_(this)) { routing_id_ = routing_id; surface_id_ = surface_id; @@ -544,7 +546,7 @@ RenderViewImpl::RenderViewImpl( // The next group of objects all implement RenderViewObserver, so are deleted // along with the RenderView automatically. devtools_agent_ = new DevToolsAgent(this); - renderer_accessibility_ = new RendererAccessibility(this); + renderer_accessibility_ = new RendererAccessibility(this, accessibility_mode); mouse_lock_dispatcher_ = new MouseLockDispatcher(this); intents_host_ = new WebIntentsHost(this); @@ -634,7 +636,8 @@ RenderViewImpl* RenderViewImpl::Create( const string16& frame_name, int32 next_page_id, const WebKit::WebScreenInfo& screen_info, - bool guest) { + bool guest, + AccessibilityMode accessibility_mode) { DCHECK(routing_id != MSG_ROUTING_NONE); return new RenderViewImpl( parent_hwnd, @@ -648,7 +651,8 @@ RenderViewImpl* RenderViewImpl::Create( frame_name, next_page_id, screen_info, - guest); + guest, + accessibility_mode); } WebPeerConnectionHandler* RenderViewImpl::CreatePeerConnectionHandler( @@ -1512,7 +1516,8 @@ WebView* RenderViewImpl::createView( frame_name, 1, screen_info_, - guest_); + guest_, + accessibility_mode_); view->opened_by_user_gesture_ = params.user_gesture; // Record whether the creator frame is trying to suppress the opener field. diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 432fe7ec..d6128a2 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h @@ -24,6 +24,7 @@ #include "content/common/edit_command.h" #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" #include "content/common/navigation_gesture.h" +#include "content/common/view_message_enums.h" #include "content/public/common/page_zoom.h" #include "content/public/common/referrer.h" #include "content/public/common/renderer_preferences.h" @@ -194,7 +195,8 @@ class RenderViewImpl : public RenderWidget, const string16& frame_name, int32 next_page_id, const WebKit::WebScreenInfo& screen_info, - bool guest); + bool guest, + AccessibilityMode accessibility_mode); // Returns the RenderViewImpl containing the given WebView. CONTENT_EXPORT static RenderViewImpl* FromWebView(WebKit::WebView* webview); @@ -742,7 +744,8 @@ class RenderViewImpl : public RenderWidget, const string16& frame_name, int32 next_page_id, const WebKit::WebScreenInfo& screen_info, - bool guest); + bool guest, + AccessibilityMode accessibility_mode); // Do not delete directly. This class is reference counted. virtual ~RenderViewImpl(); @@ -1315,6 +1318,9 @@ class RenderViewImpl : public RenderWidget, // Indicates whether this RenderView is a guest of another RenderView. bool guest_; + // The accessibility mode. + AccessibilityMode accessibility_mode_; + // NOTE: pepper_delegate_ should be last member because its constructor calls // AddObservers method of RenderViewImpl from c-tor. content::PepperPluginDelegateImpl pepper_delegate_; diff --git a/content/renderer/renderer_accessibility.cc b/content/renderer/renderer_accessibility.cc index 7e879ef..bfb22f1 100644 --- a/content/renderer/renderer_accessibility.cc +++ b/content/renderer/renderer_accessibility.cc @@ -5,7 +5,6 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/message_loop.h" -#include "content/common/accessibility_messages.h" #include "content/public/common/content_switches.h" #include "content/renderer/render_view_impl.h" #include "content/renderer/renderer_accessibility.h" @@ -84,18 +83,19 @@ bool WebAccessibilityNotificationToAccessibilityNotification( return true; } -RendererAccessibility::RendererAccessibility(RenderViewImpl* render_view) +RendererAccessibility::RendererAccessibility(RenderViewImpl* render_view, + AccessibilityMode mode) : content::RenderViewObserver(render_view), ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), browser_root_(NULL), last_scroll_offset_(gfx::Size()), + mode_(AccessibilityModeOff), ack_pending_(false), logging_(false) { const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - if (command_line.HasSwitch(switches::kEnableAccessibility)) - WebAccessibilityObject::enableAccessibility(); if (command_line.HasSwitch(switches::kEnableAccessibilityLogging)) logging_ = true; + OnSetMode(mode); } RendererAccessibility::~RendererAccessibility() { @@ -104,7 +104,7 @@ RendererAccessibility::~RendererAccessibility() { bool RendererAccessibility::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(RendererAccessibility, message) - IPC_MESSAGE_HANDLER(AccessibilityMsg_Enable, OnEnable) + IPC_MESSAGE_HANDLER(AccessibilityMsg_SetMode, OnSetMode) IPC_MESSAGE_HANDLER(AccessibilityMsg_SetFocus, OnSetFocus) IPC_MESSAGE_HANDLER(AccessibilityMsg_DoDefaultAction, OnDoDefaultAction) @@ -303,11 +303,11 @@ void RendererAccessibility::SendPendingAccessibilityNotifications() { } AccessibilityHostMsg_NotificationParams notification_msg; + BuildAccessibilityTree(obj, includes_children, ¬ification_msg.acc_tree); WebAccessibilityNotificationToAccessibilityNotification( notification.type, ¬ification_msg.notification_type); notification_msg.id = notification.id; notification_msg.includes_children = includes_children; - notification_msg.acc_tree = WebAccessibility(obj, includes_children); if (obj.axID() == root_id) { DCHECK_EQ(notification_msg.acc_tree.role, WebAccessibility::ROLE_WEB_AREA); @@ -486,9 +486,17 @@ void RendererAccessibility::OnNotificationsAck() { SendPendingAccessibilityNotifications(); } -void RendererAccessibility::OnEnable() { - if (WebAccessibilityObject::accessibilityEnabled()) +void RendererAccessibility::OnSetMode(AccessibilityMode mode) { + if (mode_ == mode) { return; + } + + mode_ = mode; + if (mode_ == AccessibilityModeOff) { + // Note: should we have a way to turn off WebKit accessibility? + // Right now it's a one-way switch. + return; + } WebAccessibilityObject::enableAccessibility(); @@ -561,3 +569,54 @@ WebDocument RendererAccessibility::GetMainDocument() { else return WebDocument(); } + +bool RendererAccessibility::IsEditableText(const WebAccessibilityObject& obj) { + return (obj.roleValue() == WebKit::WebAccessibilityRoleTextArea || + obj.roleValue() == WebKit::WebAccessibilityRoleTextField); +} + +void RendererAccessibility::RecursiveAddEditableTextNodesToTree( + const WebAccessibilityObject& src, + WebAccessibility* dst) { + if (IsEditableText(src)) { + dst->children.push_back(WebAccessibility(src, false)); + } else { + int child_count = src.childCount(); + std::set<int32> child_ids; + for (int i = 0; i < child_count; ++i) { + WebAccessibilityObject child = src.childAt(i); + if (!child.isValid()) + continue; + RecursiveAddEditableTextNodesToTree(child, dst); + } + } +} + +void RendererAccessibility::BuildAccessibilityTree( + const WebAccessibilityObject& src, + bool include_children, + WebAccessibility* dst) { + if (mode_ == AccessibilityModeComplete) { + dst->Init(src, include_children); + return; + } + + // In Editable Text mode, we send a "collapsed" tree of only editable + // text nodes as direct descendants of the root. + CHECK_EQ(mode_, AccessibilityModeEditableTextOnly); + if (IsEditableText(src)) { + dst->Init(src, false); + return; + } + + // If it's not an editable text node, it must be the root, because + // BuildAccessibilityTree will never be called on a non-root node + // that isn't already in the browser's tree. + CHECK_EQ(src.axID(), GetMainDocument().accessibilityObject().axID()); + + // Initialize the main document node, but don't add any children. + dst->Init(src, false); + + // Find all editable text nodes and add them as children. + RecursiveAddEditableTextNodesToTree(src, dst); +} diff --git a/content/renderer/renderer_accessibility.h b/content/renderer/renderer_accessibility.h index 835a00f..e7dd1dc 100644 --- a/content/renderer/renderer_accessibility.h +++ b/content/renderer/renderer_accessibility.h @@ -10,6 +10,7 @@ #include "base/hash_tables.h" #include "base/memory/weak_ptr.h" +#include "content/common/accessibility_messages.h" #include "content/public/renderer/render_view_observer.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebAccessibilityNotification.h" @@ -32,7 +33,8 @@ struct WebAccessibility; // nodes in the tree (e.g., change focus, or click on a button). class RendererAccessibility : public content::RenderViewObserver { public: - RendererAccessibility(RenderViewImpl* render_view); + RendererAccessibility(RenderViewImpl* render_view, + AccessibilityMode accessibility_mode); virtual ~RendererAccessibility(); // RenderView::Observer implementation. @@ -85,7 +87,7 @@ class RendererAccessibility : public content::RenderViewObserver { void OnChangeScrollPosition(int acc_obj_id, int scroll_x, int scroll_y); void OnScrollToMakeVisible(int acc_obj_id, gfx::Rect subfocus); void OnScrollToPoint(int acc_obj_id, gfx::Point point); - void OnEnable(); + void OnSetMode(AccessibilityMode mode); void OnSetFocus(int acc_obj_id); void OnSetTextSelection(int acc_obj_id, int start_offset, int end_offset); @@ -98,6 +100,23 @@ class RendererAccessibility : public content::RenderViewObserver { // no view or frame. WebKit::WebDocument GetMainDocument(); + // Checks if a WebKit accessibility object is an editable text node. + bool IsEditableText(const WebKit::WebAccessibilityObject& node); + + // Recursively explore the tree of WebKit accessibility objects rooted + // at |src|, and for each editable text node encountered, add a + // corresponding WebAccessibility node as a child of |dst|. + void RecursiveAddEditableTextNodesToTree( + const WebKit::WebAccessibilityObject& src, + webkit_glue::WebAccessibility* dst); + + // Build a tree of serializable WebAccessibility nodes to send to the + // browser process, given a WebAccessibilityObject node from WebKit. + // Modifies |dst| in-place, it's assumed to be empty. + void BuildAccessibilityTree(const WebKit::WebAccessibilityObject& src, + bool include_children, + webkit_glue::WebAccessibility* dst); + // So we can queue up tasks to be executed later. base::WeakPtrFactory<RendererAccessibility> weak_factory_; @@ -116,6 +135,9 @@ class RendererAccessibility : public content::RenderViewObserver { // is fixed. gfx::Size last_scroll_offset_; + // The current accessibility mode. + AccessibilityMode mode_; + // Set if we are waiting for an accessibility notification ack. bool ack_pending_; diff --git a/content/test/mock_render_process_host.cc b/content/test/mock_render_process_host.cc index 90ba216..3c1b942 100644 --- a/content/test/mock_render_process_host.cc +++ b/content/test/mock_render_process_host.cc @@ -42,7 +42,7 @@ MockRenderProcessHost::~MockRenderProcessHost() { void MockRenderProcessHost::EnableSendQueue() { } -bool MockRenderProcessHost::Init(bool is_accessibility_enabled) { +bool MockRenderProcessHost::Init() { return true; } diff --git a/content/test/mock_render_process_host.h b/content/test/mock_render_process_host.h index 4726f66..7548b6d 100644 --- a/content/test/mock_render_process_host.h +++ b/content/test/mock_render_process_host.h @@ -34,7 +34,7 @@ class MockRenderProcessHost : public RenderProcessHost { // RenderProcessHost implementation (public portion). virtual void EnableSendQueue() OVERRIDE; - virtual bool Init(bool is_accessibility_enabled) OVERRIDE; + virtual bool Init() OVERRIDE; virtual int GetNextRoutingID() OVERRIDE; virtual void CancelResourceRequests(int render_widget_id) OVERRIDE; virtual void CrossSiteSwapOutACK( diff --git a/content/test/render_view_test.cc b/content/test/render_view_test.cc index a64f8aa..25e5488 100644 --- a/content/test/render_view_test.cc +++ b/content/test/render_view_test.cc @@ -166,7 +166,8 @@ void RenderViewTest::SetUp() { string16(), 1, WebKit::WebScreenInfo(), - false); + false, + AccessibilityModeOff); view->AddRef(); view_ = view; diff --git a/webkit/glue/webaccessibility.h b/webkit/glue/webaccessibility.h index 3b6df7a..2b5f928 100644 --- a/webkit/glue/webaccessibility.h +++ b/webkit/glue/webaccessibility.h @@ -259,6 +259,10 @@ struct WEBKIT_GLUE_EXPORT WebAccessibility { ~WebAccessibility(); + // Initialize an already-created struct, same as the constructor above. + void Init(const WebKit::WebAccessibilityObject& src, + bool include_children); + #ifndef NDEBUG std::string DebugString(bool recursive, int render_routing_id, @@ -266,10 +270,6 @@ struct WEBKIT_GLUE_EXPORT WebAccessibility { #endif private: - // Initialize an already-created struct, same as the constructor above. - void Init(const WebKit::WebAccessibilityObject& src, - bool include_children); - // Returns true if |ancestor| is the first unignored parent of |child|, // which means that when walking up the parent chain from |child|, // |ancestor| is the *first* ancestor that isn't marked as |