| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 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 | 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 "config.h" | 5 #include "config.h" |
| 6 #include "WebViewImpl.h" |
| 6 | 7 |
| 8 #include "AccessibilityObject.h" |
| 9 #include "AccessibilityObjectWrapper.h" |
| 7 #include "AXObjectCache.h" | 10 #include "AXObjectCache.h" |
| 8 #include "Document.h" | 11 #include "Document.h" |
| 9 #include "Frame.h" | 12 #include "Frame.h" |
| 10 #include "RefPtr.h" | 13 #include "WebAccessibilityCacheImpl.h" |
| 11 #undef LOG | 14 #include "WebAccessibilityObject.h" |
| 15 #include "WebFrameImpl.h" |
| 12 | 16 |
| 13 #include "webkit/glue/webaccessibilitymanager_impl.h" | 17 #include <wtf/PassRefPtr.h> |
| 14 | 18 |
| 15 #include "webkit/api/public/WebAccessibilityObject.h" | 19 using namespace WebCore; |
| 16 #include "webkit/api/src/WebFrameImpl.h" | |
| 17 #include "webkit/api/src/WebViewImpl.h" | |
| 18 #include "webkit/glue/glue_accessibility_object.h" | |
| 19 #include "webkit/glue/glue_util.h" | |
| 20 | 20 |
| 21 using WebKit::WebAccessibilityObject; | 21 namespace WebKit { |
| 22 using WebKit::WebFrameImpl; | |
| 23 using WebKit::WebView; | |
| 24 | 22 |
| 25 namespace webkit_glue { | 23 const int invalidObjectId = -1; |
| 24 const int firstObjectId = 1000; |
| 26 | 25 |
| 27 // struct WebAccessibilityManagerImpl::GlueAccessibilityObjectRoot | 26 static PassRefPtr<AccessibilityObject> toAccessibilityObject(const WebAccessibilityObject& object) |
| 28 struct WebAccessibilityManagerImpl::GlueAccessibilityObjectRoot { | 27 { |
| 29 GlueAccessibilityObjectRoot() {} | 28 return object; |
| 30 | |
| 31 // Root of the WebKit AccessibilityObject tree. | |
| 32 RefPtr<GlueAccessibilityObject> acc_obj_root_; | |
| 33 }; | |
| 34 | |
| 35 /*static*/ | |
| 36 WebAccessibilityManager* WebAccessibilityManager::Create() { | |
| 37 return new WebAccessibilityManagerImpl(); | |
| 38 } | 29 } |
| 39 | 30 |
| 40 // class WebAccessibilityManagerImpl | 31 // WebView ---------------------------------------------------------------- |
| 41 WebAccessibilityManagerImpl::WebAccessibilityManagerImpl() | 32 |
| 42 : root_(new GlueAccessibilityObjectRoot), | 33 WebAccessibilityCache* WebAccessibilityCache::create() |
| 43 acc_obj_id_(1000) { | 34 { |
| 35 return new WebAccessibilityCacheImpl(); |
| 44 } | 36 } |
| 45 | 37 |
| 46 WebAccessibilityManagerImpl::~WebAccessibilityManagerImpl() { | 38 // WeakHandle ------------------------------------------------------------- |
| 47 int_to_glue_acc_obj_map_.clear(); | 39 |
| 48 acc_obj_to_int_map_.clear(); | 40 PassRefPtr<WebAccessibilityCacheImpl::WeakHandle> WebAccessibilityCacheImpl::WeakHandle::create(AccessibilityObject* object) |
| 41 { |
| 42 // FIXME: Remove resetting ref-count from AccessibilityObjectWrapper |
| 43 // and convert to use adoptRef. |
| 44 return new WebAccessibilityCacheImpl::WeakHandle(object); |
| 49 } | 45 } |
| 50 | 46 |
| 51 bool WebAccessibilityManagerImpl::GetAccObjInfo(WebView* view, | 47 WebAccessibilityCacheImpl::WeakHandle::WeakHandle(AccessibilityObject* object) |
| 52 const WebAccessibility::InParams& in_params, | 48 : AccessibilityObjectWrapper(object) |
| 53 WebAccessibility::OutParams* out_params) { | 49 { |
| 54 if (!root_->acc_obj_root_ && !InitAccObjRoot(view)) { | 50 m_object->setWrapper(this); |
| 55 // Failure in retrieving or initializing the root. | |
| 56 return false; | |
| 57 } | |
| 58 | |
| 59 // Function input parameters. | |
| 60 int object_id = in_params.object_id; | |
| 61 int child_id = in_params.child_id; | |
| 62 | |
| 63 // Since ids assigned by Chrome starts at 1000, whereas platform-specific ids | |
| 64 // used to reference a child will be in a wholly different range, we know | |
| 65 // that any id that high should be treated as a non-direct descendant. | |
| 66 if (in_params.child_id >= 1000) { | |
| 67 // Object is not a direct child, re-map the input parameters accordingly. | |
| 68 // The object to be retrieved is referred to by the |in_params.child_id|, as | |
| 69 // a result of e.g. a focus event. The local |child_id| is set to 0, to | |
| 70 // indicate that any function call should refer to the object itself. | |
| 71 object_id = in_params.child_id; | |
| 72 child_id = 0; | |
| 73 } | |
| 74 | |
| 75 // Find GlueAccessibilityObject requested by |object_id|. | |
| 76 IntToGlueAccObjMap::iterator it = | |
| 77 int_to_glue_acc_obj_map_.find(object_id); | |
| 78 if (it == int_to_glue_acc_obj_map_.end() || !it->second) { | |
| 79 // Map did not contain a valid instance of the data requested. | |
| 80 return false; | |
| 81 } | |
| 82 RefPtr<GlueAccessibilityObject> active_acc_obj = it->second; | |
| 83 | |
| 84 // Temp paramters for holding output information. | |
| 85 RefPtr<GlueAccessibilityObject> out_acc_obj = NULL; | |
| 86 WebCore::String out_string; | |
| 87 | |
| 88 switch (in_params.function_id) { | |
| 89 case WebAccessibility::FUNCTION_DODEFAULTACTION : | |
| 90 if (!active_acc_obj->DoDefaultAction(child_id)) | |
| 91 return false; | |
| 92 break; | |
| 93 case WebAccessibility::FUNCTION_HITTEST : | |
| 94 out_acc_obj = active_acc_obj->HitTest(in_params.input_long1, | |
| 95 in_params.input_long2); | |
| 96 if (!out_acc_obj.get()) | |
| 97 return false; | |
| 98 break; | |
| 99 case WebAccessibility::FUNCTION_LOCATION : | |
| 100 if (!active_acc_obj->Location(&out_params->output_long1, | |
| 101 &out_params->output_long2, | |
| 102 &out_params->output_long3, | |
| 103 &out_params->output_long4, | |
| 104 child_id)) { | |
| 105 return false; | |
| 106 } | |
| 107 break; | |
| 108 case WebAccessibility::FUNCTION_NAVIGATE : | |
| 109 out_acc_obj = active_acc_obj->Navigate( | |
| 110 static_cast<WebAccessibility::Direction>(in_params.input_long1), | |
| 111 child_id); | |
| 112 if (!out_acc_obj.get()) | |
| 113 return false; | |
| 114 break; | |
| 115 case WebAccessibility::FUNCTION_GETCHILD : | |
| 116 if (child_id == 0) { | |
| 117 // If child requested is self, stay with the same accessibility object. | |
| 118 out_params->object_id = in_params.object_id; | |
| 119 out_acc_obj = active_acc_obj.get(); | |
| 120 } else { | |
| 121 out_acc_obj = active_acc_obj->GetChild(child_id); | |
| 122 } | |
| 123 | |
| 124 if (!out_acc_obj.get()) | |
| 125 return false; | |
| 126 break; | |
| 127 case WebAccessibility::FUNCTION_CHILDCOUNT : | |
| 128 if (!active_acc_obj->ChildCount(&out_params->output_long1)) | |
| 129 return false; | |
| 130 break; | |
| 131 case WebAccessibility::FUNCTION_DEFAULTACTION : | |
| 132 if (!active_acc_obj->DefaultAction(child_id, &out_string)) | |
| 133 return false; | |
| 134 break; | |
| 135 case WebAccessibility::FUNCTION_DESCRIPTION : | |
| 136 if (!active_acc_obj->Description(child_id, &out_string)) | |
| 137 return false; | |
| 138 break; | |
| 139 case WebAccessibility::FUNCTION_GETFOCUSEDCHILD : | |
| 140 out_acc_obj = active_acc_obj->GetFocusedChild(); | |
| 141 if (!out_acc_obj.get()) | |
| 142 return false; | |
| 143 break; | |
| 144 case WebAccessibility::FUNCTION_HELPTEXT : | |
| 145 if (!active_acc_obj->HelpText(child_id, &out_string)) | |
| 146 return false; | |
| 147 break; | |
| 148 case WebAccessibility::FUNCTION_KEYBOARDSHORTCUT : | |
| 149 if (!active_acc_obj->KeyboardShortcut(child_id, &out_string)) | |
| 150 return false; | |
| 151 break; | |
| 152 case WebAccessibility::FUNCTION_NAME : | |
| 153 if (!active_acc_obj->Name(child_id, &out_string)) | |
| 154 return false; | |
| 155 break; | |
| 156 case WebAccessibility::FUNCTION_GETPARENT : | |
| 157 out_acc_obj = active_acc_obj->GetParent(); | |
| 158 if (!out_acc_obj.get()) | |
| 159 return false; | |
| 160 break; | |
| 161 case WebAccessibility::FUNCTION_ROLE : | |
| 162 if (!active_acc_obj->Role(child_id, &out_params->output_long1)) | |
| 163 return false; | |
| 164 break; | |
| 165 case WebAccessibility::FUNCTION_STATE : | |
| 166 if (!active_acc_obj->State(child_id, &out_params->output_long1)) | |
| 167 return false; | |
| 168 break; | |
| 169 case WebAccessibility::FUNCTION_VALUE : | |
| 170 if (!active_acc_obj->Value(child_id, &out_string)) | |
| 171 return false; | |
| 172 break; | |
| 173 default: | |
| 174 // Non-supported function id. | |
| 175 return false; | |
| 176 } | |
| 177 | |
| 178 // Output and hashmap assignments, as appropriate. | |
| 179 if (!out_string.isEmpty()) | |
| 180 out_params->output_string = StringToString16(out_string); | |
| 181 | |
| 182 if (out_acc_obj) { | |
| 183 AccObjToIntMap::iterator it = | |
| 184 acc_obj_to_int_map_.find(out_acc_obj->accessibilityObject()); | |
| 185 | |
| 186 if (it != acc_obj_to_int_map_.end()) { | |
| 187 // Data already present in map, return previously assigned id. | |
| 188 out_params->object_id = it->second; | |
| 189 out_params->output_long1 = -1; | |
| 190 } else { | |
| 191 // Insert new GlueAccessibilityObject in hashmaps. | |
| 192 int_to_glue_acc_obj_map_[acc_obj_id_] = out_acc_obj.get(); | |
| 193 acc_obj_to_int_map_[out_acc_obj->accessibilityObject()] = acc_obj_id_; | |
| 194 out_params->object_id = acc_obj_id_++; | |
| 195 out_params->output_long1 = -1; | |
| 196 } | |
| 197 } | |
| 198 // TODO(klink): Handle simple objects returned. | |
| 199 return true; | |
| 200 } | 51 } |
| 201 | 52 |
| 202 bool WebAccessibilityManagerImpl::InitAccObjRoot(WebView* view) { | 53 // WebAccessibilityCacheImpl ---------------------------------------- |
| 203 // Enable accessibility and retrieve Document. | |
| 204 WebCore::AXObjectCache::enableAccessibility(); | |
| 205 WebFrameImpl* main_frame_impl = | |
| 206 static_cast<WebFrameImpl*>(view->mainFrame()); | |
| 207 if (!main_frame_impl || !main_frame_impl->frame()) | |
| 208 return false; | |
| 209 | 54 |
| 210 WebCore::Document* doc = main_frame_impl->frame()->document(); | 55 void WebAccessibilityCacheImpl::WeakHandle::detach() |
| 211 | 56 { |
| 212 if (!doc || !doc->renderer()) | 57 if (m_object) |
| 213 return false; | 58 m_object = 0; |
| 214 | |
| 215 if (!root_->acc_obj_root_) { | |
| 216 // Either we've never had a wrapper for this frame's top-level Document, | |
| 217 // the Document renderer was destroyed and its wrapper was detached, or | |
| 218 // the previous Document is in the page cache, and the current document | |
| 219 // needs to be wrapped. | |
| 220 root_->acc_obj_root_ = GlueAccessibilityObject::CreateInstance(doc-> | |
| 221 axObjectCache()->getOrCreate(doc->renderer())); | |
| 222 } | |
| 223 // Insert root in hashmaps. | |
| 224 int_to_glue_acc_obj_map_[acc_obj_id_] = root_->acc_obj_root_.get(); | |
| 225 acc_obj_to_int_map_[root_->acc_obj_root_->accessibilityObject()] = | |
| 226 acc_obj_id_++; | |
| 227 | |
| 228 return true; | |
| 229 } | 59 } |
| 230 | 60 |
| 231 bool WebAccessibilityManagerImpl::ClearAccObjMap(int acc_obj_id, | 61 WebAccessibilityCacheImpl::WebAccessibilityCacheImpl() |
| 232 bool clear_all) { | 62 : m_nextNewId(firstObjectId) |
| 233 if (clear_all) { | 63 , m_initialized(false) |
| 234 // Clear maps and invalidate root. | 64 { |
| 235 int_to_glue_acc_obj_map_.clear(); | |
| 236 acc_obj_to_int_map_.clear(); | |
| 237 root_->acc_obj_root_ = 0; | |
| 238 return true; | |
| 239 } | |
| 240 | |
| 241 IntToGlueAccObjMap::iterator it = int_to_glue_acc_obj_map_.find(acc_obj_id); | |
| 242 | |
| 243 if (it == int_to_glue_acc_obj_map_.end()) { | |
| 244 // Element not found. | |
| 245 return false; | |
| 246 } | |
| 247 | |
| 248 if (it->second) { | |
| 249 // Erase element from reverse hashmap. | |
| 250 AccObjToIntMap::iterator it2 = | |
| 251 acc_obj_to_int_map_.find(it->second->accessibilityObject()); | |
| 252 | |
| 253 if (it2 != acc_obj_to_int_map_.end()) | |
| 254 acc_obj_to_int_map_.erase(it2); | |
| 255 } | |
| 256 int_to_glue_acc_obj_map_.erase(it); | |
| 257 | |
| 258 if (acc_obj_id == 1000) { | |
| 259 // Invalidate root. | |
| 260 root_->acc_obj_root_ = 0; | |
| 261 } | |
| 262 return true; | |
| 263 } | 65 } |
| 264 | 66 |
| 265 int WebAccessibilityManagerImpl::FocusAccObj( | 67 WebAccessibilityCacheImpl::~WebAccessibilityCacheImpl() |
| 266 const WebAccessibilityObject& object) { | 68 { |
| 267 if (object.isNull()) { | |
| 268 // Return with failure. | |
| 269 return -1; | |
| 270 } | |
| 271 | |
| 272 RefPtr<WebCore::AccessibilityObject> acc_obj = | |
| 273 WebAccessibilityObjectToAccessibilityObject(object); | |
| 274 | |
| 275 AccObjToIntMap::iterator it = acc_obj_to_int_map_.find(acc_obj.get()); | |
| 276 | |
| 277 if (it != acc_obj_to_int_map_.end()) | |
| 278 return it->second; | |
| 279 | |
| 280 // Insert new accessibility object in hashmaps and return its newly | |
| 281 // assigned accessibility object id. | |
| 282 int_to_glue_acc_obj_map_[acc_obj_id_] = | |
| 283 GlueAccessibilityObject::CreateInstance(acc_obj.get()); | |
| 284 acc_obj_to_int_map_[acc_obj.get()] = acc_obj_id_; | |
| 285 | |
| 286 return acc_obj_id_++; | |
| 287 } | 69 } |
| 288 | 70 |
| 289 } // namespace webkit_glue | 71 void WebAccessibilityCacheImpl::initialize(WebView* view) |
| 72 { |
| 73 AXObjectCache::enableAccessibility(); |
| 74 WebAccessibilityObject root = view->accessibilityObject(); |
| 75 if (root.isNull()) |
| 76 return; |
| 77 |
| 78 RefPtr<AccessibilityObject> rootObject = toAccessibilityObject(root); |
| 79 |
| 80 // Insert root in hashmaps. |
| 81 m_objectMap.set(m_nextNewId, WeakHandle::create(rootObject.get())); |
| 82 m_idMap.set(rootObject.get(), m_nextNewId++); |
| 83 |
| 84 m_initialized = true; |
| 85 } |
| 86 |
| 87 WebAccessibilityObject WebAccessibilityCacheImpl::getObjectById(int id) |
| 88 { |
| 89 ObjectMap::iterator it = m_objectMap.find(id); |
| 90 |
| 91 if (it == m_objectMap.end() || !it->second) |
| 92 return WebAccessibilityObject(); |
| 93 |
| 94 return WebAccessibilityObject(it->second->accessibilityObject()); |
| 95 } |
| 96 |
| 97 bool WebAccessibilityCacheImpl::isValidId(int id) const |
| 98 { |
| 99 return id >= firstObjectId; |
| 100 } |
| 101 |
| 102 void WebAccessibilityCacheImpl::remove(int id) |
| 103 { |
| 104 ObjectMap::iterator it = m_objectMap.find(id); |
| 105 |
| 106 if (it == m_objectMap.end()) |
| 107 return; |
| 108 |
| 109 if (it->second) { |
| 110 // Erase element from reverse hashmap. |
| 111 IdMap::iterator it2 = m_idMap.find(it->second->accessibilityObject()); |
| 112 if (it2 != m_idMap.end()) |
| 113 m_idMap.remove(it2); |
| 114 } |
| 115 |
| 116 m_objectMap.remove(it); |
| 117 } |
| 118 |
| 119 void WebAccessibilityCacheImpl::clear() |
| 120 { |
| 121 m_objectMap.clear(); |
| 122 m_idMap.clear(); |
| 123 } |
| 124 |
| 125 int WebAccessibilityCacheImpl::addOrGetId(const WebAccessibilityObject& object) { |
| 126 if (object.isNull()) |
| 127 return invalidObjectId; |
| 128 |
| 129 RefPtr<AccessibilityObject> o = toAccessibilityObject(object); |
| 130 |
| 131 IdMap::iterator it = m_idMap.find(o.get()); |
| 132 |
| 133 if (it != m_idMap.end()) |
| 134 return it->second; |
| 135 |
| 136 // Insert new accessibility object in hashmaps and return its newly |
| 137 // assigned accessibility object id. |
| 138 m_objectMap.set(m_nextNewId, WeakHandle::create(o.get())); |
| 139 m_idMap.set(o.get(), m_nextNewId); |
| 140 |
| 141 return m_nextNewId++; |
| 142 } |
| 143 |
| 144 } |
| OLD | NEW |