OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <comdef.h> |
| 6 |
| 7 #include "config.h" |
| 8 |
| 9 #pragma warning(push, 0) |
| 10 #include "AccessibleDocument.h" |
| 11 #include "AXObjectCache.h" |
| 12 #include "Document.h" |
| 13 #include "Frame.h" |
| 14 #pragma warning(pop) |
| 15 #undef LOG |
| 16 |
| 17 #include "webkit/glue/glue_accessibility.h" |
| 18 |
| 19 #include "chrome/browser/iaccessible_function_ids.h" |
| 20 #include "webkit/glue/webframe_impl.h" |
| 21 #include "webkit/glue/webview_impl.h" |
| 22 |
| 23 // struct GlueAccessibility::GlueAccessibilityRoot |
| 24 struct GlueAccessibility::GlueAccessibilityRoot { |
| 25 GlueAccessibilityRoot() {} |
| 26 |
| 27 // Root of the WebKit IAccessible tree. |
| 28 COMPtr<AccessibleDocument> accessibility_root_; |
| 29 }; |
| 30 |
| 31 // class GlueAccessibility |
| 32 GlueAccessibility::GlueAccessibility() |
| 33 : root_(new GlueAccessibilityRoot) { |
| 34 } |
| 35 |
| 36 GlueAccessibility::~GlueAccessibility() { |
| 37 delete root_; |
| 38 } |
| 39 |
| 40 bool GlueAccessibility::GetAccessibilityInfo(WebView* view, |
| 41 const ViewMsg_Accessibility_In_Params& in_params, |
| 42 ViewHostMsg_Accessibility_Out_Params* out_params) { |
| 43 if (!root_->accessibility_root_ && !InitAccessibilityRoot(view)) { |
| 44 // Failure in retrieving the root. |
| 45 return false; |
| 46 } |
| 47 |
| 48 // Temporary storing for the currently active IAccessible. |
| 49 COMPtr<IAccessible> active_iaccessible; |
| 50 IntToIAccessibleMap::iterator it = |
| 51 int_to_iaccessible_map_.find(in_params.iaccessible_id); |
| 52 |
| 53 if (it == int_to_iaccessible_map_.end()) { |
| 54 // Map did not contain the data requested. |
| 55 return false; |
| 56 } |
| 57 |
| 58 active_iaccessible = it->second; |
| 59 |
| 60 if (!active_iaccessible) { |
| 61 // Requested IAccessible not found. Paranoia check. |
| 62 NOTREACHED(); |
| 63 return false; |
| 64 } |
| 65 |
| 66 // Input VARIANT, determined by the browser side to be of type VT_I4. |
| 67 VARIANT input_variant; |
| 68 input_variant.vt = VT_I4; |
| 69 input_variant.lVal = in_params.input_variant_lval; |
| 70 |
| 71 // Output variables, used locally to retrieve data. |
| 72 VARIANT output_variant; |
| 73 ::VariantInit(&output_variant); |
| 74 BSTR output_bstr; |
| 75 bool string_output = false; |
| 76 HRESULT hr = S_FALSE; |
| 77 |
| 78 switch (in_params.iaccessible_function_id) { |
| 79 case IACCESSIBLE_FUNC_ACCDODEFAULTACTION : |
| 80 hr = active_iaccessible->accDoDefaultAction(input_variant); |
| 81 break; |
| 82 case IACCESSIBLE_FUNC_ACCHITTEST : |
| 83 hr = active_iaccessible->accHitTest(in_params.input_long1, |
| 84 in_params.input_long2, |
| 85 &output_variant); |
| 86 break; |
| 87 case IACCESSIBLE_FUNC_ACCLOCATION : |
| 88 hr = active_iaccessible->accLocation(&out_params->output_long1, |
| 89 &out_params->output_long2, |
| 90 &out_params->output_long3, |
| 91 &out_params->output_long4, |
| 92 input_variant); |
| 93 break; |
| 94 case IACCESSIBLE_FUNC_ACCNAVIGATE : |
| 95 hr = active_iaccessible->accNavigate(in_params.input_long1, input_variant, |
| 96 &output_variant); |
| 97 break; |
| 98 case IACCESSIBLE_FUNC_GET_ACCCHILD : |
| 99 if (input_variant.lVal == CHILDID_SELF) { |
| 100 // If child requested is CHILDID_SELF, stay with the same IAccessible. |
| 101 out_params->iaccessible_id = in_params.iaccessible_id; |
| 102 hr = S_OK; |
| 103 break; |
| 104 } |
| 105 hr = active_iaccessible->get_accChild(input_variant, |
| 106 reinterpret_cast<IDispatch **>(&output_variant.pdispVal)); |
| 107 output_variant.vt = VT_DISPATCH; |
| 108 break; |
| 109 case IACCESSIBLE_FUNC_GET_ACCCHILDCOUNT : |
| 110 hr = active_iaccessible->get_accChildCount(&out_params->output_long1); |
| 111 break; |
| 112 case IACCESSIBLE_FUNC_GET_ACCDEFAULTACTION : |
| 113 hr = active_iaccessible->get_accDefaultAction(input_variant, |
| 114 &output_bstr); |
| 115 string_output = true; |
| 116 break; |
| 117 case IACCESSIBLE_FUNC_GET_ACCDESCRIPTION : |
| 118 hr = active_iaccessible->get_accDescription(input_variant, &output_bstr); |
| 119 string_output = true; |
| 120 break; |
| 121 case IACCESSIBLE_FUNC_GET_ACCFOCUS : |
| 122 hr = active_iaccessible->get_accFocus(&output_variant); |
| 123 break; |
| 124 case IACCESSIBLE_FUNC_GET_ACCHELP : |
| 125 hr = active_iaccessible->get_accHelp(input_variant, &output_bstr); |
| 126 string_output = true; |
| 127 break; |
| 128 case IACCESSIBLE_FUNC_GET_ACCKEYBOARDSHORTCUT : |
| 129 hr = active_iaccessible->get_accKeyboardShortcut(input_variant, |
| 130 &output_bstr); |
| 131 string_output = true; |
| 132 break; |
| 133 case IACCESSIBLE_FUNC_GET_ACCNAME : |
| 134 hr = active_iaccessible->get_accName(input_variant, &output_bstr); |
| 135 string_output = true; |
| 136 break; |
| 137 case IACCESSIBLE_FUNC_GET_ACCPARENT : |
| 138 hr = active_iaccessible->get_accParent( |
| 139 reinterpret_cast<IDispatch **>(&output_variant.pdispVal)); |
| 140 output_variant.vt = VT_DISPATCH; |
| 141 break; |
| 142 case IACCESSIBLE_FUNC_GET_ACCROLE : |
| 143 hr = active_iaccessible->get_accRole(input_variant, &output_variant); |
| 144 break; |
| 145 case IACCESSIBLE_FUNC_GET_ACCSTATE : |
| 146 hr = active_iaccessible->get_accState(input_variant, &output_variant); |
| 147 break; |
| 148 case IACCESSIBLE_FUNC_GET_ACCVALUE : |
| 149 hr = active_iaccessible->get_accValue(input_variant, &output_bstr); |
| 150 string_output = true; |
| 151 break; |
| 152 default: |
| 153 // Memory cleanup. |
| 154 ::VariantClear(&input_variant); |
| 155 ::VariantClear(&output_variant); |
| 156 |
| 157 // Non-supported function id. |
| 158 return false; |
| 159 } |
| 160 |
| 161 // Return code handling. |
| 162 if (hr == S_OK) { |
| 163 out_params->return_code = true; |
| 164 |
| 165 // All is ok, assign output string if needed. |
| 166 if (string_output) { |
| 167 out_params->output_string = _bstr_t(output_bstr); |
| 168 ::SysFreeString(output_bstr); |
| 169 } |
| 170 |
| 171 } else if (hr == S_FALSE) { |
| 172 out_params->return_code = false; |
| 173 } else { |
| 174 // Memory cleanup. |
| 175 ::VariantClear(&input_variant); |
| 176 ::VariantClear(&output_variant); |
| 177 |
| 178 // Generate a generic failure on the browser side. Input validation is the |
| 179 // responsibility of the browser side, as is correctly handling calls to |
| 180 // non-supported functions appropriately. |
| 181 return false; |
| 182 } |
| 183 |
| 184 // Output and hashmap assignments, as appropriate. |
| 185 if (output_variant.vt == VT_DISPATCH && output_variant.pdispVal) { |
| 186 IAccessibleToIntMap::iterator it = |
| 187 iaccessible_to_int_map_.find( |
| 188 reinterpret_cast<IAccessible *>(output_variant.pdispVal)); |
| 189 |
| 190 if (it != iaccessible_to_int_map_.end()) { |
| 191 // Data already present in map, return previously assigned id. |
| 192 out_params->iaccessible_id = it->second; |
| 193 out_params->output_long1 = -1; |
| 194 } else { |
| 195 // Insert new IAccessible in hashmaps. |
| 196 int_to_iaccessible_map_[iaccessible_id_] = |
| 197 reinterpret_cast<IAccessible *>(output_variant.pdispVal); |
| 198 iaccessible_to_int_map_[ |
| 199 reinterpret_cast<IAccessible *>(output_variant.pdispVal)] = |
| 200 iaccessible_id_; |
| 201 out_params->iaccessible_id = iaccessible_id_++; |
| 202 out_params->output_long1 = -1; |
| 203 } |
| 204 } else if (output_variant.vt == VT_I4) { |
| 205 out_params->output_long1 = output_variant.lVal; |
| 206 } |
| 207 |
| 208 // Memory cleanup. |
| 209 ::VariantClear(&input_variant); |
| 210 ::VariantClear(&output_variant); |
| 211 |
| 212 return true; |
| 213 } |
| 214 |
| 215 bool GlueAccessibility::InitAccessibilityRoot(WebView* view) { |
| 216 WebCore::AXObjectCache::enableAccessibility(); |
| 217 iaccessible_id_ = 0; |
| 218 |
| 219 WebFrame* main_frame = view->GetMainFrame(); |
| 220 |
| 221 if (!main_frame) |
| 222 return false; |
| 223 |
| 224 WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(main_frame); |
| 225 WebCore::Frame* frame = main_frame_impl->frame(); |
| 226 |
| 227 WebCore::Document* currentDocument = frame->document(); |
| 228 if (!currentDocument) { |
| 229 root_->accessibility_root_ = 0; |
| 230 return false; |
| 231 } else if (!root_->accessibility_root_ || |
| 232 root_->accessibility_root_->document() != currentDocument) { |
| 233 // Either we've never had a wrapper for this frame's top-level Document, |
| 234 // the Document renderer was destroyed and its wrapper was detached, or |
| 235 // the previous Document is in the page cache, and the current document |
| 236 // needs to be wrapped. |
| 237 root_->accessibility_root_ = new AccessibleDocument(currentDocument); |
| 238 } |
| 239 // Insert root in hashmaps. |
| 240 int_to_iaccessible_map_[iaccessible_id_] = root_->accessibility_root_.get(); |
| 241 iaccessible_to_int_map_[root_->accessibility_root_.get()] = iaccessible_id_++; |
| 242 |
| 243 return true; |
| 244 } |
| 245 |
| 246 bool GlueAccessibility::ClearIAccessibleMap(int iaccessible_id, |
| 247 bool clear_all) { |
| 248 if (clear_all) { |
| 249 // Clear maps and invalidate root. |
| 250 int_to_iaccessible_map_.clear(); |
| 251 iaccessible_to_int_map_.clear(); |
| 252 root_->accessibility_root_ = 0; |
| 253 return true; |
| 254 } |
| 255 |
| 256 IntToIAccessibleMap::iterator it = |
| 257 int_to_iaccessible_map_.find(iaccessible_id); |
| 258 |
| 259 if (it == int_to_iaccessible_map_.end()) { |
| 260 // Element not found. |
| 261 return false; |
| 262 } else { |
| 263 if (it->second) { |
| 264 // Erase element from reverse hashmap. |
| 265 IAccessibleToIntMap::iterator it2 = |
| 266 iaccessible_to_int_map_.find(it->second); |
| 267 |
| 268 DCHECK(it2 != iaccessible_to_int_map_.end()); |
| 269 iaccessible_to_int_map_.erase(it2); |
| 270 } |
| 271 |
| 272 int_to_iaccessible_map_.erase(it); |
| 273 |
| 274 if (iaccessible_id == 0) { |
| 275 // Invalidate root. |
| 276 root_->accessibility_root_ = 0; |
| 277 } |
| 278 } |
| 279 |
| 280 return true; |
| 281 } |
OLD | NEW |