diff options
author | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-03 07:36:33 +0000 |
---|---|---|
committer | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-03 07:36:33 +0000 |
commit | 72f3f55b7fa7c0a2bb272bc250cc9b04826a8ca5 (patch) | |
tree | 46fb28291b141a3f431aeddfb51e0a02174be72c /content | |
parent | 4e039f24f17dd7b3bd12e572e82cca978188055a (diff) | |
download | chromium_src-72f3f55b7fa7c0a2bb272bc250cc9b04826a8ca5.zip chromium_src-72f3f55b7fa7c0a2bb272bc250cc9b04826a8ca5.tar.gz chromium_src-72f3f55b7fa7c0a2bb272bc250cc9b04826a8ca5.tar.bz2 |
Initial implementation of IAccessible2 scrollTo and setTextSelection and
related methods. Scrolling currently only handles the main frame, though
it's designed to be extended to support scrolling any scrollable container
shortly. Setting the text selection is only implemented for <input>
elements, pending WebKit enhancements.
BUG=104468,104469
TEST=Adds new test for scrolling logic, manual testing with accProbe.
Review URL: http://codereview.chromium.org/8770021
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112880 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
4 files changed, 318 insertions, 35 deletions
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index 9bed3ac..d365628 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc @@ -163,6 +163,92 @@ BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint( return this; } +void BrowserAccessibility::ScrollToMakeVisible(const gfx::Rect& subfocus, + const gfx::Rect& focus, + const gfx::Rect& viewport) { + int scroll_x = 0; + int scroll_x_min = 0; + int scroll_x_max = 0; + int scroll_y = 0; + int scroll_y_min = 0; + int scroll_y_max = 0; + if (!GetIntAttribute(WebAccessibility::ATTR_SCROLL_X, &scroll_x) || + !GetIntAttribute(WebAccessibility::ATTR_SCROLL_X_MIN, &scroll_x_min) || + !GetIntAttribute(WebAccessibility::ATTR_SCROLL_X_MAX, &scroll_x_max) || + !GetIntAttribute(WebAccessibility::ATTR_SCROLL_Y, &scroll_y) || + !GetIntAttribute(WebAccessibility::ATTR_SCROLL_Y_MIN, &scroll_y_min) || + !GetIntAttribute(WebAccessibility::ATTR_SCROLL_Y_MAX, &scroll_y_max)) { + return; + } + + gfx::Rect final_viewport(0, 0, location_.width(), location_.height()); + final_viewport.Intersect(viewport); + + int new_scroll_x = ComputeBestScrollOffset( + scroll_x, + subfocus.x(), subfocus.right(), + focus.x(), focus.right(), + final_viewport.x(), final_viewport.right()); + new_scroll_x = std::max(new_scroll_x, scroll_x_min); + new_scroll_x = std::min(new_scroll_x, scroll_x_max); + + int new_scroll_y = ComputeBestScrollOffset( + scroll_y, + subfocus.y(), subfocus.bottom(), + focus.y(), focus.bottom(), + final_viewport.y(), final_viewport.bottom()); + new_scroll_y = std::max(new_scroll_y, scroll_y_min); + new_scroll_y = std::min(new_scroll_y, scroll_y_max); + + manager_->ChangeScrollPosition(*this, new_scroll_x, new_scroll_y); +} + +// static +int BrowserAccessibility::ComputeBestScrollOffset( + int current_scroll_offset, + int subfocus_min, int subfocus_max, + int focus_min, int focus_max, + int viewport_min, int viewport_max) { + int viewport_size = viewport_max - viewport_min; + + // If the focus size is larger than the viewport size, shrink it in the + // direction of subfocus. + if (focus_max - focus_min > viewport_size) { + // Subfocus must be within focus: + subfocus_min = std::max(subfocus_min, focus_min); + subfocus_max = std::min(subfocus_max, focus_max); + + // Subfocus must be no larger than the viewport size; favor top/left. + if (subfocus_max - subfocus_min > viewport_size) + subfocus_max = subfocus_min + viewport_size; + + if (subfocus_min + viewport_size > focus_max) { + focus_min = focus_max - viewport_size; + } else { + focus_min = subfocus_min; + focus_max = subfocus_min + viewport_size; + } + } + + // Exit now if the focus is already within the viewport. + if (focus_min - current_scroll_offset >= viewport_min && + focus_max - current_scroll_offset <= viewport_max) { + return current_scroll_offset; + } + + // Scroll left if we're too far to the right. + if (focus_max - current_scroll_offset > viewport_max) + return focus_max - viewport_max; + + // Scroll right if we're too far to the left. + if (focus_min - current_scroll_offset < viewport_min) + return focus_min - viewport_min; + + // This shouldn't happen. + NOTREACHED(); + return current_scroll_offset; +} + void BrowserAccessibility::InternalAddReference() { ref_count_++; } diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h index 5b86072..b07518b 100644 --- a/content/browser/accessibility/browser_accessibility.h +++ b/content/browser/accessibility/browser_accessibility.h @@ -108,6 +108,53 @@ class CONTENT_EXPORT BrowserAccessibility { // (in global screen coordinates). BrowserAccessibility* BrowserAccessibilityForPoint(const gfx::Point& point); + // Scrolls this element so that the |focus| rect (in local coordinates + // relative to this element) is scrolled to fit within the given + // |viewport| (which is clipped to the actual bounds of this + // object if you specify something larger). If the whole focus area + // doesn't fit, you can specify |subfocus|, which will prioritize + // a smaller area within |focus|. + // + // Note that "focus" doesn't necessarily mean the rectangle must correspond + // to a focused element on the page; assistive technology might request + // that any object be made visible. + void ScrollToMakeVisible(const gfx::Rect& subfocus, + const gfx::Rect& focus, + const gfx::Rect& viewport); + + // This is a 1-dimensional scroll offset helper function that's applied + // separately in the horizontal and vertical directions, because the + // logic is the same. The goal is to compute the best scroll offset + // in order to make a focused item visible within a viewport. + // + // In case the whole focused item cannot fit, you can specify a + // subfocus - a smaller region within the focus that should + // be prioritized. If the whole focused item can fit, the subfocus is + // ignored. + // + // Example: the viewport is scrolled to the right just enough + // that the focus is in view. + // Before: + // +----------Viewport---------+ + // +----Focus---+ + // +--SubFocus--+ + // + // After: + // +----------Viewport---------+ + // +----Focus---+ + // +--SubFocus--+ + // + // When constraints cannot be fully satisfied, the min + // (left/top) position takes precedence over the max (right/bottom). + // + // Note that the return value represents the ideal new scroll offset. + // This may be out of range - the calling function should clip this + // to the available range. + static int ComputeBestScrollOffset(int current_scroll_offset, + int subfocus_min, int subfocus_max, + int focus_min, int focus_max, + int viewport_min, int viewport_max); + // // Reference counting // diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc index 5ffacd4..4e88ac0 100644 --- a/content/browser/accessibility/browser_accessibility_win.cc +++ b/content/browser/accessibility/browser_accessibility_win.cc @@ -4,6 +4,8 @@ #include "content/browser/accessibility/browser_accessibility_win.h" +#include <limits> + #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" @@ -726,6 +728,90 @@ STDMETHODIMP BrowserAccessibilityWin::get_relations( return S_OK; } +STDMETHODIMP BrowserAccessibilityWin::scrollTo(enum IA2ScrollType scroll_type) { + if (!instance_active_) + return E_FAIL; + + // TODO(dmazzoni): Extend this to scroll every scrollable element as + // needed, not just the root. + BrowserAccessibility* root = this; + while (root->parent()) + root = root->parent(); + + gfx::Rect r = location_; + gfx::Rect view(std::numeric_limits<int>::min(), + std::numeric_limits<int>::min(), + std::numeric_limits<int>::max(), + std::numeric_limits<int>::max()); + switch(scroll_type) { + case IA2_SCROLL_TYPE_TOP_LEFT: + root->ScrollToMakeVisible( + gfx::Rect(r.x(), r.y(), 0, 0), r, view); + break; + case IA2_SCROLL_TYPE_BOTTOM_RIGHT: + root->ScrollToMakeVisible( + gfx::Rect(r.right(), r.bottom(), 0, 0), r, view); + break; + case IA2_SCROLL_TYPE_TOP_EDGE: + root->ScrollToMakeVisible( + gfx::Rect(r.x(), r.y(), r.width(), 0), r, view); + break; + case IA2_SCROLL_TYPE_BOTTOM_EDGE: + root->ScrollToMakeVisible( + gfx::Rect(r.x(), r.bottom(), r.width(), 0), r, view); + break; + case IA2_SCROLL_TYPE_LEFT_EDGE: + root->ScrollToMakeVisible( + gfx::Rect(r.x(), r.y(), 0, r.height()), r, view); + break; + case IA2_SCROLL_TYPE_RIGHT_EDGE: + root->ScrollToMakeVisible( + gfx::Rect(r.right(), r.y(), 0, r.height()), r, view); + break; + case IA2_SCROLL_TYPE_ANYWHERE: + default: + root->ScrollToMakeVisible(r, r, view); + break; + } + + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::scrollToPoint( + enum IA2CoordinateType coordinate_type, + LONG x, + LONG y) { + if (!instance_active_) + return E_FAIL; + + // TODO(dmazzoni): Extend this to scroll every scrollable element as + // needed, not just the root. + BrowserAccessibility* root = this; + while (root->parent()) + root = root->parent(); + + if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) { + gfx::Point top_left = manager_->GetViewBounds().origin(); + x -= top_left.x(); + y -= top_left.y(); + } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) { + if (parent_) { + gfx::Rect parent_bounds = parent_->location(); + x += parent_bounds.x(); + y += parent_bounds.y(); + } + } else { + return E_INVALIDARG; + } + + gfx::Rect r = location_; + root->ScrollToMakeVisible(gfx::Rect(r.x(), r.y(), 0, 0), + r, + gfx::Rect(x, y, 0, 0)); + + return S_OK; +} + STDMETHODIMP BrowserAccessibilityWin::get_groupPosition( LONG* group_level, LONG* similar_items_in_group, @@ -1918,6 +2004,74 @@ STDMETHODIMP BrowserAccessibilityWin::get_offsetAtPoint( return S_OK; } +STDMETHODIMP BrowserAccessibilityWin::scrollSubstringTo( + LONG start_index, + LONG end_index, + enum IA2ScrollType scroll_type) { + // TODO(dmazzoni): adjust this for the start and end index, too. + return scrollTo(scroll_type); +} + +STDMETHODIMP BrowserAccessibilityWin::scrollSubstringToPoint( + LONG start_index, + LONG end_index, + enum IA2CoordinateType coordinate_type, + LONG x, LONG y) { + // TODO(dmazzoni): adjust this for the start and end index, too. + return scrollToPoint(coordinate_type, x, y); +} + +STDMETHODIMP BrowserAccessibilityWin::addSelection( + LONG start_offset, LONG end_offset) { + if (!instance_active_) + return E_FAIL; + + const string16& text_str = TextForIAccessibleText(); + HandleSpecialTextOffset(text_str, &start_offset); + HandleSpecialTextOffset(text_str, &end_offset); + + manager_->SetTextSelection(*this, start_offset, end_offset); + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::removeSelection(LONG selection_index) { + if (!instance_active_) + return E_FAIL; + + if (selection_index != 0) + return E_INVALIDARG; + + manager_->SetTextSelection(*this, 0, 0); + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::setCaretOffset(LONG offset) { + if (!instance_active_) + return E_FAIL; + + const string16& text_str = TextForIAccessibleText(); + HandleSpecialTextOffset(text_str, &offset); + manager_->SetTextSelection(*this, offset, offset); + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::setSelection(LONG selection_index, + LONG start_offset, + LONG end_offset) { + if (!instance_active_) + return E_FAIL; + + if (selection_index != 0) + return E_INVALIDARG; + + const string16& text_str = TextForIAccessibleText(); + HandleSpecialTextOffset(text_str, &start_offset); + HandleSpecialTextOffset(text_str, &end_offset); + + manager_->SetTextSelection(*this, start_offset, end_offset); + return S_OK; +} + // // IAccessibleValue methods. // @@ -2180,7 +2334,9 @@ STDMETHODIMP BrowserAccessibilityWin::get_computedStyleForProperties( } STDMETHODIMP BrowserAccessibilityWin::scrollTo(boolean placeTopLeft) { - return E_NOTIMPL; + return scrollTo(placeTopLeft ? + IA2_SCROLL_TYPE_TOP_LEFT : + IA2_SCROLL_TYPE_ANYWHERE); } STDMETHODIMP BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode** node) { diff --git a/content/browser/accessibility/browser_accessibility_win.h b/content/browser/accessibility/browser_accessibility_win.h index addb39b..db6d00f 100644 --- a/content/browser/accessibility/browser_accessibility_win.h +++ b/content/browser/accessibility/browser_accessibility_win.h @@ -194,6 +194,13 @@ BrowserAccessibilityWin IAccessibleRelation** relations, LONG* n_relations); + CONTENT_EXPORT STDMETHODIMP scrollTo(enum IA2ScrollType scroll_type); + + CONTENT_EXPORT STDMETHODIMP scrollToPoint( + enum IA2CoordinateType coordinate_type, + LONG x, + LONG y); + CONTENT_EXPORT STDMETHODIMP get_groupPosition(LONG* group_level, LONG* similar_items_in_group, LONG* position_in_group); @@ -202,15 +209,6 @@ BrowserAccessibilityWin CONTENT_EXPORT STDMETHODIMP get_extendedRole(BSTR* extended_role) { return E_NOTIMPL; } - CONTENT_EXPORT STDMETHODIMP scrollTo(enum IA2ScrollType scroll_type) { - return E_NOTIMPL; - } - CONTENT_EXPORT STDMETHODIMP scrollToPoint( - enum IA2CoordinateType coordinate_type, - LONG x, - LONG y) { - return E_NOTIMPL; - } CONTENT_EXPORT STDMETHODIMP get_localizedExtendedRole( BSTR* localized_extended_role) { return E_NOTIMPL; @@ -445,10 +443,28 @@ BrowserAccessibilityWin enum IA2CoordinateType coord_type, LONG* offset); + CONTENT_EXPORT STDMETHODIMP scrollSubstringTo( + LONG start_index, + LONG end_index, + enum IA2ScrollType scroll_type); + + CONTENT_EXPORT STDMETHODIMP scrollSubstringToPoint( + LONG start_index, + LONG end_index, + enum IA2CoordinateType coordinate_type, + LONG x, LONG y); + + CONTENT_EXPORT STDMETHODIMP addSelection(LONG start_offset, LONG end_offset); + + CONTENT_EXPORT STDMETHODIMP removeSelection(LONG selection_index); + + CONTENT_EXPORT STDMETHODIMP setCaretOffset(LONG offset); + + CONTENT_EXPORT STDMETHODIMP setSelection(LONG selection_index, + LONG start_offset, + LONG end_offset); + // IAccessibleText methods not implemented. - CONTENT_EXPORT STDMETHODIMP addSelection(LONG start_offset, LONG end_offset) { - return E_NOTIMPL; - } CONTENT_EXPORT STDMETHODIMP get_attributes(LONG offset, LONG* start_offset, LONG* end_offset, BSTR* text_attributes) { @@ -460,28 +476,6 @@ BrowserAccessibilityWin LONG* width, LONG* height) { return E_NOTIMPL; } - CONTENT_EXPORT STDMETHODIMP removeSelection(LONG selection_index) { - return E_NOTIMPL; - } - CONTENT_EXPORT STDMETHODIMP setCaretOffset(LONG offset) { - return E_NOTIMPL; - } - CONTENT_EXPORT STDMETHODIMP setSelection(LONG selection_index, - LONG start_offset, - LONG end_offset) { - return E_NOTIMPL; - } - CONTENT_EXPORT STDMETHODIMP scrollSubstringTo(LONG start_index, - LONG end_index, - enum IA2ScrollType scroll_type) { - return E_NOTIMPL; - } - CONTENT_EXPORT STDMETHODIMP scrollSubstringToPoint(LONG start_index, - LONG end_index, - enum IA2CoordinateType coordinate_type, - LONG x, LONG y) { - return E_NOTIMPL; - } // // IAccessibleValue methods. |