diff options
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. |