summaryrefslogtreecommitdiffstats
path: root/webkit/glue
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/glue')
-rw-r--r--webkit/glue/glue_accessibility.cc281
-rw-r--r--webkit/glue/glue_accessibility.h68
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_