| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "views/accessibility/view_accessibility.h" | 5 #include "views/accessibility/view_accessibility.h" |
| 6 | 6 |
| 7 #include "ui/base/view_prop.h" | 7 #include "ui/base/view_prop.h" |
| 8 #include "views/controls/button/native_button.h" | 8 #include "views/controls/button/native_button.h" |
| 9 #include "views/widget/widget.h" | 9 #include "views/widget/widget.h" |
| 10 #include "views/widget/widget_win.h" | 10 #include "views/widget/widget_win.h" |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 } | 101 } |
| 102 | 102 |
| 103 STDMETHODIMP ViewAccessibility::accLocation( | 103 STDMETHODIMP ViewAccessibility::accLocation( |
| 104 LONG* x_left, LONG* y_top, LONG* width, LONG* height, VARIANT var_id) { | 104 LONG* x_left, LONG* y_top, LONG* width, LONG* height, VARIANT var_id) { |
| 105 if (!IsValidId(var_id) || !x_left || !y_top || !width || !height) | 105 if (!IsValidId(var_id) || !x_left || !y_top || !width || !height) |
| 106 return E_INVALIDARG; | 106 return E_INVALIDARG; |
| 107 | 107 |
| 108 if (!view_) | 108 if (!view_) |
| 109 return E_FAIL; | 109 return E_FAIL; |
| 110 | 110 |
| 111 gfx::Rect view_bounds; | 111 if (!view_->bounds().IsEmpty()) { |
| 112 // Retrieving the parent View to be used for converting from view-to-screen | 112 *width = view_->width(); |
| 113 // coordinates. | 113 *height = view_->height(); |
| 114 views::View* parent = view_->GetParent(); | 114 gfx::Point topleft(view_->bounds().origin()); |
| 115 | 115 views::View::ConvertPointToScreen(view_->parent() ? view_->parent() : view_, |
| 116 if (parent == NULL) { | 116 &topleft); |
| 117 // If no parent, remain within the same View. | |
| 118 parent = view_; | |
| 119 } | |
| 120 | |
| 121 // Retrieve active View's bounds. | |
| 122 view_bounds = view_->bounds(); | |
| 123 | |
| 124 if (!view_bounds.IsEmpty()) { | |
| 125 *width = view_bounds.width(); | |
| 126 *height = view_bounds.height(); | |
| 127 | |
| 128 gfx::Point topleft(view_bounds.origin()); | |
| 129 views::View::ConvertPointToScreen(parent, &topleft); | |
| 130 *x_left = topleft.x(); | 117 *x_left = topleft.x(); |
| 131 *y_top = topleft.y(); | 118 *y_top = topleft.y(); |
| 132 } else { | 119 } else { |
| 133 return E_FAIL; | 120 return E_FAIL; |
| 134 } | 121 } |
| 135 return S_OK; | 122 return S_OK; |
| 136 } | 123 } |
| 137 | 124 |
| 138 STDMETHODIMP ViewAccessibility::accNavigate(LONG nav_dir, VARIANT start, | 125 STDMETHODIMP ViewAccessibility::accNavigate(LONG nav_dir, VARIANT start, |
| 139 VARIANT* end) { | 126 VARIANT* end) { |
| 140 if (start.vt != VT_I4 || !end) | 127 if (start.vt != VT_I4 || !end) |
| 141 return E_INVALIDARG; | 128 return E_INVALIDARG; |
| 142 | 129 |
| 143 if (!view_) | 130 if (!view_) |
| 144 return E_FAIL; | 131 return E_FAIL; |
| 145 | 132 |
| 146 switch (nav_dir) { | 133 switch (nav_dir) { |
| 147 case NAVDIR_FIRSTCHILD: | 134 case NAVDIR_FIRSTCHILD: |
| 148 case NAVDIR_LASTCHILD: { | 135 case NAVDIR_LASTCHILD: { |
| 149 if (start.lVal != CHILDID_SELF) { | 136 if (start.lVal != CHILDID_SELF) { |
| 150 // Start of navigation must be on the View itself. | 137 // Start of navigation must be on the View itself. |
| 151 return E_INVALIDARG; | 138 return E_INVALIDARG; |
| 152 } else if (view_->GetChildViewCount() == 0) { | 139 } else if (!view_->has_children()) { |
| 153 // No children found. | 140 // No children found. |
| 154 return S_FALSE; | 141 return S_FALSE; |
| 155 } | 142 } |
| 156 | 143 |
| 157 // Set child_id based on first or last child. | 144 // Set child_id based on first or last child. |
| 158 int child_id = 0; | 145 int child_id = 0; |
| 159 if (nav_dir == NAVDIR_LASTCHILD) { | 146 if (nav_dir == NAVDIR_LASTCHILD) |
| 160 child_id = view_->GetChildViewCount() - 1; | 147 child_id = view_->child_count() - 1; |
| 161 } | |
| 162 | 148 |
| 163 views::View* child = view_->GetChildViewAt(child_id); | 149 views::View* child = view_->GetChildViewAt(child_id); |
| 164 end->vt = VT_DISPATCH; | 150 end->vt = VT_DISPATCH; |
| 165 end->pdispVal = GetAccessibleForView(child); | 151 end->pdispVal = GetAccessibleForView(child); |
| 166 end->pdispVal->AddRef(); | 152 end->pdispVal->AddRef(); |
| 167 return S_OK; | 153 return S_OK; |
| 168 } | 154 } |
| 169 case NAVDIR_LEFT: | 155 case NAVDIR_LEFT: |
| 170 case NAVDIR_UP: | 156 case NAVDIR_UP: |
| 171 case NAVDIR_PREVIOUS: | 157 case NAVDIR_PREVIOUS: |
| 172 case NAVDIR_RIGHT: | 158 case NAVDIR_RIGHT: |
| 173 case NAVDIR_DOWN: | 159 case NAVDIR_DOWN: |
| 174 case NAVDIR_NEXT: { | 160 case NAVDIR_NEXT: { |
| 175 // Retrieve parent to access view index and perform bounds checking. | 161 // Retrieve parent to access view index and perform bounds checking. |
| 176 views::View* parent = view_->GetParent(); | 162 views::View* parent = view_->parent(); |
| 177 if (!parent) { | 163 if (!parent) { |
| 178 return E_FAIL; | 164 return E_FAIL; |
| 179 } | 165 } |
| 180 | 166 |
| 181 if (start.lVal == CHILDID_SELF) { | 167 if (start.lVal == CHILDID_SELF) { |
| 182 int view_index = parent->GetChildIndex(view_); | 168 int view_index = parent->GetIndexOf(view_); |
| 183 // Check navigation bounds, adjusting for View child indexing (MSAA | 169 // Check navigation bounds, adjusting for View child indexing (MSAA |
| 184 // child indexing starts with 1, whereas View indexing starts with 0). | 170 // child indexing starts with 1, whereas View indexing starts with 0). |
| 185 if (!IsValidNav(nav_dir, view_index, -1, | 171 if (!IsValidNav(nav_dir, view_index, -1, |
| 186 parent->GetChildViewCount() - 1)) { | 172 parent->child_count() - 1)) { |
| 187 // Navigation attempted to go out-of-bounds. | 173 // Navigation attempted to go out-of-bounds. |
| 188 end->vt = VT_EMPTY; | 174 end->vt = VT_EMPTY; |
| 189 return S_FALSE; | 175 return S_FALSE; |
| 190 } else { | 176 } else { |
| 191 if (IsNavDirNext(nav_dir)) { | 177 if (IsNavDirNext(nav_dir)) { |
| 192 view_index += 1; | 178 view_index += 1; |
| 193 } else { | 179 } else { |
| 194 view_index -=1; | 180 view_index -=1; |
| 195 } | 181 } |
| 196 } | 182 } |
| 197 | 183 |
| 198 views::View* child = parent->GetChildViewAt(view_index); | 184 views::View* child = parent->GetChildViewAt(view_index); |
| 199 end->pdispVal = GetAccessibleForView(child); | 185 end->pdispVal = GetAccessibleForView(child); |
| 200 end->vt = VT_DISPATCH; | 186 end->vt = VT_DISPATCH; |
| 201 end->pdispVal->AddRef(); | 187 end->pdispVal->AddRef(); |
| 202 return S_OK; | 188 return S_OK; |
| 203 } else { | 189 } else { |
| 204 // Check navigation bounds, adjusting for MSAA child indexing (MSAA | 190 // Check navigation bounds, adjusting for MSAA child indexing (MSAA |
| 205 // child indexing starts with 1, whereas View indexing starts with 0). | 191 // child indexing starts with 1, whereas View indexing starts with 0). |
| 206 if (!IsValidNav(nav_dir, start.lVal, 0, | 192 if (!IsValidNav(nav_dir, start.lVal, 0, parent->child_count() + 1)) { |
| 207 parent->GetChildViewCount() + 1)) { | |
| 208 // Navigation attempted to go out-of-bounds. | 193 // Navigation attempted to go out-of-bounds. |
| 209 end->vt = VT_EMPTY; | 194 end->vt = VT_EMPTY; |
| 210 return S_FALSE; | 195 return S_FALSE; |
| 211 } else { | 196 } else { |
| 212 if (IsNavDirNext(nav_dir)) { | 197 if (IsNavDirNext(nav_dir)) { |
| 213 start.lVal += 1; | 198 start.lVal += 1; |
| 214 } else { | 199 } else { |
| 215 start.lVal -= 1; | 200 start.lVal -= 1; |
| 216 } | 201 } |
| 217 } | 202 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 248 | 233 |
| 249 LONG child_id = V_I4(&var_child); | 234 LONG child_id = V_I4(&var_child); |
| 250 | 235 |
| 251 if (child_id == CHILDID_SELF) { | 236 if (child_id == CHILDID_SELF) { |
| 252 // Remain with the same dispatch. | 237 // Remain with the same dispatch. |
| 253 return S_OK; | 238 return S_OK; |
| 254 } | 239 } |
| 255 | 240 |
| 256 views::View* child_view = NULL; | 241 views::View* child_view = NULL; |
| 257 if (child_id > 0) { | 242 if (child_id > 0) { |
| 258 if (child_id <= view_->GetChildViewCount()) { | 243 int child_id_as_index = child_id - 1; |
| 244 if (child_id_as_index < view_->child_count()) { |
| 259 // Note: child_id is a one based index when indexing children. | 245 // Note: child_id is a one based index when indexing children. |
| 260 child_view = view_->GetChildViewAt(child_id - 1); | 246 child_view = view_->GetChildViewAt(child_id_as_index); |
| 261 } else { | 247 } else { |
| 262 // Attempt to retrieve a child view with the specified id. | 248 // Attempt to retrieve a child view with the specified id. |
| 263 child_view = view_->GetViewByID(child_id); | 249 child_view = view_->GetViewByID(child_id); |
| 264 } | 250 } |
| 265 } else { | 251 } else { |
| 266 // Negative values are used for events fired using the view's WidgetWin | 252 // Negative values are used for events fired using the view's WidgetWin |
| 267 views::WidgetWin* widget = | 253 views::WidgetWin* widget = |
| 268 static_cast<views::WidgetWin*>(view_->GetWidget()); | 254 static_cast<views::WidgetWin*>(view_->GetWidget()); |
| 269 child_view = widget->GetAccessibilityViewEventAt(child_id); | 255 child_view = widget->GetAccessibilityViewEventAt(child_id); |
| 270 } | 256 } |
| 271 | 257 |
| 272 if (!child_view) { | 258 if (!child_view) { |
| 273 // No child found. | 259 // No child found. |
| 274 *disp_child = NULL; | 260 *disp_child = NULL; |
| 275 return E_FAIL; | 261 return E_FAIL; |
| 276 } | 262 } |
| 277 | 263 |
| 278 *disp_child = GetAccessibleForView(child_view); | 264 *disp_child = GetAccessibleForView(child_view); |
| 279 (*disp_child)->AddRef(); | 265 (*disp_child)->AddRef(); |
| 280 return S_OK; | 266 return S_OK; |
| 281 } | 267 } |
| 282 | 268 |
| 283 STDMETHODIMP ViewAccessibility::get_accChildCount(LONG* child_count) { | 269 STDMETHODIMP ViewAccessibility::get_accChildCount(LONG* child_count) { |
| 284 if (!child_count || !view_) | 270 if (!child_count || !view_) |
| 285 return E_INVALIDARG; | 271 return E_INVALIDARG; |
| 286 | 272 |
| 287 if (!view_) | 273 if (!view_) |
| 288 return E_FAIL; | 274 return E_FAIL; |
| 289 | 275 |
| 290 *child_count = view_->GetChildViewCount(); | 276 *child_count = view_->child_count(); |
| 291 return S_OK; | 277 return S_OK; |
| 292 } | 278 } |
| 293 | 279 |
| 294 STDMETHODIMP ViewAccessibility::get_accDefaultAction( | 280 STDMETHODIMP ViewAccessibility::get_accDefaultAction( |
| 295 VARIANT var_id, BSTR* def_action) { | 281 VARIANT var_id, BSTR* def_action) { |
| 296 if (!IsValidId(var_id) || !def_action) | 282 if (!IsValidId(var_id) || !def_action) |
| 297 return E_INVALIDARG; | 283 return E_INVALIDARG; |
| 298 | 284 |
| 299 if (!view_) | 285 if (!view_) |
| 300 return E_FAIL; | 286 return E_FAIL; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 return E_FAIL; | 323 return E_FAIL; |
| 338 | 324 |
| 339 views::View* focus = NULL; | 325 views::View* focus = NULL; |
| 340 views::FocusManager* focus_manager = view_->GetFocusManager(); | 326 views::FocusManager* focus_manager = view_->GetFocusManager(); |
| 341 if (focus_manager) | 327 if (focus_manager) |
| 342 focus = focus_manager->GetFocusedView(); | 328 focus = focus_manager->GetFocusedView(); |
| 343 if (focus == view_) { | 329 if (focus == view_) { |
| 344 // This view has focus. | 330 // This view has focus. |
| 345 focus_child->vt = VT_I4; | 331 focus_child->vt = VT_I4; |
| 346 focus_child->lVal = CHILDID_SELF; | 332 focus_child->lVal = CHILDID_SELF; |
| 347 } else if (focus && view_->IsParentOf(focus)) { | 333 } else if (focus && view_->Contains(focus)) { |
| 348 // Return the child object that has the keyboard focus. | 334 // Return the child object that has the keyboard focus. |
| 349 focus_child->pdispVal = GetAccessibleForView(focus); | 335 focus_child->pdispVal = GetAccessibleForView(focus); |
| 350 focus_child->pdispVal->AddRef(); | 336 focus_child->pdispVal->AddRef(); |
| 351 return S_OK; | 337 return S_OK; |
| 352 } else { | 338 } else { |
| 353 // Neither this object nor any of its children has the keyboard focus. | 339 // Neither this object nor any of its children has the keyboard focus. |
| 354 focus_child->vt = VT_EMPTY; | 340 focus_child->vt = VT_EMPTY; |
| 355 } | 341 } |
| 356 return S_OK; | 342 return S_OK; |
| 357 } | 343 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 return S_OK; | 383 return S_OK; |
| 398 } | 384 } |
| 399 | 385 |
| 400 STDMETHODIMP ViewAccessibility::get_accParent(IDispatch** disp_parent) { | 386 STDMETHODIMP ViewAccessibility::get_accParent(IDispatch** disp_parent) { |
| 401 if (!disp_parent) | 387 if (!disp_parent) |
| 402 return E_INVALIDARG; | 388 return E_INVALIDARG; |
| 403 | 389 |
| 404 if (!view_) | 390 if (!view_) |
| 405 return E_FAIL; | 391 return E_FAIL; |
| 406 | 392 |
| 407 views::View* parent_view = view_->GetParent(); | 393 views::View* parent_view = view_->parent(); |
| 408 | 394 |
| 409 if (!parent_view) { | 395 if (!parent_view) { |
| 410 // This function can get called during teardown of WidetWin so we | 396 // This function can get called during teardown of WidetWin so we |
| 411 // should bail out if we fail to get the HWND. | 397 // should bail out if we fail to get the HWND. |
| 412 if (!view_->GetWidget() || !view_->GetWidget()->GetNativeView()) { | 398 if (!view_->GetWidget() || !view_->GetWidget()->GetNativeView()) { |
| 413 *disp_parent = NULL; | 399 *disp_parent = NULL; |
| 414 return S_FALSE; | 400 return S_FALSE; |
| 415 } | 401 } |
| 416 | 402 |
| 417 // For a View that has no parent (e.g. root), point the accessible parent to | 403 // For a View that has no parent (e.g. root), point the accessible parent to |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 void ViewAccessibility::SetState(VARIANT* msaa_state, views::View* view) { | 507 void ViewAccessibility::SetState(VARIANT* msaa_state, views::View* view) { |
| 522 // Ensure the output param is initialized to zero. | 508 // Ensure the output param is initialized to zero. |
| 523 msaa_state->lVal = 0; | 509 msaa_state->lVal = 0; |
| 524 | 510 |
| 525 // Default state; all views can have accessibility focus. | 511 // Default state; all views can have accessibility focus. |
| 526 msaa_state->lVal |= STATE_SYSTEM_FOCUSABLE; | 512 msaa_state->lVal |= STATE_SYSTEM_FOCUSABLE; |
| 527 | 513 |
| 528 if (!view) | 514 if (!view) |
| 529 return; | 515 return; |
| 530 | 516 |
| 531 if (!view->IsEnabled()) { | 517 if (!view->IsEnabled()) |
| 532 msaa_state->lVal |= STATE_SYSTEM_UNAVAILABLE; | 518 msaa_state->lVal |= STATE_SYSTEM_UNAVAILABLE; |
| 533 } | 519 if (!view->IsVisible()) |
| 534 if (!view->IsVisible()) { | |
| 535 msaa_state->lVal |= STATE_SYSTEM_INVISIBLE; | 520 msaa_state->lVal |= STATE_SYSTEM_INVISIBLE; |
| 536 } | 521 if (view->IsHotTracked()) |
| 537 if (view->IsHotTracked()) { | |
| 538 msaa_state->lVal |= STATE_SYSTEM_HOTTRACKED; | 522 msaa_state->lVal |= STATE_SYSTEM_HOTTRACKED; |
| 539 } | 523 if (view->IsPushed()) |
| 540 if (view->IsPushed()) { | |
| 541 msaa_state->lVal |= STATE_SYSTEM_PRESSED; | 524 msaa_state->lVal |= STATE_SYSTEM_PRESSED; |
| 542 } | |
| 543 // Check both for actual View focus, as well as accessibility focus. | |
| 544 views::View* parent = view->GetParent(); | |
| 545 | |
| 546 if (view->HasFocus()) | 525 if (view->HasFocus()) |
| 547 msaa_state->lVal |= STATE_SYSTEM_FOCUSED; | 526 msaa_state->lVal |= STATE_SYSTEM_FOCUSED; |
| 548 | 527 |
| 549 // Add on any view-specific states. | 528 // Add on any view-specific states. |
| 550 msaa_state->lVal |= MSAAState(view->GetAccessibleState()); | 529 msaa_state->lVal |= MSAAState(view->GetAccessibleState()); |
| 551 } | 530 } |
| 552 | 531 |
| 553 // IAccessible functions not supported. | 532 // IAccessible functions not supported. |
| 554 | 533 |
| 555 STDMETHODIMP ViewAccessibility::get_accSelection(VARIANT* selected) { | 534 STDMETHODIMP ViewAccessibility::get_accSelection(VARIANT* selected) { |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 739 HWND native_view_window , IAccessible** accessible) { | 718 HWND native_view_window , IAccessible** accessible) { |
| 740 if (IsWindow(native_view_window)) { | 719 if (IsWindow(native_view_window)) { |
| 741 LRESULT ret = SendMessage(native_view_window, WM_GETOBJECT, 0, | 720 LRESULT ret = SendMessage(native_view_window, WM_GETOBJECT, 0, |
| 742 OBJID_CLIENT); | 721 OBJID_CLIENT); |
| 743 return ObjectFromLresult(ret, IID_IDispatch, 0, | 722 return ObjectFromLresult(ret, IID_IDispatch, 0, |
| 744 reinterpret_cast<void**>(accessible)); | 723 reinterpret_cast<void**>(accessible)); |
| 745 } | 724 } |
| 746 | 725 |
| 747 return E_FAIL; | 726 return E_FAIL; |
| 748 } | 727 } |
| OLD | NEW |