Roll leveldb to r76.
[chromium-blink-merge.git] / chrome_frame / test / chrome_frame_ui_test_utils.cc
blobd113115a1f2550496212a250fafd1ca606576084
1 // Copyright (c) 2012 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.
5 #include "chrome_frame/test/chrome_frame_ui_test_utils.h"
7 #include <windows.h>
9 #include <sstream>
10 #include <stack>
12 #include "base/bind.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/path_service.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/win/scoped_bstr.h"
20 #include "chrome/common/chrome_paths.h"
21 #include "chrome_frame/test/win_event_receiver.h"
22 #include "chrome_frame/utils.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "third_party/iaccessible2/ia2_api_all.h"
25 #include "ui/gfx/point.h"
26 #include "ui/gfx/rect.h"
28 namespace chrome_frame_test {
30 // Timeout for waiting on Chrome to create the accessibility tree for the DOM.
31 const int kChromeDOMAccessibilityTreeTimeoutMs = 10 * 1000;
33 // Timeout for waiting on a menu to popup.
34 const int kMenuPopupTimeoutMs = 10 * 1000;
36 // AccObject methods
37 AccObject::AccObject(IAccessible* accessible, int child_id)
38 : accessible_(accessible), child_id_(child_id) {
39 DCHECK(accessible);
40 if (child_id != CHILDID_SELF) {
41 base::win::ScopedComPtr<IDispatch> dispatch;
42 // This class does not support referring to a full MSAA object using the
43 // parent object and the child id.
44 HRESULT result = accessible_->get_accChild(child_id_, dispatch.Receive());
45 if (result != S_FALSE && result != E_NOINTERFACE) {
46 LOG(ERROR) << "AccObject created which refers to full MSAA object using "
47 "parent object and child id. This should NOT be done.";
49 DCHECK(result == S_FALSE || result == E_NOINTERFACE);
53 // static
54 AccObject* AccObject::CreateFromWindow(HWND hwnd) {
55 base::win::ScopedComPtr<IAccessible> accessible;
56 ::AccessibleObjectFromWindow(hwnd, OBJID_CLIENT,
57 IID_IAccessible, reinterpret_cast<void**>(accessible.Receive()));
58 if (accessible)
59 return new AccObject(accessible);
60 return NULL;
63 // static
64 AccObject* AccObject::CreateFromEvent(HWND hwnd, LONG object_id,
65 LONG child_id) {
66 base::win::ScopedComPtr<IAccessible> accessible;
67 base::win::ScopedVariant acc_child_id;
68 ::AccessibleObjectFromEvent(hwnd, object_id, child_id, accessible.Receive(),
69 acc_child_id.Receive());
70 if (accessible && acc_child_id.type() == VT_I4)
71 return new AccObject(accessible, V_I4(&acc_child_id));
72 return NULL;
75 // static
76 AccObject* AccObject::CreateFromDispatch(IDispatch* dispatch) {
77 if (dispatch) {
78 base::win::ScopedComPtr<IAccessible> accessible;
79 accessible.QueryFrom(dispatch);
80 if (accessible)
81 return new AccObject(accessible);
83 return NULL;
86 // static
87 AccObject* AccObject::CreateFromPoint(int x, int y) {
88 base::win::ScopedComPtr<IAccessible> accessible;
89 base::win::ScopedVariant child_id;
90 POINT point = {x, y};
91 ::AccessibleObjectFromPoint(point, accessible.Receive(), child_id.Receive());
92 if (accessible && child_id.type() == VT_I4)
93 return new AccObject(accessible, V_I4(&child_id));
94 return NULL;
97 bool AccObject::DoDefaultAction() {
98 // Prevent clients from using this method to try to select menu items, which
99 // does not work with a locked desktop.
100 std::wstring class_name;
101 if (GetWindowClassName(&class_name)) {
102 DCHECK(class_name != L"#32768") << "Do not use DoDefaultAction with menus";
105 HRESULT result = accessible_->accDoDefaultAction(child_id_);
106 EXPECT_HRESULT_SUCCEEDED(result)
107 << "Could not do default action for AccObject: " << GetDescription();
108 return SUCCEEDED(result);
111 bool AccObject::LeftClick() {
112 return PostMouseClickAtCenter(WM_LBUTTONDOWN, WM_LBUTTONUP);
115 bool AccObject::RightClick() {
116 return PostMouseClickAtCenter(WM_RBUTTONDOWN, WM_RBUTTONUP);
119 bool AccObject::Focus() {
120 EXPECT_HRESULT_SUCCEEDED(
121 accessible_->accSelect(SELFLAG_TAKEFOCUS, child_id_));
123 // Double check that the object actually received focus. In some cases
124 // the parent object must have the focus first.
125 bool did_focus = false;
126 base::win::ScopedVariant focused;
127 if (SUCCEEDED(accessible_->get_accFocus(focused.Receive()))) {
128 if (focused.type() != VT_EMPTY)
129 did_focus = true;
131 EXPECT_TRUE(did_focus) << "Could not focus AccObject: " << GetDescription();
132 return did_focus;
135 bool AccObject::Select() {
136 // SELFLAG_TAKESELECTION needs to be combined with the focus in order to
137 // take effect.
138 int selection_flag = SELFLAG_TAKEFOCUS | SELFLAG_TAKESELECTION;
139 EXPECT_HRESULT_SUCCEEDED(accessible_->accSelect(selection_flag, child_id_));
141 // Double check that the object actually received selection.
142 bool did_select = false;
143 base::win::ScopedVariant selected;
144 if (SUCCEEDED(accessible_->get_accSelection(selected.Receive()))) {
145 if (selected.type() != VT_EMPTY)
146 did_select = true;
148 EXPECT_TRUE(did_select) << "Could not select AccObject: " << GetDescription();
149 return did_select;
152 bool AccObject::SetValue(const std::wstring& value) {
153 base::win::ScopedBstr value_bstr(value.c_str());
154 EXPECT_HRESULT_SUCCEEDED(accessible_->put_accValue(child_id_, value_bstr));
156 // Double check that the object's value has actually changed. Some objects'
157 // values can not be changed.
158 bool did_set_value = false;
159 std::wstring actual_value = L"-";
160 if (GetValue(&actual_value) && value == actual_value) {
161 did_set_value = true;
163 EXPECT_TRUE(did_set_value) << "Could not set value for AccObject: "
164 << GetDescription();
165 return did_set_value;
168 bool AccObject::GetName(std::wstring* name) {
169 DCHECK(name);
170 base::win::ScopedBstr name_bstr;
171 HRESULT result = accessible_->get_accName(child_id_, name_bstr.Receive());
172 if (SUCCEEDED(result))
173 name->assign(name_bstr, name_bstr.Length());
174 return SUCCEEDED(result);
177 bool AccObject::GetRoleText(std::wstring* role_text) {
178 DCHECK(role_text);
179 base::win::ScopedVariant role_variant;
180 if (SUCCEEDED(accessible_->get_accRole(child_id_, role_variant.Receive()))) {
181 if (role_variant.type() == VT_I4) {
182 wchar_t role_text_array[50];
183 UINT characters = ::GetRoleText(V_I4(&role_variant), role_text_array,
184 arraysize(role_text_array));
185 if (characters) {
186 *role_text = role_text_array;
187 return true;
188 } else {
189 LOG(ERROR) << "GetRoleText failed for role: " << V_I4(&role_variant);
191 } else if (role_variant.type() == VT_BSTR) {
192 *role_text = V_BSTR(&role_variant);
193 return true;
194 } else {
195 LOG(ERROR) << "Role was unexpected variant type: "
196 << role_variant.type();
199 return false;
202 bool AccObject::GetValue(std::wstring* value) {
203 DCHECK(value);
204 base::win::ScopedBstr value_bstr;
205 HRESULT result = accessible_->get_accValue(child_id_, value_bstr.Receive());
206 if (SUCCEEDED(result))
207 value->assign(value_bstr, value_bstr.Length());
208 return SUCCEEDED(result);
211 bool AccObject::GetState(int* state) {
212 DCHECK(state);
213 base::win::ScopedVariant state_variant;
214 if (SUCCEEDED(accessible_->get_accState(child_id_,
215 state_variant.Receive()))) {
216 if (state_variant.type() == VT_I4) {
217 *state = V_I4(&state_variant);
218 return true;
221 return false;
224 bool AccObject::GetLocation(gfx::Rect* location) {
225 DCHECK(location);
226 long left, top, width, height; // NOLINT
227 HRESULT result = accessible_->accLocation(&left, &top, &width, &height,
228 child_id_);
229 if (SUCCEEDED(result))
230 *location = gfx::Rect(left, top, width, height);
231 return SUCCEEDED(result);
234 bool AccObject::GetLocationInClient(gfx::Rect* client_location) {
235 DCHECK(client_location);
236 gfx::Rect location;
237 if (!GetLocation(&location))
238 return false;
239 HWND container_window = NULL;
240 if (!GetWindow(&container_window))
241 return false;
242 POINT offset = {0, 0};
243 if (!::ScreenToClient(container_window, &offset)) {
244 LOG(ERROR) << "Could not convert from screen to client coordinates for "
245 "window containing accessibility object: "
246 << GetDescription();
247 return false;
249 location.Offset(offset.x, offset.y);
250 *client_location = location;
251 return true;
254 AccObject* AccObject::GetParent() {
255 if (IsSimpleElement())
256 return new AccObject(accessible_);
257 base::win::ScopedComPtr<IDispatch> dispatch;
258 if (FAILED(accessible_->get_accParent(dispatch.Receive())))
259 return NULL;
260 return AccObject::CreateFromDispatch(dispatch.get());
263 bool AccObject::GetChildren(RefCountedAccObjectVector* client_objects) {
264 DCHECK(client_objects);
265 int child_count;
266 if (!GetChildCount(&child_count)) {
267 LOG(ERROR) << "Failed to get child count of AccObject";
268 return false;
270 if (child_count == 0)
271 return true;
273 RefCountedAccObjectVector objects;
274 // Find children using |AccessibleChildren|.
275 scoped_ptr<VARIANT[]> children(new VARIANT[child_count]);
276 long found_child_count; // NOLINT
277 if (FAILED(AccessibleChildren(accessible_, 0L, child_count,
278 children.get(),
279 &found_child_count))) {
280 LOG(ERROR) << "Failed to get children of accessible object";
281 return false;
283 if (found_child_count > 0) {
284 for (int i = 0; i < found_child_count; i++) {
285 scoped_refptr<AccObject> obj = CreateFromVariant(this, children[i]);
286 if (obj)
287 objects.push_back(obj);
288 ::VariantClear(&children[i]);
292 // In some cases, there are more children which can be found only by using
293 // the deprecated |accNavigate| method. Many of the menus, such as
294 // 'Favorites', cannot be found in IE6 using |AccessibileChildren|. Here we
295 // attempt a best effort at finding some remaining children.
296 int remaining_child_count = child_count - found_child_count;
297 scoped_refptr<AccObject> child_object;
298 if (remaining_child_count > 0) {
299 GetFromNavigation(NAVDIR_FIRSTCHILD, &child_object);
301 while (remaining_child_count > 0 && child_object) {
302 // Add to the children list if this child was not found earlier.
303 bool already_found = false;
304 for (size_t i = 0; i < objects.size(); ++i) {
305 if (child_object->Equals(objects[i])) {
306 already_found = true;
307 break;
310 if (!already_found) {
311 objects.push_back(child_object);
312 remaining_child_count--;
314 scoped_refptr<AccObject> next_child_object;
315 child_object->GetFromNavigation(NAVDIR_NEXT, &next_child_object);
316 child_object = next_child_object;
319 client_objects->insert(client_objects->end(), objects.begin(), objects.end());
320 return true;
323 bool AccObject::GetChildCount(int* child_count) {
324 DCHECK(child_count);
325 *child_count = 0;
326 if (!IsSimpleElement()) {
327 long long_child_count; // NOLINT
328 if (FAILED(accessible_->get_accChildCount(&long_child_count)))
329 return false;
330 *child_count = static_cast<int>(long_child_count);
332 return true;
335 bool AccObject::GetFromNavigation(long navigation_type,
336 scoped_refptr<AccObject>* object) {
337 DCHECK(object);
338 bool is_child_navigation = navigation_type == NAVDIR_FIRSTCHILD ||
339 navigation_type == NAVDIR_LASTCHILD;
340 DCHECK(!is_child_navigation || !IsSimpleElement());
341 base::win::ScopedVariant object_variant;
342 HRESULT result = accessible_->accNavigate(navigation_type,
343 child_id_,
344 object_variant.Receive());
345 if (FAILED(result)) {
346 LOG(WARNING) << "Navigation from accessibility object failed";
347 return false;
349 if (result == S_FALSE || object_variant.type() == VT_EMPTY) {
350 // This indicates that there was no accessibility object found by the
351 // navigation.
352 return true;
354 AccObject* navigated_to_object;
355 if (!is_child_navigation && !IsSimpleElement()) {
356 scoped_refptr<AccObject> parent = GetParent();
357 if (!parent.get()) {
358 LOG(WARNING) << "Could not get parent for accessibiliy navigation";
359 return false;
361 navigated_to_object = CreateFromVariant(parent, object_variant);
362 } else {
363 navigated_to_object = CreateFromVariant(this, object_variant);
365 if (!navigated_to_object)
366 return false;
367 *object = navigated_to_object;
368 return true;
371 bool AccObject::GetWindow(HWND* window) {
372 DCHECK(window);
373 return SUCCEEDED(::WindowFromAccessibleObject(accessible_, window)) && window;
376 bool AccObject::GetWindowClassName(std::wstring* class_name) {
377 DCHECK(class_name);
378 HWND container_window = NULL;
379 if (GetWindow(&container_window)) {
380 wchar_t class_arr[MAX_PATH];
381 if (::GetClassName(container_window, class_arr, arraysize(class_arr))) {
382 *class_name = class_arr;
383 return true;
386 return false;
389 bool AccObject::GetSelectionRange(int* start_offset, int* end_offset) {
390 DCHECK(start_offset);
391 DCHECK(end_offset);
392 base::win::ScopedComPtr<IAccessibleText> accessible_text;
393 HRESULT hr = DoQueryService(IID_IAccessibleText,
394 accessible_,
395 accessible_text.Receive());
396 if (FAILED(hr)) {
397 LOG(ERROR) << "Could not get IAccessibleText interface. Error: " << hr
398 << "\nIs IAccessible2Proxy.dll registered?";
399 return false;
402 LONG selection_count = 0;
403 accessible_text->get_nSelections(&selection_count);
404 LONG start = 0, end = 0;
405 if (selection_count > 0) {
406 if (FAILED(accessible_text->get_selection(0, &start, &end))) {
407 LOG(WARNING) << "Could not get first selection";
408 return false;
411 *start_offset = start;
412 *end_offset = end;
413 return true;
416 bool AccObject::GetSelectedText(std::wstring* text) {
417 DCHECK(text);
418 int start = 0, end = 0;
419 if (!GetSelectionRange(&start, &end))
420 return false;
421 base::win::ScopedComPtr<IAccessibleText> accessible_text;
422 HRESULT hr = DoQueryService(IID_IAccessibleText,
423 accessible_,
424 accessible_text.Receive());
425 if (FAILED(hr)) {
426 LOG(ERROR) << "Could not get IAccessibleText interface. Error: " << hr
427 << "\nIs IAccessible2Proxy.dll registered?";
428 return false;
430 base::win::ScopedBstr text_bstr;
431 if (FAILED(accessible_text->get_text(start, end, text_bstr.Receive()))) {
432 LOG(WARNING) << "Could not get text from selection range";
433 return false;
435 text->assign(text_bstr, text_bstr.Length());
436 return true;
439 bool AccObject::IsSimpleElement() {
440 return V_I4(&child_id_) != CHILDID_SELF;
443 bool AccObject::Equals(AccObject* other) {
444 if (other) {
445 DCHECK(child_id_.type() == VT_I4 && other->child_id_.type() == VT_I4);
446 return accessible_.get() == other->accessible_.get() &&
447 V_I4(&child_id_) == V_I4(&other->child_id_);
449 return false;
452 std::wstring AccObject::GetDescription() {
453 std::wstring name = L"-", role_text = L"-", value = L"-";
454 if (GetName(&name))
455 name = L"'" + name + L"'";
456 if (GetRoleText(&role_text))
457 role_text = L"'" + role_text + L"'";
458 if (GetValue(&value))
459 value = L"'" + value + L"'";
460 int state = 0;
461 GetState(&state);
462 return base::StringPrintf(L"[%ls, %ls, %ls, 0x%x]", name.c_str(),
463 role_text.c_str(), value.c_str(), state);
466 std::wstring AccObject::GetTree() {
467 std::wostringstream string_stream;
468 string_stream << L"Accessibility object tree:" << std::endl;
469 string_stream << L"[name, role_text, value, state]" << std::endl;
471 std::stack<std::pair<scoped_refptr<AccObject>, int> > pairs;
472 pairs.push(std::make_pair(this, 0));
473 while (!pairs.empty()) {
474 scoped_refptr<AccObject> object = pairs.top().first;
475 int depth = pairs.top().second;
476 pairs.pop();
478 for (int i = 0; i < depth; ++i)
479 string_stream << L" ";
480 string_stream << object->GetDescription() << std::endl;
482 RefCountedAccObjectVector children;
483 if (object->GetChildren(&children)) {
484 for (int i = static_cast<int>(children.size()) - 1; i >= 0; --i)
485 pairs.push(std::make_pair(children[i], depth + 1));
488 return string_stream.str();
491 // static
492 AccObject* AccObject::CreateFromVariant(AccObject* object,
493 const VARIANT& variant) {
494 IAccessible* accessible = object->accessible_;
495 if (V_VT(&variant) == VT_I4) {
496 // According to MSDN, a server is allowed to return a full Accessibility
497 // object using the parent object and the child id. If get_accChild is
498 // called with the id, the server must return the actual IAccessible
499 // interface. Do that here to get an actual IAccessible interface if
500 // possible, since this class operates under the assumption that if the
501 // child id is not CHILDID_SELF, the object is a simple element. See the
502 // DCHECK in the constructor.
503 base::win::ScopedComPtr<IDispatch> dispatch;
504 HRESULT result = accessible->get_accChild(variant,
505 dispatch.Receive());
506 if (result == S_FALSE || result == E_NOINTERFACE) {
507 // The object in question really is a simple element.
508 return new AccObject(accessible, V_I4(&variant));
509 } else if (SUCCEEDED(result)) {
510 // The object in question was actually a full object.
511 return CreateFromDispatch(dispatch.get());
513 VLOG(1) << "Failed to determine if child id refers to a full "
514 << "object. Error: " << result << std::endl
515 << "Parent object: " << WideToUTF8(object->GetDescription())
516 << std::endl << "Child ID: " << V_I4(&variant);
517 return NULL;
518 } else if (V_VT(&variant) == VT_DISPATCH) {
519 return CreateFromDispatch(V_DISPATCH(&variant));
521 LOG(WARNING) << "Unrecognizable child type";
522 return NULL;
525 bool AccObject::PostMouseClickAtCenter(int button_down, int button_up) {
526 std::wstring class_name;
527 if (!GetWindowClassName(&class_name)) {
528 LOG(ERROR) << "Could not get class name of window for accessibility "
529 << "object: " << GetDescription();
530 return false;
532 gfx::Rect location;
533 if (class_name == L"#32768") {
534 // For some reason, it seems that menus expect screen coordinates.
535 if (!GetLocation(&location))
536 return false;
537 } else {
538 if (!GetLocationInClient(&location))
539 return false;
542 gfx::Point center = location.CenterPoint();
543 return PostMouseButtonMessages(button_down, button_up,
544 center.x(), center.y());
547 bool AccObject::PostMouseButtonMessages(
548 int button_down, int button_up, int x, int y) {
549 HWND container_window;
550 if (!GetWindow(&container_window))
551 return false;
553 LPARAM coordinates = MAKELPARAM(x, y);
554 ::PostMessage(container_window, button_down, 0, coordinates);
555 ::PostMessage(container_window, button_up, 0, coordinates);
556 return true;
559 // AccObjectMatcher methods
560 AccObjectMatcher::AccObjectMatcher(const std::wstring& name,
561 const std::wstring& role_text,
562 const std::wstring& value)
563 : name_(name), role_text_(role_text), value_(value) {
566 bool AccObjectMatcher::FindHelper(AccObject* object,
567 scoped_refptr<AccObject>* match) const {
568 if (DoesMatch(object)) {
569 *match = object;
570 } else {
571 // Try to match the children of |object|.
572 AccObject::RefCountedAccObjectVector children;
573 if (!object->GetChildren(&children)) {
574 LOG(ERROR) << "Could not get children of AccObject";
575 return false;
577 for (size_t i = 0; i < children.size(); ++i) {
578 if (!FindHelper(children[i], match)) {
579 return false;
581 if (*match)
582 break;
585 return true;
588 bool AccObjectMatcher::Find(AccObject* object,
589 scoped_refptr<AccObject>* match) const {
590 DCHECK(object);
591 DCHECK(match);
592 *match = NULL;
593 return FindHelper(object, match);
596 bool AccObjectMatcher::FindInWindow(HWND hwnd,
597 scoped_refptr<AccObject>* match) const {
598 scoped_refptr<AccObject> object(AccObject::CreateFromWindow(hwnd));
599 if (!object) {
600 VLOG(1) << "Failed to get accessible object from window";
601 return false;
603 return Find(object.get(), match);
606 bool AccObjectMatcher::DoesMatch(AccObject* object) const {
607 DCHECK(object);
608 bool does_match = true;
609 std::wstring name, role_text, value;
610 if (name_.length()) {
611 object->GetName(&name);
612 does_match = MatchPattern(StringToUpperASCII(name),
613 StringToUpperASCII(name_));
615 if (does_match && role_text_.length()) {
616 object->GetRoleText(&role_text);
617 does_match = MatchPattern(role_text, role_text_);
619 if (does_match && value_.length()) {
620 object->GetValue(&value);
621 does_match = MatchPattern(value, value_);
623 return does_match;
626 std::wstring AccObjectMatcher::GetDescription() const {
627 std::wostringstream ss;
628 ss << L"[";
629 if (name_.length())
630 ss << L"Name: '" << name_ << L"', ";
631 if (role_text_.length())
632 ss << L"Role: '" << role_text_ << L"', ";
633 if (value_.length())
634 ss << L"Value: '" << value_ << L"'";
635 ss << L"]";
636 return ss.str();
639 // AccEventObserver methods
640 AccEventObserver::AccEventObserver()
641 : event_handler_(new EventHandler(this)),
642 is_watching_(false) {
643 event_receiver_.SetListenerForEvents(this, EVENT_SYSTEM_MENUPOPUPSTART,
644 EVENT_OBJECT_VALUECHANGE);
647 AccEventObserver::~AccEventObserver() {
648 event_handler_->observer_ = NULL;
651 void AccEventObserver::WatchForOneValueChange(const AccObjectMatcher& matcher) {
652 is_watching_ = true;
653 watching_for_matcher_ = matcher;
656 void AccEventObserver::OnEventReceived(DWORD event,
657 HWND hwnd,
658 LONG object_id,
659 LONG child_id) {
660 // Process events in a separate task to stop reentrancy problems.
661 DCHECK(base::MessageLoop::current());
662 base::MessageLoop::current()->PostTask(
663 FROM_HERE, base::Bind(&EventHandler::Handle, event_handler_.get(), event,
664 hwnd, object_id, child_id));
667 // AccEventObserver::EventHandler methods
668 AccEventObserver::EventHandler::EventHandler(AccEventObserver* observer)
669 : observer_(observer) {
672 void AccEventObserver::EventHandler::Handle(DWORD event,
673 HWND hwnd,
674 LONG object_id,
675 LONG child_id) {
676 if (!observer_)
677 return;
679 switch (event) {
680 case EVENT_SYSTEM_MENUPOPUPSTART:
681 observer_->OnMenuPopup(hwnd);
682 break;
683 case IA2_EVENT_DOCUMENT_LOAD_COMPLETE:
684 observer_->OnAccDocLoad(hwnd);
685 break;
686 case IA2_EVENT_TEXT_CARET_MOVED: {
687 scoped_refptr<AccObject> object(
688 AccObject::CreateFromEvent(hwnd, object_id, child_id));
689 if (object)
690 observer_->OnTextCaretMoved(hwnd, object.get());
691 break;
693 case EVENT_OBJECT_VALUECHANGE:
694 if (observer_->is_watching_) {
695 scoped_refptr<AccObject> object(
696 AccObject::CreateFromEvent(hwnd, object_id, child_id));
697 if (object) {
698 if (observer_->watching_for_matcher_.DoesMatch(object.get())) {
699 // Stop watching before calling OnAccValueChange in case the
700 // client invokes our watch method during the call.
701 observer_->is_watching_ = false;
702 std::wstring new_value;
703 if (object->GetValue(&new_value)) {
704 observer_->OnAccValueChange(hwnd, object.get(), new_value);
709 break;
710 default:
711 break;
715 // Other methods
716 bool FindAccObjectInWindow(HWND hwnd, const AccObjectMatcher& matcher,
717 scoped_refptr<AccObject>* object) {
718 DCHECK(object);
719 EXPECT_TRUE(matcher.FindInWindow(hwnd, object));
720 EXPECT_TRUE(*object) << "Element not found for matcher: "
721 << matcher.GetDescription();
722 if (!*object)
723 DumpAccessibilityTreeForWindow(hwnd);
724 return *object;
727 void DumpAccessibilityTreeForWindow(HWND hwnd) {
728 scoped_refptr<AccObject> object(AccObject::CreateFromWindow(hwnd));
729 if (object)
730 std::wcout << object->GetTree();
731 else
732 std::cout << "Could not get IAccessible for window" << std::endl;
735 bool IsDesktopUnlocked() {
736 HDESK desk = ::OpenInputDesktop(0, FALSE, DESKTOP_SWITCHDESKTOP);
737 if (desk)
738 ::CloseDesktop(desk);
739 return desk;
742 base::FilePath GetIAccessible2ProxyStubPath() {
743 base::FilePath path;
744 PathService::Get(chrome::DIR_APP, &path);
745 return path.AppendASCII("IAccessible2Proxy.dll");
748 } // namespace chrome_frame_test