diff options
Diffstat (limited to 'webkit/glue')
-rw-r--r-- | webkit/glue/glue_accessibility.cc | 281 | ||||
-rw-r--r-- | webkit/glue/glue_accessibility.h | 68 |
2 files changed, 349 insertions, 0 deletions
diff --git a/webkit/glue/glue_accessibility.cc b/webkit/glue/glue_accessibility.cc new file mode 100644 index 0000000..60c1cf9 --- /dev/null +++ b/webkit/glue/glue_accessibility.cc @@ -0,0 +1,281 @@ +// 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 <comdef.h> + +#include "config.h" + +#pragma warning(push, 0) +#include "AccessibleDocument.h" +#include "AXObjectCache.h" +#include "Document.h" +#include "Frame.h" +#pragma warning(pop) +#undef LOG + +#include "webkit/glue/glue_accessibility.h" + +#include "chrome/browser/iaccessible_function_ids.h" +#include "webkit/glue/webframe_impl.h" +#include "webkit/glue/webview_impl.h" + +// struct GlueAccessibility::GlueAccessibilityRoot +struct GlueAccessibility::GlueAccessibilityRoot { + GlueAccessibilityRoot() {} + + // Root of the WebKit IAccessible tree. + COMPtr<AccessibleDocument> accessibility_root_; +}; + +// class GlueAccessibility +GlueAccessibility::GlueAccessibility() + : root_(new GlueAccessibilityRoot) { +} + +GlueAccessibility::~GlueAccessibility() { + delete root_; +} + +bool GlueAccessibility::GetAccessibilityInfo(WebView* view, + const ViewMsg_Accessibility_In_Params& in_params, + ViewHostMsg_Accessibility_Out_Params* out_params) { + if (!root_->accessibility_root_ && !InitAccessibilityRoot(view)) { + // Failure in retrieving the root. + return false; + } + + // Temporary storing for the currently active IAccessible. + COMPtr<IAccessible> active_iaccessible; + IntToIAccessibleMap::iterator it = + int_to_iaccessible_map_.find(in_params.iaccessible_id); + + if (it == int_to_iaccessible_map_.end()) { + // Map did not contain the data requested. + return false; + } + + active_iaccessible = it->second; + + if (!active_iaccessible) { + // Requested IAccessible not found. Paranoia check. + NOTREACHED(); + return false; + } + + // Input VARIANT, determined by the browser side to be of type VT_I4. + VARIANT input_variant; + input_variant.vt = VT_I4; + input_variant.lVal = in_params.input_variant_lval; + + // Output variables, used locally to retrieve data. + VARIANT output_variant; + ::VariantInit(&output_variant); + BSTR output_bstr; + bool string_output = false; + HRESULT hr = S_FALSE; + + switch (in_params.iaccessible_function_id) { + case IACCESSIBLE_FUNC_ACCDODEFAULTACTION : + hr = active_iaccessible->accDoDefaultAction(input_variant); + break; + case IACCESSIBLE_FUNC_ACCHITTEST : + hr = active_iaccessible->accHitTest(in_params.input_long1, + in_params.input_long2, + &output_variant); + break; + case IACCESSIBLE_FUNC_ACCLOCATION : + hr = active_iaccessible->accLocation(&out_params->output_long1, + &out_params->output_long2, + &out_params->output_long3, + &out_params->output_long4, + input_variant); + break; + case IACCESSIBLE_FUNC_ACCNAVIGATE : + hr = active_iaccessible->accNavigate(in_params.input_long1, input_variant, + &output_variant); + break; + case IACCESSIBLE_FUNC_GET_ACCCHILD : + if (input_variant.lVal == CHILDID_SELF) { + // If child requested is CHILDID_SELF, stay with the same IAccessible. + out_params->iaccessible_id = in_params.iaccessible_id; + hr = S_OK; + break; + } + hr = active_iaccessible->get_accChild(input_variant, + reinterpret_cast<IDispatch **>(&output_variant.pdispVal)); + output_variant.vt = VT_DISPATCH; + break; + case IACCESSIBLE_FUNC_GET_ACCCHILDCOUNT : + hr = active_iaccessible->get_accChildCount(&out_params->output_long1); + break; + case IACCESSIBLE_FUNC_GET_ACCDEFAULTACTION : + hr = active_iaccessible->get_accDefaultAction(input_variant, + &output_bstr); + string_output = true; + break; + case IACCESSIBLE_FUNC_GET_ACCDESCRIPTION : + hr = active_iaccessible->get_accDescription(input_variant, &output_bstr); + string_output = true; + break; + case IACCESSIBLE_FUNC_GET_ACCFOCUS : + hr = active_iaccessible->get_accFocus(&output_variant); + break; + case IACCESSIBLE_FUNC_GET_ACCHELP : + hr = active_iaccessible->get_accHelp(input_variant, &output_bstr); + string_output = true; + break; + case IACCESSIBLE_FUNC_GET_ACCKEYBOARDSHORTCUT : + hr = active_iaccessible->get_accKeyboardShortcut(input_variant, + &output_bstr); + string_output = true; + break; + case IACCESSIBLE_FUNC_GET_ACCNAME : + hr = active_iaccessible->get_accName(input_variant, &output_bstr); + string_output = true; + break; + case IACCESSIBLE_FUNC_GET_ACCPARENT : + hr = active_iaccessible->get_accParent( + reinterpret_cast<IDispatch **>(&output_variant.pdispVal)); + output_variant.vt = VT_DISPATCH; + break; + case IACCESSIBLE_FUNC_GET_ACCROLE : + hr = active_iaccessible->get_accRole(input_variant, &output_variant); + break; + case IACCESSIBLE_FUNC_GET_ACCSTATE : + hr = active_iaccessible->get_accState(input_variant, &output_variant); + break; + case IACCESSIBLE_FUNC_GET_ACCVALUE : + hr = active_iaccessible->get_accValue(input_variant, &output_bstr); + string_output = true; + break; + default: + // Memory cleanup. + ::VariantClear(&input_variant); + ::VariantClear(&output_variant); + + // Non-supported function id. + return false; + } + + // Return code handling. + if (hr == S_OK) { + out_params->return_code = true; + + // All is ok, assign output string if needed. + if (string_output) { + out_params->output_string = _bstr_t(output_bstr); + ::SysFreeString(output_bstr); + } + + } else if (hr == S_FALSE) { + out_params->return_code = false; + } else { + // Memory cleanup. + ::VariantClear(&input_variant); + ::VariantClear(&output_variant); + + // Generate a generic failure on the browser side. Input validation is the + // responsibility of the browser side, as is correctly handling calls to + // non-supported functions appropriately. + return false; + } + + // Output and hashmap assignments, as appropriate. + if (output_variant.vt == VT_DISPATCH && output_variant.pdispVal) { + IAccessibleToIntMap::iterator it = + iaccessible_to_int_map_.find( + reinterpret_cast<IAccessible *>(output_variant.pdispVal)); + + if (it != iaccessible_to_int_map_.end()) { + // Data already present in map, return previously assigned id. + out_params->iaccessible_id = it->second; + out_params->output_long1 = -1; + } else { + // Insert new IAccessible in hashmaps. + int_to_iaccessible_map_[iaccessible_id_] = + reinterpret_cast<IAccessible *>(output_variant.pdispVal); + iaccessible_to_int_map_[ + reinterpret_cast<IAccessible *>(output_variant.pdispVal)] = + iaccessible_id_; + out_params->iaccessible_id = iaccessible_id_++; + out_params->output_long1 = -1; + } + } else if (output_variant.vt == VT_I4) { + out_params->output_long1 = output_variant.lVal; + } + + // Memory cleanup. + ::VariantClear(&input_variant); + ::VariantClear(&output_variant); + + return true; +} + +bool GlueAccessibility::InitAccessibilityRoot(WebView* view) { + WebCore::AXObjectCache::enableAccessibility(); + iaccessible_id_ = 0; + + WebFrame* main_frame = view->GetMainFrame(); + + if (!main_frame) + return false; + + WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(main_frame); + WebCore::Frame* frame = main_frame_impl->frame(); + + WebCore::Document* currentDocument = frame->document(); + if (!currentDocument) { + root_->accessibility_root_ = 0; + return false; + } else if (!root_->accessibility_root_ || + root_->accessibility_root_->document() != currentDocument) { + // 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_->accessibility_root_ = new AccessibleDocument(currentDocument); + } + // Insert root in hashmaps. + int_to_iaccessible_map_[iaccessible_id_] = root_->accessibility_root_.get(); + iaccessible_to_int_map_[root_->accessibility_root_.get()] = iaccessible_id_++; + + return true; +} + +bool GlueAccessibility::ClearIAccessibleMap(int iaccessible_id, + bool clear_all) { + if (clear_all) { + // Clear maps and invalidate root. + int_to_iaccessible_map_.clear(); + iaccessible_to_int_map_.clear(); + root_->accessibility_root_ = 0; + return true; + } + + IntToIAccessibleMap::iterator it = + int_to_iaccessible_map_.find(iaccessible_id); + + if (it == int_to_iaccessible_map_.end()) { + // Element not found. + return false; + } else { + if (it->second) { + // Erase element from reverse hashmap. + IAccessibleToIntMap::iterator it2 = + iaccessible_to_int_map_.find(it->second); + + DCHECK(it2 != iaccessible_to_int_map_.end()); + iaccessible_to_int_map_.erase(it2); + } + + int_to_iaccessible_map_.erase(it); + + if (iaccessible_id == 0) { + // Invalidate root. + root_->accessibility_root_ = 0; + } + } + + return true; +} diff --git a/webkit/glue/glue_accessibility.h b/webkit/glue/glue_accessibility.h new file mode 100644 index 0000000..576ccc4 --- /dev/null +++ b/webkit/glue/glue_accessibility.h @@ -0,0 +1,68 @@ +// 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. + +#ifndef WEBKIT_GLUE_GLUE_ACCESSIBILITY_H_ +#define WEBKIT_GLUE_GLUE_ACCESSIBILITY_H_ + +#include <oleacc.h> +#include <hash_map> + +#include "chrome/common/render_messages.h" + +class WebView; + +typedef stdext::hash_map<int, IAccessible*> IntToIAccessibleMap; +typedef stdext::hash_map<IAccessible*, int> IAccessibleToIntMap; + +//////////////////////////////////////////////////////////////////////////////// +// +// GlueAccessibility +// +// Operations that access the underlying WebKit DOM directly, exposing +// accessibility information. +//////////////////////////////////////////////////////////////////////////////// +class GlueAccessibility { + public: + GlueAccessibility(); + ~GlueAccessibility(); + + // Retrieves the IAccessible information as requested in in_params, by calling + // into WebKit's implementation of IAccessible. Maintains a hashmap of the + // currently active (browser ref count not zero) IAccessibles. Returns true if + // successful, false otherwise. + bool GetAccessibilityInfo(WebView* view, + const ViewMsg_Accessibility_In_Params& in_params, + ViewHostMsg_Accessibility_Out_Params* out_params); + + // Retrieves the RenderObject associated with this WebView, and uses it to + // initialize the root of the render-side MSAA tree with the associated + // accessibility information. Returns true if successful, false otherwise. + bool InitAccessibilityRoot(WebView* view); + + // Erases the entry identified by the |iaccessible_id| from the hash map. If + // |clear_all| is true, all entries are erased. Returns true if successful, + // false otherwise. + bool ClearIAccessibleMap(int iaccessible_id, bool clear_all); + + private: + // Wrapper around the COM pointer that holds the root of the MSAA tree, to + // ensure that we are not requiring WebKit includes outside of glue. + struct GlueAccessibilityRoot; + GlueAccessibilityRoot* root_; + + // Hashmap for cashing of elements in use by the AT, mapping id (int) to an + // IAccessible pointer. + IntToIAccessibleMap int_to_iaccessible_map_; + // Hashmap for cashing of elements in use by the AT, mapping an IAccessible + // pointer to its id (int). Needed for reverse lookup, to ensure unnecessary + // duplicate entries are not created in the IntToIAccessibleMap (above). + IAccessibleToIntMap iaccessible_to_int_map_; + + // Unique identifier for retrieving an IAccessible from the page's hashmap. + int iaccessible_id_; + + DISALLOW_COPY_AND_ASSIGN(GlueAccessibility); +}; + +#endif // WEBKIT_GLUE_GLUE_ACCESSIBILITY_H_ |