Commit c93c9c32 authored by dmazzoni@chromium.org's avatar dmazzoni@chromium.org

Implement put_accvalue for textfields and location bar.

All interactive views implement GetAccessibleState
to provide accessibility information about the current
state of the view. This struct now includes a callback
that can be used to change the string value, since
automation software wants to fill in text fields,
and this interface is implemented for Textfield
and LocationBarView, and hooked up to put_accValue.

BUG=260266

Review URL: https://chromiumcodereview.appspot.com/23441024

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221688 0039d316-1c4b-4281-b951-d872f2087c98
parent 70bd4e54
...@@ -190,7 +190,8 @@ LocationBarView::LocationBarView(Browser* browser, ...@@ -190,7 +190,8 @@ LocationBarView::LocationBarView(Browser* browser,
is_popup_mode_(is_popup_mode), is_popup_mode_(is_popup_mode),
show_focus_rect_(false), show_focus_rect_(false),
template_url_service_(NULL), template_url_service_(NULL),
animation_offset_(0) { animation_offset_(0),
weak_ptr_factory_(this) {
if (!views::Textfield::IsViewsTextfieldEnabled()) if (!views::Textfield::IsViewsTextfieldEnabled())
set_id(VIEW_ID_OMNIBOX); set_id(VIEW_ID_OMNIBOX);
...@@ -634,17 +635,6 @@ void LocationBarView::ZoomChangedForActiveTab(bool can_show_bubble) { ...@@ -634,17 +635,6 @@ void LocationBarView::ZoomChangedForActiveTab(bool can_show_bubble) {
ZoomBubbleView::ShowBubble(delegate_->GetWebContents(), true); ZoomBubbleView::ShowBubble(delegate_->GetWebContents(), true);
} }
void LocationBarView::RefreshZoomView() {
DCHECK(zoom_view_);
WebContents* web_contents = GetWebContents();
if (!web_contents)
return;
ZoomController* zoom_controller =
ZoomController::FromWebContents(web_contents);
zoom_view_->Update(zoom_controller);
}
gfx::Point LocationBarView::GetLocationEntryOrigin() const { gfx::Point LocationBarView::GetLocationEntryOrigin() const {
gfx::Point origin(location_entry_view_->bounds().origin()); gfx::Point origin(location_entry_view_->bounds().origin());
// If the UI layout is RTL, the coordinate system is not transformed and // If the UI layout is RTL, the coordinate system is not transformed and
...@@ -1121,192 +1111,6 @@ const ToolbarModel* LocationBarView::GetToolbarModel() const { ...@@ -1121,192 +1111,6 @@ const ToolbarModel* LocationBarView::GetToolbarModel() const {
return delegate_->GetToolbarModel(); return delegate_->GetToolbarModel();
} }
// static
int LocationBarView::GetBuiltInHorizontalPaddingForChildViews() {
return (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) ?
GetItemPadding() / 2 : 0;
}
int LocationBarView::GetHorizontalEdgeThickness() const {
// In maximized popup mode, there isn't any edge.
return (is_popup_mode_ && browser_ && browser_->window() &&
browser_->window()->IsMaximized()) ? 0 : vertical_edge_thickness();
}
void LocationBarView::UpdateContentSettingViewsPreLayout() {
for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
i != content_setting_views_.end(); ++i) {
(*i)->UpdatePreLayout(GetToolbarModel()->input_in_progress() ?
NULL : GetWebContents());
}
}
void LocationBarView::UpdateContentSettingViewsPostLayout() {
for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
i != content_setting_views_.end(); ++i) {
(*i)->UpdatePostLayout(GetToolbarModel()->input_in_progress() ?
NULL : GetWebContents());
}
}
void LocationBarView::DeletePageActionViews() {
for (PageActionViews::const_iterator i(page_action_views_.begin());
i != page_action_views_.end(); ++i)
RemoveChildView(*i);
STLDeleteElements(&page_action_views_);
}
void LocationBarView::RefreshPageActionViews() {
if (is_popup_mode_)
return;
// Remember the previous visibility of the page actions so that we can
// notify when this changes.
std::map<ExtensionAction*, bool> old_visibility;
for (PageActionViews::const_iterator i(page_action_views_.begin());
i != page_action_views_.end(); ++i) {
old_visibility[(*i)->image_view()->page_action()] = (*i)->visible();
}
std::vector<ExtensionAction*> new_page_actions;
WebContents* contents = delegate_->GetWebContents();
if (contents) {
extensions::TabHelper* extensions_tab_helper =
extensions::TabHelper::FromWebContents(contents);
extensions::LocationBarController* controller =
extensions_tab_helper->location_bar_controller();
new_page_actions = controller->GetCurrentActions();
}
// On startup we sometimes haven't loaded any extensions. This makes sure
// we catch up when the extensions (and any page actions) load.
if (page_actions_ != new_page_actions) {
page_actions_.swap(new_page_actions);
DeletePageActionViews(); // Delete the old views (if any).
page_action_views_.resize(page_actions_.size());
View* right_anchor = open_pdf_in_reader_view_;
if (!right_anchor)
right_anchor = star_view_;
if (!right_anchor)
right_anchor = script_bubble_icon_view_;
DCHECK(right_anchor);
// Add the page actions in reverse order, so that the child views are
// inserted in left-to-right order for accessibility.
for (int i = page_actions_.size() - 1; i >= 0; --i) {
page_action_views_[i] = new PageActionWithBadgeView(
delegate_->CreatePageActionImageView(this, page_actions_[i]));
page_action_views_[i]->SetVisible(false);
AddChildViewAt(page_action_views_[i], GetIndexOf(right_anchor));
}
}
if (!page_action_views_.empty() && contents) {
Browser* browser = chrome::FindBrowserWithWebContents(contents);
GURL url = browser->tab_strip_model()->GetActiveWebContents()->GetURL();
for (PageActionViews::const_iterator i(page_action_views_.begin());
i != page_action_views_.end(); ++i) {
(*i)->UpdateVisibility(
GetToolbarModel()->input_in_progress() ? NULL : contents, url);
// Check if the visibility of the action changed and notify if it did.
ExtensionAction* action = (*i)->image_view()->page_action();
if (old_visibility.find(action) == old_visibility.end() ||
old_visibility[action] != (*i)->visible()) {
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
content::Source<ExtensionAction>(action),
content::Details<WebContents>(contents));
}
}
}
}
size_t LocationBarView::ScriptBubbleScriptsRunning() {
WebContents* contents = delegate_->GetWebContents();
if (!contents)
return false;
extensions::TabHelper* extensions_tab_helper =
extensions::TabHelper::FromWebContents(contents);
if (!extensions_tab_helper)
return false;
extensions::ScriptBubbleController* script_bubble_controller =
extensions_tab_helper->script_bubble_controller();
if (!script_bubble_controller)
return false;
size_t script_count =
script_bubble_controller->extensions_running_scripts().size();
return script_count;
}
void LocationBarView::RefreshScriptBubble() {
if (!script_bubble_icon_view_)
return;
size_t script_count = ScriptBubbleScriptsRunning();
script_bubble_icon_view_->SetVisible(script_count > 0);
if (script_count > 0)
script_bubble_icon_view_->SetScriptCount(script_count);
}
#if defined(OS_WIN) && !defined(USE_AURA)
void LocationBarView::OnMouseEvent(const ui::MouseEvent& event, UINT msg) {
OmniboxViewWin* omnibox_win = GetOmniboxViewWin(location_entry_.get());
if (omnibox_win) {
UINT flags = event.native_event().wParam;
gfx::Point screen_point(event.location());
ConvertPointToScreen(this, &screen_point);
omnibox_win->HandleExternalMsg(msg, flags, screen_point.ToPOINT());
}
}
#endif
void LocationBarView::ShowFirstRunBubbleInternal() {
#if !defined(OS_CHROMEOS)
// First run bubble doesn't make sense for Chrome OS.
Browser* browser = GetBrowserFromDelegate(delegate_);
if (!browser)
return; // Possible when browser is shutting down.
FirstRunBubble::ShowBubble(browser, location_icon_view_);
#endif
}
void LocationBarView::PaintPageActionBackgrounds(gfx::Canvas* canvas) {
WebContents* web_contents = GetWebContents();
// web_contents may be NULL while the browser is shutting down.
if (!web_contents)
return;
const int32 tab_id = SessionID::IdForTab(web_contents);
const ToolbarModel::SecurityLevel security_level =
GetToolbarModel()->GetSecurityLevel(false);
const SkColor text_color = GetColor(security_level, TEXT);
const SkColor background_color = GetColor(security_level, BACKGROUND);
for (PageActionViews::const_iterator
page_action_view = page_action_views_.begin();
page_action_view != page_action_views_.end();
++page_action_view) {
gfx::Rect bounds = (*page_action_view)->bounds();
int horizontal_padding =
GetItemPadding() - GetBuiltInHorizontalPaddingForChildViews();
// Make the bounding rectangle include the whole vertical range of the
// location bar, and the mid-point pixels between adjacent page actions.
//
// For odd horizontal_paddings, "horizontal_padding + 1" includes the
// mid-point between two page actions in the bounding rectangle. For even
// paddings, the +1 is dropped, which is right since there is no pixel at
// the mid-point.
bounds.Inset(-(horizontal_padding + 1) / 2, 0);
location_bar_util::PaintExtensionActionBackground(
*(*page_action_view)->image_view()->page_action(),
tab_id, canvas, bounds, text_color, background_color);
}
}
const char* LocationBarView::GetClassName() const { const char* LocationBarView::GetClassName() const {
return kViewClassName; return kViewClassName;
} }
...@@ -1339,6 +1143,9 @@ bool LocationBarView::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) { ...@@ -1339,6 +1143,9 @@ bool LocationBarView::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
} }
void LocationBarView::GetAccessibleState(ui::AccessibleViewState* state) { void LocationBarView::GetAccessibleState(ui::AccessibleViewState* state) {
if (!location_entry_)
return;
state->role = ui::AccessibilityTypes::ROLE_LOCATION_BAR; state->role = ui::AccessibilityTypes::ROLE_LOCATION_BAR;
state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_LOCATION); state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_LOCATION);
state->value = location_entry_->GetText(); state->value = location_entry_->GetText();
...@@ -1348,6 +1155,14 @@ void LocationBarView::GetAccessibleState(ui::AccessibleViewState* state) { ...@@ -1348,6 +1155,14 @@ void LocationBarView::GetAccessibleState(ui::AccessibleViewState* state) {
location_entry_->GetSelectionBounds(&entry_start, &entry_end); location_entry_->GetSelectionBounds(&entry_start, &entry_end);
state->selection_start = entry_start; state->selection_start = entry_start;
state->selection_end = entry_end; state->selection_end = entry_end;
if (is_popup_mode_) {
state->state |= ui::AccessibilityTypes::STATE_READONLY;
} else {
state->set_value_callback =
base::Bind(&LocationBarView::AccessibilitySetValue,
weak_ptr_factory_.GetWeakPtr());
}
} }
bool LocationBarView::HasFocus() const { bool LocationBarView::HasFocus() const {
...@@ -1563,7 +1378,211 @@ int LocationBarView::GetInternalHeight(bool use_preferred_size) { ...@@ -1563,7 +1378,211 @@ int LocationBarView::GetInternalHeight(bool use_preferred_size) {
return std::max(total_height - (vertical_edge_thickness() * 2), 0); return std::max(total_height - (vertical_edge_thickness() * 2), 0);
} }
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, private:
// static
int LocationBarView::GetBuiltInHorizontalPaddingForChildViews() {
return (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) ?
GetItemPadding() / 2 : 0;
}
int LocationBarView::GetHorizontalEdgeThickness() const {
// In maximized popup mode, there isn't any edge.
return (is_popup_mode_ && browser_ && browser_->window() &&
browser_->window()->IsMaximized()) ? 0 : vertical_edge_thickness();
}
void LocationBarView::UpdateContentSettingViewsPreLayout() {
for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
i != content_setting_views_.end(); ++i) {
(*i)->UpdatePreLayout(GetToolbarModel()->input_in_progress() ?
NULL : GetWebContents());
}
}
void LocationBarView::UpdateContentSettingViewsPostLayout() {
for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
i != content_setting_views_.end(); ++i) {
(*i)->UpdatePostLayout(GetToolbarModel()->input_in_progress() ?
NULL : GetWebContents());
}
}
void LocationBarView::DeletePageActionViews() {
for (PageActionViews::const_iterator i(page_action_views_.begin());
i != page_action_views_.end(); ++i)
RemoveChildView(*i);
STLDeleteElements(&page_action_views_);
}
void LocationBarView::RefreshPageActionViews() {
if (is_popup_mode_)
return;
// Remember the previous visibility of the page actions so that we can
// notify when this changes.
std::map<ExtensionAction*, bool> old_visibility;
for (PageActionViews::const_iterator i(page_action_views_.begin());
i != page_action_views_.end(); ++i) {
old_visibility[(*i)->image_view()->page_action()] = (*i)->visible();
}
std::vector<ExtensionAction*> new_page_actions;
WebContents* contents = delegate_->GetWebContents();
if (contents) {
extensions::TabHelper* extensions_tab_helper =
extensions::TabHelper::FromWebContents(contents);
extensions::LocationBarController* controller =
extensions_tab_helper->location_bar_controller();
new_page_actions = controller->GetCurrentActions();
}
// On startup we sometimes haven't loaded any extensions. This makes sure
// we catch up when the extensions (and any page actions) load.
if (page_actions_ != new_page_actions) {
page_actions_.swap(new_page_actions);
DeletePageActionViews(); // Delete the old views (if any).
page_action_views_.resize(page_actions_.size());
View* right_anchor = open_pdf_in_reader_view_;
if (!right_anchor)
right_anchor = star_view_;
if (!right_anchor)
right_anchor = script_bubble_icon_view_;
DCHECK(right_anchor);
// Add the page actions in reverse order, so that the child views are
// inserted in left-to-right order for accessibility.
for (int i = page_actions_.size() - 1; i >= 0; --i) {
page_action_views_[i] = new PageActionWithBadgeView(
delegate_->CreatePageActionImageView(this, page_actions_[i]));
page_action_views_[i]->SetVisible(false);
AddChildViewAt(page_action_views_[i], GetIndexOf(right_anchor));
}
}
if (!page_action_views_.empty() && contents) {
Browser* browser = chrome::FindBrowserWithWebContents(contents);
GURL url = browser->tab_strip_model()->GetActiveWebContents()->GetURL();
for (PageActionViews::const_iterator i(page_action_views_.begin());
i != page_action_views_.end(); ++i) {
(*i)->UpdateVisibility(
GetToolbarModel()->input_in_progress() ? NULL : contents, url);
// Check if the visibility of the action changed and notify if it did.
ExtensionAction* action = (*i)->image_view()->page_action();
if (old_visibility.find(action) == old_visibility.end() ||
old_visibility[action] != (*i)->visible()) {
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
content::Source<ExtensionAction>(action),
content::Details<WebContents>(contents));
}
}
}
}
size_t LocationBarView::ScriptBubbleScriptsRunning() {
WebContents* contents = delegate_->GetWebContents();
if (!contents)
return false;
extensions::TabHelper* extensions_tab_helper =
extensions::TabHelper::FromWebContents(contents);
if (!extensions_tab_helper)
return false;
extensions::ScriptBubbleController* script_bubble_controller =
extensions_tab_helper->script_bubble_controller();
if (!script_bubble_controller)
return false;
size_t script_count =
script_bubble_controller->extensions_running_scripts().size();
return script_count;
}
void LocationBarView::RefreshScriptBubble() {
if (!script_bubble_icon_view_)
return;
size_t script_count = ScriptBubbleScriptsRunning();
script_bubble_icon_view_->SetVisible(script_count > 0);
if (script_count > 0)
script_bubble_icon_view_->SetScriptCount(script_count);
}
void LocationBarView::RefreshZoomView() {
DCHECK(zoom_view_);
WebContents* web_contents = GetWebContents();
if (!web_contents)
return;
ZoomController* zoom_controller =
ZoomController::FromWebContents(web_contents);
zoom_view_->Update(zoom_controller);
}
#if defined(OS_WIN) && !defined(USE_AURA)
void LocationBarView::OnMouseEvent(const ui::MouseEvent& event, UINT msg) {
OmniboxViewWin* omnibox_win = GetOmniboxViewWin(location_entry_.get());
if (omnibox_win) {
UINT flags = event.native_event().wParam;
gfx::Point screen_point(event.location());
ConvertPointToScreen(this, &screen_point);
omnibox_win->HandleExternalMsg(msg, flags, screen_point.ToPOINT());
}
}
#endif
bool LocationBarView::HasValidSuggestText() const { bool LocationBarView::HasValidSuggestText() const {
return suggested_text_view_->visible() && return suggested_text_view_->visible() &&
!suggested_text_view_->size().IsEmpty(); !suggested_text_view_->size().IsEmpty();
} }
void LocationBarView::ShowFirstRunBubbleInternal() {
#if !defined(OS_CHROMEOS)
// First run bubble doesn't make sense for Chrome OS.
Browser* browser = GetBrowserFromDelegate(delegate_);
if (!browser)
return; // Possible when browser is shutting down.
FirstRunBubble::ShowBubble(browser, location_icon_view_);
#endif
}
void LocationBarView::PaintPageActionBackgrounds(gfx::Canvas* canvas) {
WebContents* web_contents = GetWebContents();
// web_contents may be NULL while the browser is shutting down.
if (!web_contents)
return;
const int32 tab_id = SessionID::IdForTab(web_contents);
const ToolbarModel::SecurityLevel security_level =
GetToolbarModel()->GetSecurityLevel(false);
const SkColor text_color = GetColor(security_level, TEXT);
const SkColor background_color = GetColor(security_level, BACKGROUND);
for (PageActionViews::const_iterator
page_action_view = page_action_views_.begin();
page_action_view != page_action_views_.end();
++page_action_view) {
gfx::Rect bounds = (*page_action_view)->bounds();
int horizontal_padding =
GetItemPadding() - GetBuiltInHorizontalPaddingForChildViews();
// Make the bounding rectangle include the whole vertical range of the
// location bar, and the mid-point pixels between adjacent page actions.
//
// For odd horizontal_paddings, "horizontal_padding + 1" includes the
// mid-point between two page actions in the bounding rectangle. For even
// paddings, the +1 is dropped, which is right since there is no pixel at
// the mid-point.
bounds.Inset(-(horizontal_padding + 1) / 2, 0);
location_bar_util::PaintExtensionActionBackground(
*(*page_action_view)->image_view()->page_action(),
tab_id, canvas, bounds, text_color, background_color);
}
}
void LocationBarView::AccessibilitySetValue(const string16& new_value) {
location_entry_->SetUserText(new_value);
}
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "base/prefs/pref_member.h" #include "base/prefs/pref_member.h"
#include "chrome/browser/extensions/extension_context_menu_model.h" #include "chrome/browser/extensions/extension_context_menu_model.h"
#include "chrome/browser/search_engines/template_url_service_observer.h" #include "chrome/browser/search_engines/template_url_service_observer.h"
...@@ -413,9 +414,6 @@ class LocationBarView : public LocationBar, ...@@ -413,9 +414,6 @@ class LocationBarView : public LocationBar,
// Update the view for the zoom icon based on the current tab's zoom. // Update the view for the zoom icon based on the current tab's zoom.
void RefreshZoomView(); void RefreshZoomView();
// Sets the visibility of view to new_vis.
void ToggleVisibility(bool new_vis, views::View* view);
#if !defined(USE_AURA) #if !defined(USE_AURA)
// Helper for the Mouse event handlers that does all the real work. // Helper for the Mouse event handlers that does all the real work.
void OnMouseEvent(const ui::MouseEvent& event, UINT msg); void OnMouseEvent(const ui::MouseEvent& event, UINT msg);
...@@ -431,6 +429,11 @@ class LocationBarView : public LocationBar, ...@@ -431,6 +429,11 @@ class LocationBarView : public LocationBar,
// after layout, so the |page_action_views_| have their bounds. // after layout, so the |page_action_views_| have their bounds.
void PaintPageActionBackgrounds(gfx::Canvas* canvas); void PaintPageActionBackgrounds(gfx::Canvas* canvas);
// Handles a request to change the value of this text field from software
// using an accessibility API (typically automation software, screen readers
// don't normally use this). Sets the value and clears the selection.
void AccessibilitySetValue(const string16& new_value);
// The Browser this LocationBarView is in. Note that at least // The Browser this LocationBarView is in. Note that at least
// chromeos::SimpleWebViewDialog uses a LocationBarView outside any browser // chromeos::SimpleWebViewDialog uses a LocationBarView outside any browser
// window, so this may be NULL. // window, so this may be NULL.
...@@ -543,6 +546,9 @@ class LocationBarView : public LocationBar, ...@@ -543,6 +546,9 @@ class LocationBarView : public LocationBar,
// Used to register for notifications received by NotificationObserver. // Used to register for notifications received by NotificationObserver.
content::NotificationRegistrar registrar_; content::NotificationRegistrar registrar_;
// Used to bind callback functions to this object.
base::WeakPtrFactory<LocationBarView> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(LocationBarView); DISALLOW_COPY_AND_ASSIGN(LocationBarView);
}; };
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define UI_BASE_ACCESSIBILITY_ACCESSIBLE_VIEW_STATE_H_ #define UI_BASE_ACCESSIBILITY_ACCESSIBLE_VIEW_STATE_H_
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/callback.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "ui/base/accessibility/accessibility_types.h" #include "ui/base/accessibility/accessibility_types.h"
#include "ui/base/ui_export.h" #include "ui/base/ui_export.h"
...@@ -54,6 +55,17 @@ struct UI_EXPORT AccessibleViewState { ...@@ -54,6 +55,17 @@ struct UI_EXPORT AccessibleViewState {
// index and count should be -1 otherwise. // index and count should be -1 otherwise.
int index; int index;
int count; int count;
// An optional callback that can be used by accessibility clients to
// set the string value of this view. This only applies to roles where
// setting the value makes sense, like a text box. Not often used by
// screen readers, but often used by automation software to script
// things like logging into portals or filling forms.
//
// This callback is only valid for the lifetime of the view, and should
// be a safe no-op if the view is deleted. Typically, accessible views
// should use a WeakPtr when binding the callback.
base::Callback<void(const base::string16&)> set_value_callback;
}; };
} // namespace ui } // namespace ui
......
...@@ -582,8 +582,8 @@ STDMETHODIMP NativeViewAccessibilityWin::get_accState( ...@@ -582,8 +582,8 @@ STDMETHODIMP NativeViewAccessibilityWin::get_accState(
return S_OK; return S_OK;
} }
STDMETHODIMP NativeViewAccessibilityWin::get_accValue( STDMETHODIMP NativeViewAccessibilityWin::get_accValue(VARIANT var_id,
VARIANT var_id, BSTR* value) { BSTR* value) {
if (!IsValidId(var_id) || !value) if (!IsValidId(var_id) || !value)
return E_INVALIDARG; return E_INVALIDARG;
...@@ -607,6 +607,24 @@ STDMETHODIMP NativeViewAccessibilityWin::get_accValue( ...@@ -607,6 +607,24 @@ STDMETHODIMP NativeViewAccessibilityWin::get_accValue(
return S_OK; return S_OK;
} }
STDMETHODIMP NativeViewAccessibilityWin::put_accValue(VARIANT var_id,
BSTR new_value) {
if (!IsValidId(var_id) || !new_value)
return E_INVALIDARG;
if (!view_)
return E_FAIL;
// Return an error if the view can't set the value.
ui::AccessibleViewState state;
view_->GetAccessibleState(&state);
if (state.set_value_callback.is_null())
return E_FAIL;
state.set_value_callback.Run(new_value);
return S_OK;
}
// IAccessible functions not supported. // IAccessible functions not supported.
STDMETHODIMP NativeViewAccessibilityWin::get_accSelection(VARIANT* selected) { STDMETHODIMP NativeViewAccessibilityWin::get_accSelection(VARIANT* selected) {
...@@ -644,12 +662,6 @@ STDMETHODIMP NativeViewAccessibilityWin::put_accName( ...@@ -644,12 +662,6 @@ STDMETHODIMP NativeViewAccessibilityWin::put_accName(
return E_NOTIMPL; return E_NOTIMPL;
} }
STDMETHODIMP NativeViewAccessibilityWin::put_accValue(
VARIANT var_id, BSTR put_val) {
// Deprecated.
return E_NOTIMPL;
}
// //
// IAccessible2 // IAccessible2
// //
......
...@@ -114,10 +114,11 @@ NativeViewAccessibilityWin ...@@ -114,10 +114,11 @@ NativeViewAccessibilityWin
// Retrieves the current state of the specified object. // Retrieves the current state of the specified object.
STDMETHODIMP get_accState(VARIANT var_id, VARIANT* state); STDMETHODIMP get_accState(VARIANT var_id, VARIANT* state);
// Retrieves the current value associated with the specified object. // Retrieve or set the string value associated with the specified object.
// Setting the value is not typically used by screen readers, but it's
// used frequently by automation software.
STDMETHODIMP get_accValue(VARIANT var_id, BSTR* value); STDMETHODIMP get_accValue(VARIANT var_id, BSTR* value);
STDMETHODIMP put_accValue(VARIANT var_id, BSTR new_value);
// Non-supported IAccessible methods.
// Selections not applicable to views. // Selections not applicable to views.
STDMETHODIMP get_accSelection(VARIANT* selected); STDMETHODIMP get_accSelection(VARIANT* selected);
...@@ -131,7 +132,6 @@ NativeViewAccessibilityWin ...@@ -131,7 +132,6 @@ NativeViewAccessibilityWin
// Deprecated functions, not implemented here. // Deprecated functions, not implemented here.
STDMETHODIMP put_accName(VARIANT var_id, BSTR put_name); STDMETHODIMP put_accName(VARIANT var_id, BSTR put_name);
STDMETHODIMP put_accValue(VARIANT var_id, BSTR put_val);
// //
// IAccessible2 // IAccessible2
......
// Copyright 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 <oleacc.h>
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_comptr.h"
#include "base/win/scoped_variant.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/views_test_base.h"
namespace views {
namespace test {
typedef ViewsTestBase NativeViewAcccessibilityWinTest;
TEST_F(NativeViewAcccessibilityWinTest, TextfieldAccessibility) {
Widget widget;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_POPUP);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget.Init(init_params);
View* content = new View;
widget.SetContentsView(content);
Textfield* textfield = new Textfield;
textfield->SetAccessibleName(L"Name");
textfield->SetText(L"Value");
content->AddChildView(textfield);
base::win::ScopedComPtr<IAccessible> content_accessible(
content->GetNativeViewAccessible());
LONG child_count = 0;
ASSERT_EQ(S_OK, content_accessible->get_accChildCount(&child_count));
ASSERT_EQ(1L, child_count);
base::win::ScopedComPtr<IDispatch> textfield_dispatch;
base::win::ScopedComPtr<IAccessible> textfield_accessible;
base::win::ScopedVariant child_index(1);
ASSERT_EQ(S_OK, content_accessible->get_accChild(
child_index, textfield_dispatch.Receive()));
ASSERT_EQ(S_OK, textfield_dispatch.QueryInterface(
textfield_accessible.Receive()));
base::win::ScopedBstr name;
base::win::ScopedVariant childid_self(CHILDID_SELF);
ASSERT_EQ(S_OK, textfield_accessible->get_accName(
childid_self, name.Receive()));
ASSERT_STREQ(L"Name", name);
base::win::ScopedBstr value;
ASSERT_EQ(S_OK, textfield_accessible->get_accValue(
childid_self, value.Receive()));
ASSERT_STREQ(L"Value", value);
base::win::ScopedBstr new_value(L"New value");
ASSERT_EQ(S_OK, textfield_accessible->put_accValue(childid_self, new_value));
ASSERT_STREQ(L"New value", textfield->text().c_str());
}
} // namespace test
} // namespace views
...@@ -85,7 +85,8 @@ Textfield::Textfield() ...@@ -85,7 +85,8 @@ Textfield::Textfield()
vertical_margins_were_set_(false), vertical_margins_were_set_(false),
vertical_alignment_(gfx::ALIGN_VCENTER), vertical_alignment_(gfx::ALIGN_VCENTER),
placeholder_text_color_(kDefaultPlaceholderTextColor), placeholder_text_color_(kDefaultPlaceholderTextColor),
text_input_type_(ui::TEXT_INPUT_TYPE_TEXT) { text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
weak_ptr_factory_(this) {
set_focusable(true); set_focusable(true);
if (ViewsDelegate::views_delegate) { if (ViewsDelegate::views_delegate) {
...@@ -110,7 +111,8 @@ Textfield::Textfield(StyleFlags style) ...@@ -110,7 +111,8 @@ Textfield::Textfield(StyleFlags style)
vertical_margins_were_set_(false), vertical_margins_were_set_(false),
vertical_alignment_(gfx::ALIGN_VCENTER), vertical_alignment_(gfx::ALIGN_VCENTER),
placeholder_text_color_(kDefaultPlaceholderTextColor), placeholder_text_color_(kDefaultPlaceholderTextColor),
text_input_type_(ui::TEXT_INPUT_TYPE_TEXT) { text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
weak_ptr_factory_(this) {
set_focusable(true); set_focusable(true);
if (IsObscured()) if (IsObscured())
SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
...@@ -502,6 +504,12 @@ void Textfield::GetAccessibleState(ui::AccessibleViewState* state) { ...@@ -502,6 +504,12 @@ void Textfield::GetAccessibleState(ui::AccessibleViewState* state) {
const ui::Range range = native_wrapper_->GetSelectedRange(); const ui::Range range = native_wrapper_->GetSelectedRange();
state->selection_start = range.start(); state->selection_start = range.start();
state->selection_end = range.end(); state->selection_end = range.end();
if (!read_only()) {
state->set_value_callback =
base::Bind(&Textfield::AccessibilitySetValue,
weak_ptr_factory_.GetWeakPtr());
}
} }
ui::TextInputClient* Textfield::GetTextInputClient() { ui::TextInputClient* Textfield::GetTextInputClient() {
...@@ -543,6 +551,9 @@ const char* Textfield::GetClassName() const { ...@@ -543,6 +551,9 @@ const char* Textfield::GetClassName() const {
return kViewClassName; return kViewClassName;
} }
////////////////////////////////////////////////////////////////////////////////
// Textfield, private:
gfx::Insets Textfield::GetTextInsets() const { gfx::Insets Textfield::GetTextInsets() const {
gfx::Insets insets = GetInsets(); gfx::Insets insets = GetInsets();
if (draw_border_ && native_wrapper_) if (draw_border_ && native_wrapper_)
...@@ -550,6 +561,13 @@ gfx::Insets Textfield::GetTextInsets() const { ...@@ -550,6 +561,13 @@ gfx::Insets Textfield::GetTextInsets() const {
return insets; return insets;
} }
void Textfield::AccessibilitySetValue(const string16& new_value) {
if (!read_only()) {
SetText(new_value);
ClearSelection();
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// NativeTextfieldWrapper, public: // NativeTextfieldWrapper, public:
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
...@@ -285,6 +286,11 @@ class VIEWS_EXPORT Textfield : public View { ...@@ -285,6 +286,11 @@ class VIEWS_EXPORT Textfield : public View {
// Returns the insets to the rectangle where text is actually painted. // Returns the insets to the rectangle where text is actually painted.
gfx::Insets GetTextInsets() const; gfx::Insets GetTextInsets() const;
// Handles a request to change the value of this text field from software
// using an accessibility API (typically automation software, screen readers
// don't normally use this). Sets the value and clears the selection.
void AccessibilitySetValue(const string16& new_value);
// This is the current listener for events from this Textfield. // This is the current listener for events from this Textfield.
TextfieldController* controller_; TextfieldController* controller_;
...@@ -344,6 +350,9 @@ class VIEWS_EXPORT Textfield : public View { ...@@ -344,6 +350,9 @@ class VIEWS_EXPORT Textfield : public View {
// The duration to reveal the last typed char for obscured textfields. // The duration to reveal the last typed char for obscured textfields.
base::TimeDelta obscured_reveal_duration_; base::TimeDelta obscured_reveal_duration_;
// Used to bind callback functions to this object.
base::WeakPtrFactory<Textfield> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(Textfield); DISALLOW_COPY_AND_ASSIGN(Textfield);
}; };
......
...@@ -696,6 +696,7 @@ ...@@ -696,6 +696,7 @@
'..', '..',
], ],
'sources': [ 'sources': [
'accessibility/native_view_accessibility_win_unittest.cc',
'accessible_pane_view_unittest.cc', 'accessible_pane_view_unittest.cc',
'animation/bounds_animator_unittest.cc', 'animation/bounds_animator_unittest.cc',
'bubble/bubble_border_unittest.cc', 'bubble/bubble_border_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment