Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: content/renderer/accessibility/render_accessibility_impl.cc

Issue 2426193003: Re-land: Create AXAction and AXActionData as a way to simplify accessibility actions (Closed)
Patch Set: Rebase Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/renderer/accessibility/render_accessibility_impl.h ('k') | ui/accessibility/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/renderer/accessibility/render_accessibility_impl.h" 5 #include "content/renderer/accessibility/render_accessibility_impl.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <queue> 10 #include <queue>
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 } 111 }
112 } 112 }
113 113
114 RenderAccessibilityImpl::~RenderAccessibilityImpl() { 114 RenderAccessibilityImpl::~RenderAccessibilityImpl() {
115 } 115 }
116 116
117 bool RenderAccessibilityImpl::OnMessageReceived(const IPC::Message& message) { 117 bool RenderAccessibilityImpl::OnMessageReceived(const IPC::Message& message) {
118 bool handled = true; 118 bool handled = true;
119 during_action_ = true; 119 during_action_ = true;
120 IPC_BEGIN_MESSAGE_MAP(RenderAccessibilityImpl, message) 120 IPC_BEGIN_MESSAGE_MAP(RenderAccessibilityImpl, message)
121 IPC_MESSAGE_HANDLER(AccessibilityMsg_SetFocus, OnSetFocus) 121 IPC_MESSAGE_HANDLER(AccessibilityMsg_PerformAction, OnPerformAction)
122 IPC_MESSAGE_HANDLER(AccessibilityMsg_DoDefaultAction, OnDoDefaultAction)
123 IPC_MESSAGE_HANDLER(AccessibilityMsg_Events_ACK, OnEventsAck) 122 IPC_MESSAGE_HANDLER(AccessibilityMsg_Events_ACK, OnEventsAck)
124 IPC_MESSAGE_HANDLER(AccessibilityMsg_ScrollToMakeVisible,
125 OnScrollToMakeVisible)
126 IPC_MESSAGE_HANDLER(AccessibilityMsg_ScrollToPoint, OnScrollToPoint)
127 IPC_MESSAGE_HANDLER(AccessibilityMsg_SetScrollOffset, OnSetScrollOffset)
128 IPC_MESSAGE_HANDLER(AccessibilityMsg_SetSelection, OnSetSelection)
129 IPC_MESSAGE_HANDLER(AccessibilityMsg_SetValue, OnSetValue)
130 IPC_MESSAGE_HANDLER(AccessibilityMsg_ShowContextMenu, OnShowContextMenu)
131 IPC_MESSAGE_HANDLER(AccessibilityMsg_HitTest, OnHitTest) 123 IPC_MESSAGE_HANDLER(AccessibilityMsg_HitTest, OnHitTest)
132 IPC_MESSAGE_HANDLER(AccessibilityMsg_SetAccessibilityFocus,
133 OnSetAccessibilityFocus)
134 IPC_MESSAGE_HANDLER(AccessibilityMsg_Reset, OnReset) 124 IPC_MESSAGE_HANDLER(AccessibilityMsg_Reset, OnReset)
135 IPC_MESSAGE_HANDLER(AccessibilityMsg_FatalError, OnFatalError) 125 IPC_MESSAGE_HANDLER(AccessibilityMsg_FatalError, OnFatalError)
136 IPC_MESSAGE_UNHANDLED(handled = false) 126 IPC_MESSAGE_UNHANDLED(handled = false)
137 IPC_END_MESSAGE_MAP() 127 IPC_END_MESSAGE_MAP()
138 during_action_ = false; 128 during_action_ = false;
139 return handled; 129 return handled;
140 } 130 }
141 131
142 void RenderAccessibilityImpl::HandleWebAccessibilityEvent( 132 void RenderAccessibilityImpl::HandleWebAccessibilityEvent(
143 const blink::WebAXObject& obj, blink::WebAXEvent event) { 133 const blink::WebAXObject& obj, blink::WebAXEvent event) {
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
436 std::vector<blink::WebAXObject> children; 426 std::vector<blink::WebAXObject> children;
437 tree_source_.GetChildren(obj, &children); 427 tree_source_.GetChildren(obj, &children);
438 for (size_t i = 0; i < children.size(); ++i) 428 for (size_t i = 0; i < children.size(); ++i)
439 objs_to_explore.push(children[i]); 429 objs_to_explore.push(children[i]);
440 } 430 }
441 locations_.swap(new_locations); 431 locations_.swap(new_locations);
442 432
443 Send(new AccessibilityHostMsg_LocationChanges(routing_id(), messages)); 433 Send(new AccessibilityHostMsg_LocationChanges(routing_id(), messages));
444 } 434 }
445 435
446 void RenderAccessibilityImpl::OnDoDefaultAction(int acc_obj_id) { 436 void RenderAccessibilityImpl::OnPerformAction(
437 const ui::AXActionData& data) {
447 const WebDocument& document = GetMainDocument(); 438 const WebDocument& document = GetMainDocument();
448 if (document.isNull()) 439 if (document.isNull())
449 return; 440 return;
450 441
451 WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id); 442 WebAXObject root = document.accessibilityObject();
452 if (obj.isDetached()) { 443 if (!root.updateLayoutAndCheckValidity())
453 #ifndef NDEBUG
454 LOG(WARNING) << "DoDefaultAction on invalid object id " << acc_obj_id;
455 #endif
456 return; 444 return;
445
446 WebAXObject target = document.accessibilityObjectFromID(data.target_node_id);
447 WebAXObject anchor = document.accessibilityObjectFromID(data.anchor_node_id);
448 WebAXObject focus = document.accessibilityObjectFromID(data.focus_node_id);
449
450 switch (data.action) {
451 case ui::AX_ACTION_DO_DEFAULT:
452 target.performDefaultAction();
453 break;
454 case ui::AX_ACTION_HIT_TEST:
455 OnHitTest(data.target_point);
456 break;
457 case ui::AX_ACTION_SCROLL_TO_MAKE_VISIBLE:
458 target.scrollToMakeVisibleWithSubFocus(
459 WebRect(data.target_rect.x(), data.target_rect.y(),
460 data.target_rect.width(), data.target_rect.height()));
461 break;
462 case ui::AX_ACTION_SCROLL_TO_POINT:
463 target.scrollToGlobalPoint(
464 WebPoint(data.target_point.x(), data.target_point.y()));
465 break;
466 case ui::AX_ACTION_SET_ACCESSIBILITY_FOCUS:
467 OnSetAccessibilityFocus(target);
468 break;
469 case ui::AX_ACTION_SET_FOCUS:
470 // By convention, calling SetFocus on the root of the tree should
471 // clear the current focus. Otherwise set the focus to the new node.
472 if (data.target_node_id == root.axID())
473 render_frame_->GetRenderView()->GetWebView()->clearFocusedElement();
474 else
475 target.setFocused(true);
476 break;
477 case ui::AX_ACTION_SET_SCROLL_OFFSET:
478 target.setScrollOffset(
479 WebPoint(data.target_point.x(), data.target_point.y()));
480 break;
481 case ui::AX_ACTION_SET_SELECTION:
482 anchor.setSelection(anchor, data.anchor_offset, focus, data.focus_offset);
483 HandleAXEvent(root, ui::AX_EVENT_LAYOUT_COMPLETE);
484 break;
485 case ui::AX_ACTION_SET_VALUE:
486 target.setValue(data.value);
487 HandleAXEvent(target, ui::AX_EVENT_VALUE_CHANGED);
488 break;
489 case ui::AX_ACTION_SHOW_CONTEXT_MENU:
490 target.showContextMenu();
491 break;
492 case ui::AX_ACTION_NONE:
493 NOTREACHED();
494 break;
457 } 495 }
458
459 obj.performDefaultAction();
460 } 496 }
461 497
462 void RenderAccessibilityImpl::OnEventsAck(int ack_token) { 498 void RenderAccessibilityImpl::OnEventsAck(int ack_token) {
463 // Ignore acks intended for a different or previous instance. 499 // Ignore acks intended for a different or previous instance.
464 if (ack_token_ != ack_token) 500 if (ack_token_ != ack_token)
465 return; 501 return;
466 502
467 DCHECK(ack_pending_); 503 DCHECK(ack_pending_);
468 ack_pending_ = false; 504 ack_pending_ = false;
469 SendPendingAccessibilityEvents(); 505 SendPendingAccessibilityEvents();
470 } 506 }
471 507
472 void RenderAccessibilityImpl::OnFatalError() { 508 void RenderAccessibilityImpl::OnFatalError() {
473 CHECK(false) << "Invalid accessibility tree."; 509 CHECK(false) << "Invalid accessibility tree.";
474 } 510 }
475 511
476 void RenderAccessibilityImpl::OnHitTest(gfx::Point point) { 512 void RenderAccessibilityImpl::OnHitTest(const gfx::Point& point) {
477 const WebDocument& document = GetMainDocument(); 513 const WebDocument& document = GetMainDocument();
478 if (document.isNull()) 514 if (document.isNull())
479 return; 515 return;
480 WebAXObject root_obj = document.accessibilityObject(); 516 WebAXObject root_obj = document.accessibilityObject();
481 if (!root_obj.updateLayoutAndCheckValidity()) 517 if (!root_obj.updateLayoutAndCheckValidity())
482 return; 518 return;
483 519
484 WebAXObject obj = root_obj.hitTest(point); 520 WebAXObject obj = root_obj.hitTest(point);
485 if (obj.isDetached()) 521 if (obj.isDetached())
486 return; 522 return;
487 523
488 // If the object that was hit has a child frame, we have to send a 524 // If the object that was hit has a child frame, we have to send a
489 // message back to the browser to do the hit test in the child frame, 525 // message back to the browser to do the hit test in the child frame,
490 // recursively. 526 // recursively.
491 AXContentNodeData data; 527 AXContentNodeData data;
492 ScopedFreezeBlinkAXTreeSource freeze(&tree_source_); 528 ScopedFreezeBlinkAXTreeSource freeze(&tree_source_);
493 tree_source_.SerializeNode(obj, &data); 529 tree_source_.SerializeNode(obj, &data);
494 if (data.HasContentIntAttribute(AX_CONTENT_ATTR_CHILD_ROUTING_ID) || 530 if (data.HasContentIntAttribute(AX_CONTENT_ATTR_CHILD_ROUTING_ID) ||
495 data.HasContentIntAttribute( 531 data.HasContentIntAttribute(
496 AX_CONTENT_ATTR_CHILD_BROWSER_PLUGIN_INSTANCE_ID)) { 532 AX_CONTENT_ATTR_CHILD_BROWSER_PLUGIN_INSTANCE_ID)) {
497 Send(new AccessibilityHostMsg_ChildFrameHitTestResult(routing_id(), point, 533 Send(new AccessibilityHostMsg_ChildFrameHitTestResult(routing_id(), point,
498 obj.axID())); 534 obj.axID()));
499 return; 535 return;
500 } 536 }
501 537
502 // Otherwise, send a HOVER event on the node that was hit. 538 // Otherwise, send a HOVER event on the node that was hit.
503 HandleAXEvent(obj, ui::AX_EVENT_HOVER); 539 HandleAXEvent(obj, ui::AX_EVENT_HOVER);
504 } 540 }
505 541
506 void RenderAccessibilityImpl::OnSetAccessibilityFocus(int acc_obj_id) { 542 void RenderAccessibilityImpl::OnSetAccessibilityFocus(
543 const blink::WebAXObject& obj) {
507 ScopedFreezeBlinkAXTreeSource freeze(&tree_source_); 544 ScopedFreezeBlinkAXTreeSource freeze(&tree_source_);
508 if (tree_source_.accessibility_focus_id() == acc_obj_id) 545 if (tree_source_.accessibility_focus_id() == obj.axID())
509 return; 546 return;
510 547
511 tree_source_.set_accessibility_focus_id(acc_obj_id); 548 tree_source_.set_accessibility_focus_id(obj.axID());
512 549
513 const WebDocument& document = GetMainDocument(); 550 const WebDocument& document = GetMainDocument();
514 if (document.isNull()) 551 if (document.isNull())
515 return; 552 return;
516 553
517 WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id);
518
519 // This object may not be a leaf node. Force the whole subtree to be 554 // This object may not be a leaf node. Force the whole subtree to be
520 // re-serialized. 555 // re-serialized.
521 serializer_.DeleteClientSubtree(obj); 556 serializer_.DeleteClientSubtree(obj);
522 557
523 // Explicitly send a tree change update event now. 558 // Explicitly send a tree change update event now.
524 HandleAXEvent(obj, ui::AX_EVENT_TREE_CHANGED); 559 HandleAXEvent(obj, ui::AX_EVENT_TREE_CHANGED);
525 } 560 }
526 561
527 void RenderAccessibilityImpl::OnReset(int reset_token) { 562 void RenderAccessibilityImpl::OnReset(int reset_token) {
528 reset_token_ = reset_token; 563 reset_token_ = reset_token;
529 serializer_.Reset(); 564 serializer_.Reset();
530 pending_events_.clear(); 565 pending_events_.clear();
531 566
532 const WebDocument& document = GetMainDocument(); 567 const WebDocument& document = GetMainDocument();
533 if (!document.isNull()) { 568 if (!document.isNull()) {
534 // Tree-only mode gets used by the automation extension API which requires a 569 // Tree-only mode gets used by the automation extension API which requires a
535 // load complete event to invoke listener callbacks. 570 // load complete event to invoke listener callbacks.
536 ui::AXEvent evt = document.accessibilityObject().isLoaded() 571 ui::AXEvent evt = document.accessibilityObject().isLoaded()
537 ? ui::AX_EVENT_LOAD_COMPLETE : ui::AX_EVENT_LAYOUT_COMPLETE; 572 ? ui::AX_EVENT_LOAD_COMPLETE : ui::AX_EVENT_LAYOUT_COMPLETE;
538 HandleAXEvent(document.accessibilityObject(), evt); 573 HandleAXEvent(document.accessibilityObject(), evt);
539 } 574 }
540 } 575 }
541 576
542 void RenderAccessibilityImpl::OnScrollToMakeVisible(
543 int acc_obj_id, gfx::Rect subfocus) {
544 if (plugin_tree_source_ && plugin_tree_source_->GetFromId(acc_obj_id)) {
545 ScrollPlugin(acc_obj_id);
546 return;
547 }
548
549 const WebDocument& document = GetMainDocument();
550 if (document.isNull())
551 return;
552
553 WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id);
554 if (obj.isDetached()) {
555 #ifndef NDEBUG
556 LOG(WARNING) << "ScrollToMakeVisible on invalid object id " << acc_obj_id;
557 #endif
558 return;
559 }
560
561 obj.scrollToMakeVisibleWithSubFocus(
562 WebRect(subfocus.x(), subfocus.y(), subfocus.width(), subfocus.height()));
563
564 // Make sure the browser gets an event when the scroll
565 // position actually changes.
566 // TODO(dmazzoni): remove this once this bug is fixed:
567 // https://bugs.webkit.org/show_bug.cgi?id=73460
568 HandleAXEvent(document.accessibilityObject(), ui::AX_EVENT_LAYOUT_COMPLETE);
569 }
570
571 void RenderAccessibilityImpl::OnScrollToPoint(
572 int acc_obj_id, gfx::Point point) {
573 const WebDocument& document = GetMainDocument();
574 if (document.isNull())
575 return;
576
577 WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id);
578 if (obj.isDetached()) {
579 #ifndef NDEBUG
580 LOG(WARNING) << "ScrollToPoint on invalid object id " << acc_obj_id;
581 #endif
582 return;
583 }
584
585 obj.scrollToGlobalPoint(WebPoint(point.x(), point.y()));
586
587 // Make sure the browser gets an event when the scroll
588 // position actually changes.
589 // TODO(dmazzoni): remove this once this bug is fixed:
590 // https://bugs.webkit.org/show_bug.cgi?id=73460
591 HandleAXEvent(document.accessibilityObject(), ui::AX_EVENT_LAYOUT_COMPLETE);
592 }
593
594 void RenderAccessibilityImpl::OnSetScrollOffset(int acc_obj_id,
595 gfx::Point offset) {
596 const WebDocument& document = GetMainDocument();
597 if (document.isNull())
598 return;
599
600 WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id);
601 if (obj.isDetached())
602 return;
603
604 obj.setScrollOffset(WebPoint(offset.x(), offset.y()));
605 }
606
607 void RenderAccessibilityImpl::OnSetFocus(int acc_obj_id) {
608 const WebDocument& document = GetMainDocument();
609 if (document.isNull())
610 return;
611
612 WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id);
613 if (obj.isDetached()) {
614 #ifndef NDEBUG
615 LOG(WARNING) << "OnSetAccessibilityFocus on invalid object id "
616 << acc_obj_id;
617 #endif
618 return;
619 }
620
621 WebAXObject root = document.accessibilityObject();
622 if (root.isDetached()) {
623 #ifndef NDEBUG
624 LOG(WARNING) << "OnSetAccessibilityFocus but root is invalid";
625 #endif
626 return;
627 }
628
629 // By convention, calling SetFocus on the root of the tree should clear the
630 // current focus. Otherwise set the focus to the new node.
631 if (acc_obj_id == root.axID())
632 render_frame_->GetRenderView()->GetWebView()->clearFocusedElement();
633 else
634 obj.setFocused(true);
635 }
636
637 void RenderAccessibilityImpl::OnSetSelection(int anchor_acc_obj_id,
638 int anchor_offset,
639 int focus_acc_obj_id,
640 int focus_offset) {
641 const WebDocument& document = GetMainDocument();
642 if (document.isNull())
643 return;
644
645 WebAXObject anchor_obj =
646 document.accessibilityObjectFromID(anchor_acc_obj_id);
647 if (anchor_obj.isDetached()) {
648 #ifndef NDEBUG
649 LOG(WARNING) << "SetTextSelection on invalid object id "
650 << anchor_acc_obj_id;
651 #endif
652 return;
653 }
654
655 WebAXObject focus_obj = document.accessibilityObjectFromID(focus_acc_obj_id);
656 if (focus_obj.isDetached()) {
657 #ifndef NDEBUG
658 LOG(WARNING) << "SetTextSelection on invalid object id "
659 << focus_acc_obj_id;
660 #endif
661 return;
662 }
663
664 anchor_obj.setSelection(anchor_obj, anchor_offset, focus_obj, focus_offset);
665 WebAXObject root = document.accessibilityObject();
666 if (root.isDetached()) {
667 #ifndef NDEBUG
668 LOG(WARNING) << "OnSetAccessibilityFocus but root is invalid";
669 #endif
670 return;
671 }
672 HandleAXEvent(root, ui::AX_EVENT_LAYOUT_COMPLETE);
673 }
674
675 void RenderAccessibilityImpl::OnSetValue(
676 int acc_obj_id,
677 base::string16 value) {
678 const WebDocument& document = GetMainDocument();
679 if (document.isNull())
680 return;
681
682 WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id);
683 if (obj.isDetached()) {
684 #ifndef NDEBUG
685 LOG(WARNING) << "SetTextSelection on invalid object id " << acc_obj_id;
686 #endif
687 return;
688 }
689
690 obj.setValue(value);
691 HandleAXEvent(obj, ui::AX_EVENT_VALUE_CHANGED);
692 }
693
694 void RenderAccessibilityImpl::OnShowContextMenu(int acc_obj_id) {
695 const WebDocument& document = GetMainDocument();
696 if (document.isNull())
697 return;
698
699 WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id);
700 if (obj.isDetached()) {
701 #ifndef NDEBUG
702 LOG(WARNING) << "ShowContextMenu on invalid object id " << acc_obj_id;
703 #endif
704 return;
705 }
706
707 obj.showContextMenu();
708 }
709
710 void RenderAccessibilityImpl::OnDestruct() { 577 void RenderAccessibilityImpl::OnDestruct() {
711 delete this; 578 delete this;
712 } 579 }
713 580
714 void RenderAccessibilityImpl::AddPluginTreeToUpdate( 581 void RenderAccessibilityImpl::AddPluginTreeToUpdate(
715 AXContentTreeUpdate* update) { 582 AXContentTreeUpdate* update) {
716 for (size_t i = 0; i < update->nodes.size(); ++i) { 583 for (size_t i = 0; i < update->nodes.size(); ++i) {
717 if (update->nodes[i].role == ui::AX_ROLE_EMBEDDED_OBJECT) { 584 if (update->nodes[i].role == ui::AX_ROLE_EMBEDDED_OBJECT) {
718 const ui::AXNode* root = plugin_tree_source_->GetRoot(); 585 const ui::AXNode* root = plugin_tree_source_->GetRoot();
719 update->nodes[i].child_ids.push_back(root->id()); 586 update->nodes[i].child_ids.push_back(root->id());
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
756 623
757 const WebDocument& document = GetMainDocument(); 624 const WebDocument& document = GetMainDocument();
758 if (document.isNull()) 625 if (document.isNull())
759 return; 626 return;
760 627
761 document.accessibilityObject().scrollToMakeVisibleWithSubFocus( 628 document.accessibilityObject().scrollToMakeVisibleWithSubFocus(
762 WebRect(bounds.x(), bounds.y(), bounds.width(), bounds.height())); 629 WebRect(bounds.x(), bounds.y(), bounds.width(), bounds.height()));
763 } 630 }
764 631
765 } // namespace content 632 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/accessibility/render_accessibility_impl.h ('k') | ui/accessibility/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698