// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "config.h" #include "AXObjectCache.h" #include "Document.h" #include "Frame.h" #include "RefPtr.h" #undef LOG #include "webkit/glue/webaccessibilitymanager_impl.h" #include "webkit/api/public/WebAccessibilityObject.h" #include "webkit/glue/glue_accessibility_object.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/webframe_impl.h" #include "webkit/glue/webview_impl.h" using WebKit::WebAccessibilityObject; using WebKit::WebView; namespace webkit_glue { // struct WebAccessibilityManagerImpl::GlueAccessibilityObjectRoot struct WebAccessibilityManagerImpl::GlueAccessibilityObjectRoot { GlueAccessibilityObjectRoot() {} // Root of the WebKit AccessibilityObject tree. RefPtr acc_obj_root_; }; /*static*/ WebAccessibilityManager* WebAccessibilityManager::Create() { return new WebAccessibilityManagerImpl(); } // class WebAccessibilityManagerImpl WebAccessibilityManagerImpl::WebAccessibilityManagerImpl() : root_(new GlueAccessibilityObjectRoot), acc_obj_id_(1000) { } WebAccessibilityManagerImpl::~WebAccessibilityManagerImpl() { int_to_glue_acc_obj_map_.clear(); acc_obj_to_int_map_.clear(); } bool WebAccessibilityManagerImpl::GetAccObjInfo(WebView* view, const WebAccessibility::InParams& in_params, WebAccessibility::OutParams* out_params) { if (!root_->acc_obj_root_ && !InitAccObjRoot(view)) { // Failure in retrieving or initializing the root. return false; } // Function input parameters. int object_id = in_params.object_id; int child_id = in_params.child_id; // Since ids assigned by Chrome starts at 1000, whereas platform-specific ids // used to reference a child will be in a wholly different range, we know // that any id that high should be treated as a non-direct descendant. if (in_params.child_id >= 1000) { // Object is not a direct child, re-map the input parameters accordingly. // The object to be retrieved is referred to by the |in_params.child_id|, as // a result of e.g. a focus event. The local |child_id| is set to 0, to // indicate that any function call should refer to the object itself. object_id = in_params.child_id; child_id = 0; } // Find GlueAccessibilityObject requested by |object_id|. IntToGlueAccObjMap::iterator it = int_to_glue_acc_obj_map_.find(object_id); if (it == int_to_glue_acc_obj_map_.end() || !it->second) { // Map did not contain a valid instance of the data requested. return false; } RefPtr active_acc_obj = it->second; // Temp paramters for holding output information. RefPtr out_acc_obj = NULL; WebCore::String out_string; switch (in_params.function_id) { case WebAccessibility::FUNCTION_DODEFAULTACTION : if (!active_acc_obj->DoDefaultAction(child_id)) return false; break; case WebAccessibility::FUNCTION_HITTEST : out_acc_obj = active_acc_obj->HitTest(in_params.input_long1, in_params.input_long2); if (!out_acc_obj.get()) return false; break; case WebAccessibility::FUNCTION_LOCATION : if (!active_acc_obj->Location(&out_params->output_long1, &out_params->output_long2, &out_params->output_long3, &out_params->output_long4, child_id)) { return false; } break; case WebAccessibility::FUNCTION_NAVIGATE : out_acc_obj = active_acc_obj->Navigate( static_cast(in_params.input_long1), child_id); if (!out_acc_obj.get()) return false; break; case WebAccessibility::FUNCTION_GETCHILD : if (child_id == 0) { // If child requested is self, stay with the same accessibility object. out_params->object_id = in_params.object_id; out_acc_obj = active_acc_obj.get(); } else { out_acc_obj = active_acc_obj->GetChild(child_id); } if (!out_acc_obj.get()) return false; break; case WebAccessibility::FUNCTION_CHILDCOUNT : if (!active_acc_obj->ChildCount(&out_params->output_long1)) return false; break; case WebAccessibility::FUNCTION_DEFAULTACTION : if (!active_acc_obj->DefaultAction(child_id, &out_string)) return false; break; case WebAccessibility::FUNCTION_DESCRIPTION : if (!active_acc_obj->Description(child_id, &out_string)) return false; break; case WebAccessibility::FUNCTION_GETFOCUSEDCHILD : out_acc_obj = active_acc_obj->GetFocusedChild(); if (!out_acc_obj.get()) return false; break; case WebAccessibility::FUNCTION_HELPTEXT : if (!active_acc_obj->HelpText(child_id, &out_string)) return false; break; case WebAccessibility::FUNCTION_KEYBOARDSHORTCUT : if (!active_acc_obj->KeyboardShortcut(child_id, &out_string)) return false; break; case WebAccessibility::FUNCTION_NAME : if (!active_acc_obj->Name(child_id, &out_string)) return false; break; case WebAccessibility::FUNCTION_GETPARENT : out_acc_obj = active_acc_obj->GetParent(); if (!out_acc_obj.get()) return false; break; case WebAccessibility::FUNCTION_ROLE : if (!active_acc_obj->Role(child_id, &out_params->output_long1)) return false; break; case WebAccessibility::FUNCTION_STATE : if (!active_acc_obj->State(child_id, &out_params->output_long1)) return false; break; case WebAccessibility::FUNCTION_VALUE : if (!active_acc_obj->Value(child_id, &out_string)) return false; break; default: // Non-supported function id. return false; } // Output and hashmap assignments, as appropriate. if (!out_string.isEmpty()) out_params->output_string = StringToString16(out_string); if (out_acc_obj) { AccObjToIntMap::iterator it = acc_obj_to_int_map_.find(out_acc_obj->accessibilityObject()); if (it != acc_obj_to_int_map_.end()) { // Data already present in map, return previously assigned id. out_params->object_id = it->second; out_params->output_long1 = -1; } else { // Insert new GlueAccessibilityObject in hashmaps. int_to_glue_acc_obj_map_[acc_obj_id_] = out_acc_obj.get(); acc_obj_to_int_map_[out_acc_obj->accessibilityObject()] = acc_obj_id_; out_params->object_id = acc_obj_id_++; out_params->output_long1 = -1; } } // TODO(klink): Handle simple objects returned. return true; } bool WebAccessibilityManagerImpl::InitAccObjRoot(WebView* view) { // Enable accessibility and retrieve Document. WebCore::AXObjectCache::enableAccessibility(); WebFrameImpl* main_frame_impl = static_cast(view->mainFrame()); if (!main_frame_impl || !main_frame_impl->frame()) return false; WebCore::Document* doc = main_frame_impl->frame()->document(); if (!doc || !doc->renderer()) return false; if (!root_->acc_obj_root_) { // Either we've never had a wrapper for this frame's top-level Document, // the Document renderer was destroyed and its wrapper was detached, or // the previous Document is in the page cache, and the current document // needs to be wrapped. root_->acc_obj_root_ = GlueAccessibilityObject::CreateInstance(doc-> axObjectCache()->getOrCreate(doc->renderer())); } // Insert root in hashmaps. int_to_glue_acc_obj_map_[acc_obj_id_] = root_->acc_obj_root_.get(); acc_obj_to_int_map_[root_->acc_obj_root_->accessibilityObject()] = acc_obj_id_++; return true; } bool WebAccessibilityManagerImpl::ClearAccObjMap(int acc_obj_id, bool clear_all) { if (clear_all) { // Clear maps and invalidate root. int_to_glue_acc_obj_map_.clear(); acc_obj_to_int_map_.clear(); root_->acc_obj_root_ = 0; return true; } IntToGlueAccObjMap::iterator it = int_to_glue_acc_obj_map_.find(acc_obj_id); if (it == int_to_glue_acc_obj_map_.end()) { // Element not found. return false; } if (it->second) { // Erase element from reverse hashmap. AccObjToIntMap::iterator it2 = acc_obj_to_int_map_.find(it->second->accessibilityObject()); if (it2 != acc_obj_to_int_map_.end()) acc_obj_to_int_map_.erase(it2); } int_to_glue_acc_obj_map_.erase(it); if (acc_obj_id == 1000) { // Invalidate root. root_->acc_obj_root_ = 0; } return true; } int WebAccessibilityManagerImpl::FocusAccObj( const WebAccessibilityObject& object) { if (object.isNull()) { // Return with failure. return -1; } RefPtr acc_obj = WebAccessibilityObjectToAccessibilityObject(object); AccObjToIntMap::iterator it = acc_obj_to_int_map_.find(acc_obj.get()); if (it != acc_obj_to_int_map_.end()) return it->second; // Insert new accessibility object in hashmaps and return its newly // assigned accessibility object id. int_to_glue_acc_obj_map_[acc_obj_id_] = GlueAccessibilityObject::CreateInstance(acc_obj.get()); acc_obj_to_int_map_[acc_obj.get()] = acc_obj_id_; return acc_obj_id_++; } } // namespace webkit_glue