Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / public / test / browser_test_utils.cc
bloba19331b5cd02916d45148f003b4375307ba4e8cd
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 "content/public/test/browser_test_utils.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/json/json_reader.h"
10 #include "base/path_service.h"
11 #include "base/process/kill.h"
12 #include "base/rand_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "base/test/test_timeouts.h"
17 #include "base/values.h"
18 #include "content/browser/renderer_host/render_widget_host_impl.h"
19 #include "content/browser/web_contents/web_contents_view.h"
20 #include "content/common/input/synthetic_web_input_event_builders.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/dom_operation_notification_details.h"
23 #include "content/public/browser/histogram_fetcher.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/render_frame_host.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/render_view_host.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/browser/web_contents_observer.h"
31 #include "content/public/test/test_utils.h"
32 #include "grit/webui_resources.h"
33 #include "net/base/filename_util.h"
34 #include "net/cookies/cookie_store.h"
35 #include "net/test/python_utils.h"
36 #include "net/url_request/url_request_context.h"
37 #include "net/url_request/url_request_context_getter.h"
38 #include "testing/gtest/include/gtest/gtest.h"
39 #include "ui/base/resource/resource_bundle.h"
40 #include "ui/compositor/test/draw_waiter_for_test.h"
41 #include "ui/events/gestures/gesture_configuration.h"
42 #include "ui/events/keycodes/dom4/keycode_converter.h"
44 #if defined(USE_AURA)
45 #include "ui/aura/test/window_event_dispatcher_test_api.h"
46 #include "ui/aura/window.h"
47 #include "ui/aura/window_event_dispatcher.h"
48 #include "ui/aura/window_tree_host.h"
49 #endif // USE_AURA
51 namespace content {
52 namespace {
54 class DOMOperationObserver : public NotificationObserver,
55 public WebContentsObserver {
56 public:
57 explicit DOMOperationObserver(RenderViewHost* rvh)
58 : WebContentsObserver(WebContents::FromRenderViewHost(rvh)),
59 did_respond_(false) {
60 registrar_.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE,
61 Source<WebContents>(web_contents()));
62 message_loop_runner_ = new MessageLoopRunner;
65 virtual void Observe(int type,
66 const NotificationSource& source,
67 const NotificationDetails& details) OVERRIDE {
68 DCHECK(type == NOTIFICATION_DOM_OPERATION_RESPONSE);
69 Details<DomOperationNotificationDetails> dom_op_details(details);
70 response_ = dom_op_details->json;
71 did_respond_ = true;
72 message_loop_runner_->Quit();
75 // Overridden from WebContentsObserver:
76 virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE {
77 message_loop_runner_->Quit();
80 bool WaitAndGetResponse(std::string* response) WARN_UNUSED_RESULT {
81 message_loop_runner_->Run();
82 *response = response_;
83 return did_respond_;
86 private:
87 NotificationRegistrar registrar_;
88 std::string response_;
89 bool did_respond_;
90 scoped_refptr<MessageLoopRunner> message_loop_runner_;
92 DISALLOW_COPY_AND_ASSIGN(DOMOperationObserver);
95 // Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute.
96 bool ExecuteScriptHelper(
97 RenderFrameHost* render_frame_host,
98 const std::string& original_script,
99 scoped_ptr<base::Value>* result) WARN_UNUSED_RESULT;
101 // Executes the passed |original_script| in the frame specified by
102 // |render_frame_host|. If |result| is not NULL, stores the value that the
103 // evaluation of the script in |result|. Returns true on success.
104 bool ExecuteScriptHelper(RenderFrameHost* render_frame_host,
105 const std::string& original_script,
106 scoped_ptr<base::Value>* result) {
107 // TODO(jcampan): we should make the domAutomationController not require an
108 // automation id.
109 std::string script =
110 "window.domAutomationController.setAutomationId(0);" + original_script;
111 DOMOperationObserver dom_op_observer(render_frame_host->GetRenderViewHost());
112 render_frame_host->ExecuteJavaScript(base::UTF8ToUTF16(script));
113 std::string json;
114 if (!dom_op_observer.WaitAndGetResponse(&json)) {
115 DLOG(ERROR) << "Cannot communicate with DOMOperationObserver.";
116 return false;
119 // Nothing more to do for callers that ignore the returned JS value.
120 if (!result)
121 return true;
123 base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
124 result->reset(reader.ReadToValue(json));
125 if (!result->get()) {
126 DLOG(ERROR) << reader.GetErrorMessage();
127 return false;
130 return true;
133 void BuildSimpleWebKeyEvent(blink::WebInputEvent::Type type,
134 ui::KeyboardCode key_code,
135 int native_key_code,
136 int modifiers,
137 NativeWebKeyboardEvent* event) {
138 event->nativeKeyCode = native_key_code;
139 event->windowsKeyCode = key_code;
140 event->setKeyIdentifierFromWindowsKeyCode();
141 event->type = type;
142 event->modifiers = modifiers;
143 event->isSystemKey = false;
144 event->timeStampSeconds = base::Time::Now().ToDoubleT();
145 event->skip_in_browser = true;
147 if (type == blink::WebInputEvent::Char ||
148 type == blink::WebInputEvent::RawKeyDown) {
149 event->text[0] = key_code;
150 event->unmodifiedText[0] = key_code;
154 void InjectRawKeyEvent(WebContents* web_contents,
155 blink::WebInputEvent::Type type,
156 ui::KeyboardCode key_code,
157 int native_key_code,
158 int modifiers) {
159 NativeWebKeyboardEvent event;
160 BuildSimpleWebKeyEvent(type, key_code, native_key_code, modifiers, &event);
161 web_contents->GetRenderViewHost()->ForwardKeyboardEvent(event);
164 void GetCookiesCallback(std::string* cookies_out,
165 base::WaitableEvent* event,
166 const std::string& cookies) {
167 *cookies_out = cookies;
168 event->Signal();
171 void GetCookiesOnIOThread(const GURL& url,
172 net::URLRequestContextGetter* context_getter,
173 base::WaitableEvent* event,
174 std::string* cookies) {
175 net::CookieStore* cookie_store =
176 context_getter->GetURLRequestContext()->cookie_store();
177 cookie_store->GetCookiesWithOptionsAsync(
178 url, net::CookieOptions(),
179 base::Bind(&GetCookiesCallback, cookies, event));
182 void SetCookieCallback(bool* result,
183 base::WaitableEvent* event,
184 bool success) {
185 *result = success;
186 event->Signal();
189 void SetCookieOnIOThread(const GURL& url,
190 const std::string& value,
191 net::URLRequestContextGetter* context_getter,
192 base::WaitableEvent* event,
193 bool* result) {
194 net::CookieStore* cookie_store =
195 context_getter->GetURLRequestContext()->cookie_store();
196 cookie_store->SetCookieWithOptionsAsync(
197 url, value, net::CookieOptions(),
198 base::Bind(&SetCookieCallback, result, event));
201 } // namespace
204 GURL GetFileUrlWithQuery(const base::FilePath& path,
205 const std::string& query_string) {
206 GURL url = net::FilePathToFileURL(path);
207 if (!query_string.empty()) {
208 GURL::Replacements replacements;
209 replacements.SetQueryStr(query_string);
210 return url.ReplaceComponents(replacements);
212 return url;
215 void WaitForLoadStop(WebContents* web_contents) {
216 // In many cases, the load may have finished before we get here. Only wait if
217 // the tab still has a pending navigation.
218 if (web_contents->IsLoading()) {
219 WindowedNotificationObserver load_stop_observer(
220 NOTIFICATION_LOAD_STOP,
221 Source<NavigationController>(&web_contents->GetController()));
222 load_stop_observer.Wait();
226 void CrashTab(WebContents* web_contents) {
227 RenderProcessHost* rph = web_contents->GetRenderProcessHost();
228 RenderProcessHostWatcher watcher(
229 rph, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
230 base::KillProcess(rph->GetHandle(), 0, false);
231 watcher.Wait();
234 #if defined(USE_AURA)
235 bool IsResizeComplete(aura::test::WindowEventDispatcherTestApi* dispatcher_test,
236 RenderWidgetHostImpl* widget_host) {
237 return !dispatcher_test->HoldingPointerMoves() &&
238 !widget_host->resize_ack_pending_for_testing();
241 void WaitForResizeComplete(WebContents* web_contents) {
242 aura::Window* content = web_contents->GetContentNativeView();
243 if (!content)
244 return;
246 aura::WindowTreeHost* window_host = content->GetHost();
247 aura::WindowEventDispatcher* dispatcher = window_host->dispatcher();
248 aura::test::WindowEventDispatcherTestApi dispatcher_test(dispatcher);
249 RenderWidgetHostImpl* widget_host =
250 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
251 if (!IsResizeComplete(&dispatcher_test, widget_host)) {
252 WindowedNotificationObserver resize_observer(
253 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
254 base::Bind(IsResizeComplete, &dispatcher_test, widget_host));
255 resize_observer.Wait();
258 #endif // USE_AURA
260 void SimulateMouseClick(WebContents* web_contents,
261 int modifiers,
262 blink::WebMouseEvent::Button button) {
263 int x = web_contents->GetContainerBounds().width() / 2;
264 int y = web_contents->GetContainerBounds().height() / 2;
265 SimulateMouseClickAt(web_contents, modifiers, button, gfx::Point(x, y));
268 void SimulateMouseClickAt(WebContents* web_contents,
269 int modifiers,
270 blink::WebMouseEvent::Button button,
271 const gfx::Point& point) {
272 blink::WebMouseEvent mouse_event;
273 mouse_event.type = blink::WebInputEvent::MouseDown;
274 mouse_event.button = button;
275 mouse_event.x = point.x();
276 mouse_event.y = point.y();
277 mouse_event.modifiers = modifiers;
278 // Mac needs globalX/globalY for events to plugins.
279 gfx::Rect offset = web_contents->GetContainerBounds();
280 mouse_event.globalX = point.x() + offset.x();
281 mouse_event.globalY = point.y() + offset.y();
282 mouse_event.clickCount = 1;
283 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
284 mouse_event.type = blink::WebInputEvent::MouseUp;
285 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
288 void SimulateMouseEvent(WebContents* web_contents,
289 blink::WebInputEvent::Type type,
290 const gfx::Point& point) {
291 blink::WebMouseEvent mouse_event;
292 mouse_event.type = type;
293 mouse_event.x = point.x();
294 mouse_event.y = point.y();
295 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
298 void SimulateTapAt(WebContents* web_contents, const gfx::Point& point) {
299 blink::WebGestureEvent tap;
300 tap.type = blink::WebGestureEvent::GestureTap;
301 tap.x = point.x();
302 tap.y = point.y();
303 RenderWidgetHostImpl* widget_host =
304 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
305 widget_host->ForwardGestureEvent(tap);
308 void SimulateKeyPress(WebContents* web_contents,
309 ui::KeyboardCode key_code,
310 bool control,
311 bool shift,
312 bool alt,
313 bool command) {
314 SimulateKeyPressWithCode(
315 web_contents, key_code, NULL, control, shift, alt, command);
318 void SimulateKeyPressWithCode(WebContents* web_contents,
319 ui::KeyboardCode key_code,
320 const char* code,
321 bool control,
322 bool shift,
323 bool alt,
324 bool command) {
325 int native_key_code = ui::KeycodeConverter::CodeToNativeKeycode(code);
327 int modifiers = 0;
329 // The order of these key down events shouldn't matter for our simulation.
330 // For our simulation we can use either the left keys or the right keys.
331 if (control) {
332 modifiers |= blink::WebInputEvent::ControlKey;
333 InjectRawKeyEvent(web_contents,
334 blink::WebInputEvent::RawKeyDown,
335 ui::VKEY_CONTROL,
336 ui::KeycodeConverter::CodeToNativeKeycode("ControlLeft"),
337 modifiers);
340 if (shift) {
341 modifiers |= blink::WebInputEvent::ShiftKey;
342 InjectRawKeyEvent(web_contents,
343 blink::WebInputEvent::RawKeyDown,
344 ui::VKEY_SHIFT,
345 ui::KeycodeConverter::CodeToNativeKeycode("ShiftLeft"),
346 modifiers);
349 if (alt) {
350 modifiers |= blink::WebInputEvent::AltKey;
351 InjectRawKeyEvent(web_contents,
352 blink::WebInputEvent::RawKeyDown,
353 ui::VKEY_MENU,
354 ui::KeycodeConverter::CodeToNativeKeycode("AltLeft"),
355 modifiers);
358 if (command) {
359 modifiers |= blink::WebInputEvent::MetaKey;
360 InjectRawKeyEvent(web_contents,
361 blink::WebInputEvent::RawKeyDown,
362 ui::VKEY_COMMAND,
363 ui::KeycodeConverter::CodeToNativeKeycode("OSLeft"),
364 modifiers);
367 InjectRawKeyEvent(
368 web_contents,
369 blink::WebInputEvent::RawKeyDown,
370 key_code,
371 native_key_code,
372 modifiers);
374 InjectRawKeyEvent(
375 web_contents,
376 blink::WebInputEvent::Char,
377 key_code,
378 native_key_code,
379 modifiers);
381 InjectRawKeyEvent(
382 web_contents,
383 blink::WebInputEvent::KeyUp,
384 key_code,
385 native_key_code,
386 modifiers);
388 // The order of these key releases shouldn't matter for our simulation.
389 if (control) {
390 modifiers &= ~blink::WebInputEvent::ControlKey;
391 InjectRawKeyEvent(web_contents,
392 blink::WebInputEvent::KeyUp,
393 ui::VKEY_CONTROL,
394 ui::KeycodeConverter::CodeToNativeKeycode("ControlLeft"),
395 modifiers);
398 if (shift) {
399 modifiers &= ~blink::WebInputEvent::ShiftKey;
400 InjectRawKeyEvent(web_contents,
401 blink::WebInputEvent::KeyUp,
402 ui::VKEY_SHIFT,
403 ui::KeycodeConverter::CodeToNativeKeycode("ShiftLeft"),
404 modifiers);
407 if (alt) {
408 modifiers &= ~blink::WebInputEvent::AltKey;
409 InjectRawKeyEvent(web_contents,
410 blink::WebInputEvent::KeyUp,
411 ui::VKEY_MENU,
412 ui::KeycodeConverter::CodeToNativeKeycode("AltLeft"),
413 modifiers);
416 if (command) {
417 modifiers &= ~blink::WebInputEvent::MetaKey;
418 InjectRawKeyEvent(web_contents,
419 blink::WebInputEvent::KeyUp,
420 ui::VKEY_COMMAND,
421 ui::KeycodeConverter::CodeToNativeKeycode("OSLeft"),
422 modifiers);
425 ASSERT_EQ(modifiers, 0);
428 namespace internal {
430 ToRenderFrameHost::ToRenderFrameHost(WebContents* web_contents)
431 : render_frame_host_(web_contents->GetMainFrame()) {
434 ToRenderFrameHost::ToRenderFrameHost(RenderViewHost* render_view_host)
435 : render_frame_host_(render_view_host->GetMainFrame()) {
438 ToRenderFrameHost::ToRenderFrameHost(RenderFrameHost* render_frame_host)
439 : render_frame_host_(render_frame_host) {
442 } // namespace internal
444 bool ExecuteScript(const internal::ToRenderFrameHost& adapter,
445 const std::string& script) {
446 std::string new_script =
447 script + ";window.domAutomationController.send(0);";
448 return ExecuteScriptHelper(adapter.render_frame_host(), new_script, NULL);
451 bool ExecuteScriptAndExtractInt(const internal::ToRenderFrameHost& adapter,
452 const std::string& script, int* result) {
453 DCHECK(result);
454 scoped_ptr<base::Value> value;
455 if (!ExecuteScriptHelper(adapter.render_frame_host(), script, &value) ||
456 !value.get()) {
457 return false;
460 return value->GetAsInteger(result);
463 bool ExecuteScriptAndExtractBool(const internal::ToRenderFrameHost& adapter,
464 const std::string& script, bool* result) {
465 DCHECK(result);
466 scoped_ptr<base::Value> value;
467 if (!ExecuteScriptHelper(adapter.render_frame_host(), script, &value) ||
468 !value.get()) {
469 return false;
472 return value->GetAsBoolean(result);
475 bool ExecuteScriptAndExtractString(const internal::ToRenderFrameHost& adapter,
476 const std::string& script,
477 std::string* result) {
478 DCHECK(result);
479 scoped_ptr<base::Value> value;
480 if (!ExecuteScriptHelper(adapter.render_frame_host(), script, &value) ||
481 !value.get()) {
482 return false;
485 return value->GetAsString(result);
488 namespace {
489 void AddToSetIfFrameMatchesPredicate(
490 std::set<RenderFrameHost*>* frame_set,
491 const base::Callback<bool(RenderFrameHost*)>& predicate,
492 RenderFrameHost* host) {
493 if (predicate.Run(host))
494 frame_set->insert(host);
498 RenderFrameHost* FrameMatchingPredicate(
499 WebContents* web_contents,
500 const base::Callback<bool(RenderFrameHost*)>& predicate) {
501 std::set<RenderFrameHost*> frame_set;
502 web_contents->ForEachFrame(
503 base::Bind(&AddToSetIfFrameMatchesPredicate, &frame_set, predicate));
504 DCHECK_EQ(1U, frame_set.size());
505 return *frame_set.begin();
508 bool FrameMatchesName(const std::string& name, RenderFrameHost* frame) {
509 return frame->GetFrameName() == name;
512 bool FrameIsChildOfMainFrame(RenderFrameHost* frame) {
513 return frame->GetParent() && !frame->GetParent()->GetParent();
516 bool FrameHasSourceUrl(const GURL& url, RenderFrameHost* frame) {
517 return frame->GetLastCommittedURL() == url;
520 bool ExecuteWebUIResourceTest(WebContents* web_contents,
521 const std::vector<int>& js_resource_ids) {
522 // Inject WebUI test runner script first prior to other scripts required to
523 // run the test as scripts may depend on it being declared.
524 std::vector<int> ids;
525 ids.push_back(IDR_WEBUI_JS_WEBUI_RESOURCE_TEST);
526 ids.insert(ids.end(), js_resource_ids.begin(), js_resource_ids.end());
528 std::string script;
529 for (std::vector<int>::iterator iter = ids.begin();
530 iter != ids.end();
531 ++iter) {
532 ResourceBundle::GetSharedInstance().GetRawDataResource(*iter)
533 .AppendToString(&script);
534 script.append("\n");
536 if (!ExecuteScript(web_contents, script))
537 return false;
539 DOMMessageQueue message_queue;
540 if (!ExecuteScript(web_contents, "runTests()"))
541 return false;
543 std::string message;
544 do {
545 if (!message_queue.WaitForMessage(&message))
546 return false;
547 } while (message.compare("\"PENDING\"") == 0);
549 return message.compare("\"SUCCESS\"") == 0;
552 std::string GetCookies(BrowserContext* browser_context, const GURL& url) {
553 std::string cookies;
554 base::WaitableEvent event(true, false);
555 net::URLRequestContextGetter* context_getter =
556 browser_context->GetRequestContext();
558 BrowserThread::PostTask(
559 BrowserThread::IO, FROM_HERE,
560 base::Bind(&GetCookiesOnIOThread, url,
561 make_scoped_refptr(context_getter), &event, &cookies));
562 event.Wait();
563 return cookies;
566 bool SetCookie(BrowserContext* browser_context,
567 const GURL& url,
568 const std::string& value) {
569 bool result = false;
570 base::WaitableEvent event(true, false);
571 net::URLRequestContextGetter* context_getter =
572 browser_context->GetRequestContext();
574 BrowserThread::PostTask(
575 BrowserThread::IO, FROM_HERE,
576 base::Bind(&SetCookieOnIOThread, url, value,
577 make_scoped_refptr(context_getter), &event, &result));
578 event.Wait();
579 return result;
582 void FetchHistogramsFromChildProcesses() {
583 scoped_refptr<content::MessageLoopRunner> runner = new MessageLoopRunner;
585 FetchHistogramsAsynchronously(
586 base::MessageLoop::current(),
587 runner->QuitClosure(),
588 // If this call times out, it means that a child process is not
589 // responding, which is something we should not ignore. The timeout is
590 // set to be longer than the normal browser test timeout so that it will
591 // be prempted by the normal timeout.
592 TestTimeouts::action_max_timeout());
593 runner->Run();
596 TitleWatcher::TitleWatcher(WebContents* web_contents,
597 const base::string16& expected_title)
598 : WebContentsObserver(web_contents),
599 message_loop_runner_(new MessageLoopRunner) {
600 EXPECT_TRUE(web_contents != NULL);
601 expected_titles_.push_back(expected_title);
604 void TitleWatcher::AlsoWaitForTitle(const base::string16& expected_title) {
605 expected_titles_.push_back(expected_title);
608 TitleWatcher::~TitleWatcher() {
611 const base::string16& TitleWatcher::WaitAndGetTitle() {
612 TestTitle();
613 message_loop_runner_->Run();
614 return observed_title_;
617 void TitleWatcher::DidStopLoading(RenderViewHost* render_view_host) {
618 // When navigating through the history, the restored NavigationEntry's title
619 // will be used. If the entry ends up having the same title after we return
620 // to it, as will usually be the case, then WebContentsObserver::TitleSet
621 // will then be suppressed, since the NavigationEntry's title hasn't changed.
622 TestTitle();
625 void TitleWatcher::TitleWasSet(NavigationEntry* entry, bool explicit_set) {
626 TestTitle();
629 void TitleWatcher::TestTitle() {
630 std::vector<base::string16>::const_iterator it =
631 std::find(expected_titles_.begin(),
632 expected_titles_.end(),
633 web_contents()->GetTitle());
634 if (it == expected_titles_.end())
635 return;
637 observed_title_ = *it;
638 message_loop_runner_->Quit();
641 WebContentsDestroyedWatcher::WebContentsDestroyedWatcher(
642 WebContents* web_contents)
643 : WebContentsObserver(web_contents),
644 message_loop_runner_(new MessageLoopRunner) {
645 EXPECT_TRUE(web_contents != NULL);
648 WebContentsDestroyedWatcher::~WebContentsDestroyedWatcher() {
651 void WebContentsDestroyedWatcher::Wait() {
652 message_loop_runner_->Run();
655 void WebContentsDestroyedWatcher::WebContentsDestroyed() {
656 message_loop_runner_->Quit();
659 RenderProcessHostWatcher::RenderProcessHostWatcher(
660 RenderProcessHost* render_process_host, WatchType type)
661 : render_process_host_(render_process_host),
662 type_(type),
663 message_loop_runner_(new MessageLoopRunner) {
664 render_process_host_->AddObserver(this);
667 RenderProcessHostWatcher::RenderProcessHostWatcher(
668 WebContents* web_contents, WatchType type)
669 : render_process_host_(web_contents->GetRenderProcessHost()),
670 type_(type),
671 message_loop_runner_(new MessageLoopRunner) {
672 render_process_host_->AddObserver(this);
675 RenderProcessHostWatcher::~RenderProcessHostWatcher() {
676 if (render_process_host_)
677 render_process_host_->RemoveObserver(this);
680 void RenderProcessHostWatcher::Wait() {
681 message_loop_runner_->Run();
684 void RenderProcessHostWatcher::RenderProcessExited(
685 RenderProcessHost* host,
686 base::ProcessHandle handle,
687 base::TerminationStatus status,
688 int exit_code) {
689 if (type_ == WATCH_FOR_PROCESS_EXIT)
690 message_loop_runner_->Quit();
693 void RenderProcessHostWatcher::RenderProcessHostDestroyed(
694 RenderProcessHost* host) {
695 render_process_host_ = NULL;
696 if (type_ == WATCH_FOR_HOST_DESTRUCTION)
697 message_loop_runner_->Quit();
700 DOMMessageQueue::DOMMessageQueue() {
701 registrar_.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE,
702 NotificationService::AllSources());
705 DOMMessageQueue::~DOMMessageQueue() {}
707 void DOMMessageQueue::Observe(int type,
708 const NotificationSource& source,
709 const NotificationDetails& details) {
710 Details<DomOperationNotificationDetails> dom_op_details(details);
711 message_queue_.push(dom_op_details->json);
712 if (message_loop_runner_.get())
713 message_loop_runner_->Quit();
716 void DOMMessageQueue::ClearQueue() {
717 message_queue_ = std::queue<std::string>();
720 bool DOMMessageQueue::WaitForMessage(std::string* message) {
721 DCHECK(message);
722 if (message_queue_.empty()) {
723 // This will be quit when a new message comes in.
724 message_loop_runner_ = new MessageLoopRunner;
725 message_loop_runner_->Run();
727 // The queue should not be empty, unless we were quit because of a timeout.
728 if (message_queue_.empty())
729 return false;
730 *message = message_queue_.front();
731 message_queue_.pop();
732 return true;
735 } // namespace content