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

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

Issue 2410333005: Create AXAction and AXActionData as a way to simplify accessibility actions (Closed)
Patch Set: Fix Android compile 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
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 ui::AXAction action,
438 const ui::AXActionData& data) {
447 const WebDocument& document = GetMainDocument(); 439 const WebDocument& document = GetMainDocument();
448 if (document.isNull()) 440 if (document.isNull())
449 return; 441 return;
450 442
451 WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id); 443 WebAXObject root = document.accessibilityObject();
452 if (obj.isDetached()) { 444 if (!root.updateLayoutAndCheckValidity())
453 #ifndef NDEBUG
454 LOG(WARNING) << "DoDefaultAction on invalid object id " << acc_obj_id;
455 #endif
456 return; 445 return;
446
447 WebAXObject target = document.accessibilityObjectFromID(data.target_node_id);
448 WebAXObject anchor = document.accessibilityObjectFromID(data.anchor_node_id);
449 WebAXObject focus = document.accessibilityObjectFromID(data.focus_node_id);
450
451 switch (action) {
452 case ui::AX_ACTION_DO_DEFAULT:
453 target.performDefaultAction();
454 break;
455 case ui::AX_ACTION_HIT_TEST:
456 OnHitTest(data.target_point);
457 break;
458 case ui::AX_ACTION_SCROLL_TO_MAKE_VISIBLE:
459 target.scrollToMakeVisibleWithSubFocus(
460 WebRect(data.target_rect.x(), data.target_rect.y(),
461 data.target_rect.width(), data.target_rect.height()));
462 break;
463 case ui::AX_ACTION_SCROLL_TO_POINT:
464 target.scrollToGlobalPoint(
465 WebPoint(data.target_point.x(), data.target_point.y()));
466 break;
467 case ui::AX_ACTION_SET_ACCESSIBILITY_FOCUS:
468 OnSetAccessibilityFocus(target);
469 break;
470 case ui::AX_ACTION_SET_FOCUS:
471 // By convention, calling SetFocus on the root of the tree should
472 // clear the current focus. Otherwise set the focus to the new node.
473 if (data.target_node_id == root.axID())
474 render_frame_->GetRenderView()->GetWebView()->clearFocusedElement();
475 else
476 target.setFocused(true);
477 break;
478 case ui::AX_ACTION_SET_SCROLL_OFFSET:
479 target.setScrollOffset(
480 WebPoint(data.target_point.x(), data.target_point.y()));
481 break;
482 case ui::AX_ACTION_SET_SELECTION:
483 anchor.setSelection(anchor, data.anchor_offset, focus, data.focus_offset);
484 HandleAXEvent(root, ui::AX_EVENT_LAYOUT_COMPLETE);
485 break;
486 case ui::AX_ACTION_SET_VALUE:
487 target.setValue(data.value);
488 HandleAXEvent(target, ui::AX_EVENT_VALUE_CHANGED);
489 break;
490 case ui::AX_ACTION_SHOW_CONTEXT_MENU:
491 target.showContextMenu();
492 break;
493 case ui::AX_ACTION_NONE:
494 NOTREACHED();
495 break;
457 } 496 }
458
459 obj.performDefaultAction();
460 } 497 }
461 498
462 void RenderAccessibilityImpl::OnEventsAck(int ack_token) { 499 void RenderAccessibilityImpl::OnEventsAck(int ack_token) {
463 // Ignore acks intended for a different or previous instance. 500 // Ignore acks intended for a different or previous instance.
464 if (ack_token_ != ack_token) 501 if (ack_token_ != ack_token)
465 return; 502 return;
466 503
467 DCHECK(ack_pending_); 504 DCHECK(ack_pending_);
468 ack_pending_ = false; 505 ack_pending_ = false;
469 SendPendingAccessibilityEvents(); 506 SendPendingAccessibilityEvents();
470 } 507 }
471 508
472 void RenderAccessibilityImpl::OnFatalError() { 509 void RenderAccessibilityImpl::OnFatalError() {
473 CHECK(false) << "Invalid accessibility tree."; 510 CHECK(false) << "Invalid accessibility tree.";
474 } 511 }
475 512
476 void RenderAccessibilityImpl::OnHitTest(gfx::Point point) { 513 void RenderAccessibilityImpl::OnHitTest(const gfx::Point& point) {
477 const WebDocument& document = GetMainDocument(); 514 const WebDocument& document = GetMainDocument();
478 if (document.isNull()) 515 if (document.isNull())
479 return; 516 return;
480 WebAXObject root_obj = document.accessibilityObject(); 517 WebAXObject root_obj = document.accessibilityObject();
481 if (!root_obj.updateLayoutAndCheckValidity()) 518 if (!root_obj.updateLayoutAndCheckValidity())
482 return; 519 return;
483 520
484 WebAXObject obj = root_obj.hitTest(point); 521 WebAXObject obj = root_obj.hitTest(point);
485 if (obj.isDetached()) 522 if (obj.isDetached())
486 return; 523 return;
487 524
488 // If the object that was hit has a child frame, we have to send a 525 // 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, 526 // message back to the browser to do the hit test in the child frame,
490 // recursively. 527 // recursively.
491 AXContentNodeData data; 528 AXContentNodeData data;
492 ScopedFreezeBlinkAXTreeSource freeze(&tree_source_); 529 ScopedFreezeBlinkAXTreeSource freeze(&tree_source_);
493 tree_source_.SerializeNode(obj, &data); 530 tree_source_.SerializeNode(obj, &data);
494 if (data.HasContentIntAttribute(AX_CONTENT_ATTR_CHILD_ROUTING_ID) || 531 if (data.HasContentIntAttribute(AX_CONTENT_ATTR_CHILD_ROUTING_ID) ||
495 data.HasContentIntAttribute( 532 data.HasContentIntAttribute(
496 AX_CONTENT_ATTR_CHILD_BROWSER_PLUGIN_INSTANCE_ID)) { 533 AX_CONTENT_ATTR_CHILD_BROWSER_PLUGIN_INSTANCE_ID)) {
497 Send(new AccessibilityHostMsg_ChildFrameHitTestResult(routing_id(), point, 534 Send(new AccessibilityHostMsg_ChildFrameHitTestResult(routing_id(), point,
498 obj.axID())); 535 obj.axID()));
499 return; 536 return;
500 } 537 }
501 538
502 // Otherwise, send a HOVER event on the node that was hit. 539 // Otherwise, send a HOVER event on the node that was hit.
503 HandleAXEvent(obj, ui::AX_EVENT_HOVER); 540 HandleAXEvent(obj, ui::AX_EVENT_HOVER);
504 } 541 }
505 542
506 void RenderAccessibilityImpl::OnSetAccessibilityFocus(int acc_obj_id) { 543 void RenderAccessibilityImpl::OnSetAccessibilityFocus(
544 const blink::WebAXObject& obj) {
507 ScopedFreezeBlinkAXTreeSource freeze(&tree_source_); 545 ScopedFreezeBlinkAXTreeSource freeze(&tree_source_);
508 if (tree_source_.accessibility_focus_id() == acc_obj_id) 546 if (tree_source_.accessibility_focus_id() == obj.axID())
509 return; 547 return;
510 548
511 tree_source_.set_accessibility_focus_id(acc_obj_id); 549 tree_source_.set_accessibility_focus_id(obj.axID());
512 550
513 const WebDocument& document = GetMainDocument(); 551 const WebDocument& document = GetMainDocument();
514 if (document.isNull()) 552 if (document.isNull())
515 return; 553 return;
516 554
517 WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id);
518
519 // This object may not be a leaf node. Force the whole subtree to be 555 // This object may not be a leaf node. Force the whole subtree to be
520 // re-serialized. 556 // re-serialized.
521 serializer_.DeleteClientSubtree(obj); 557 serializer_.DeleteClientSubtree(obj);
522 558
523 // Explicitly send a tree change update event now. 559 // Explicitly send a tree change update event now.
524 HandleAXEvent(obj, ui::AX_EVENT_TREE_CHANGED); 560 HandleAXEvent(obj, ui::AX_EVENT_TREE_CHANGED);
525 } 561 }
526 562
527 void RenderAccessibilityImpl::OnReset(int reset_token) { 563 void RenderAccessibilityImpl::OnReset(int reset_token) {
528 reset_token_ = reset_token; 564 reset_token_ = reset_token;
529 serializer_.Reset(); 565 serializer_.Reset();
530 pending_events_.clear(); 566 pending_events_.clear();
531 567
532 const WebDocument& document = GetMainDocument(); 568 const WebDocument& document = GetMainDocument();
533 if (!document.isNull()) { 569 if (!document.isNull()) {
534 // Tree-only mode gets used by the automation extension API which requires a 570 // Tree-only mode gets used by the automation extension API which requires a
535 // load complete event to invoke listener callbacks. 571 // load complete event to invoke listener callbacks.
536 ui::AXEvent evt = document.accessibilityObject().isLoaded() 572 ui::AXEvent evt = document.accessibilityObject().isLoaded()
537 ? ui::AX_EVENT_LOAD_COMPLETE : ui::AX_EVENT_LAYOUT_COMPLETE; 573 ? ui::AX_EVENT_LOAD_COMPLETE : ui::AX_EVENT_LAYOUT_COMPLETE;
538 HandleAXEvent(document.accessibilityObject(), evt); 574 HandleAXEvent(document.accessibilityObject(), evt);
539 } 575 }
540 } 576 }
541 577
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() { 578 void RenderAccessibilityImpl::OnDestruct() {
711 delete this; 579 delete this;
712 } 580 }
713 581
714 void RenderAccessibilityImpl::AddPluginTreeToUpdate( 582 void RenderAccessibilityImpl::AddPluginTreeToUpdate(
715 AXContentTreeUpdate* update) { 583 AXContentTreeUpdate* update) {
716 for (size_t i = 0; i < update->nodes.size(); ++i) { 584 for (size_t i = 0; i < update->nodes.size(); ++i) {
717 if (update->nodes[i].role == ui::AX_ROLE_EMBEDDED_OBJECT) { 585 if (update->nodes[i].role == ui::AX_ROLE_EMBEDDED_OBJECT) {
718 const ui::AXNode* root = plugin_tree_source_->GetRoot(); 586 const ui::AXNode* root = plugin_tree_source_->GetRoot();
719 update->nodes[i].child_ids.push_back(root->id()); 587 update->nodes[i].child_ids.push_back(root->id());
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
756 624
757 const WebDocument& document = GetMainDocument(); 625 const WebDocument& document = GetMainDocument();
758 if (document.isNull()) 626 if (document.isNull())
759 return; 627 return;
760 628
761 document.accessibilityObject().scrollToMakeVisibleWithSubFocus( 629 document.accessibilityObject().scrollToMakeVisibleWithSubFocus(
762 WebRect(bounds.x(), bounds.y(), bounds.width(), bounds.height())); 630 WebRect(bounds.x(), bounds.y(), bounds.width(), bounds.height()));
763 } 631 }
764 632
765 } // namespace content 633 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698