blob: 5451a829a0eddc0442a4e320ce2b6ffd51d9dce8 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// 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.
initial.commit09911bf2008-07-26 23:55:294
5#include "chrome/browser/automation/automation_provider.h"
6
7#include "base/path_service.h"
[email protected]1eb89e82008-08-15 12:27:038#include "chrome/app/chrome_dll_resource.h"
initial.commit09911bf2008-07-26 23:55:299#include "chrome/browser/automation/automation_provider_list.h"
10#include "chrome/browser/automation/ui_controls.h"
11#include "chrome/browser/automation/url_request_failed_dns_job.h"
12#include "chrome/browser/automation/url_request_mock_http_job.h"
13#include "chrome/browser/automation/url_request_slow_download_job.h"
[email protected]f3e99e32008-07-30 04:48:3914#include "chrome/browser/browser_window.h"
initial.commit09911bf2008-07-26 23:55:2915#include "chrome/browser/dom_operation_notification_details.h"
16#include "chrome/browser/download_manager.h"
17#include "chrome/browser/external_tab_container.h"
18#include "chrome/browser/find_notification_details.h"
19#include "chrome/browser/login_prompt.h"
20#include "chrome/browser/navigation_entry.h"
21#include "chrome/browser/printing/print_job.h"
[email protected]fa83e762008-08-15 21:41:3922#include "chrome/browser/render_view_host.h"
initial.commit09911bf2008-07-26 23:55:2923#include "chrome/browser/save_package.h"
24#include "chrome/browser/ssl_blocking_page.h"
[email protected]1eb89e82008-08-15 12:27:0325#include "chrome/browser/web_contents.h"
[email protected]195442e2008-07-31 22:41:2826#include "chrome/browser/views/location_bar_view.h"
initial.commit09911bf2008-07-26 23:55:2927#include "chrome/common/chrome_paths.h"
28#include "chrome/test/automation/automation_messages.h"
29#include "net/base/cookie_monster.h"
30#include "net/url_request/url_request_filter.h"
31
32class InitialLoadObserver : public NotificationObserver {
33 public:
34 InitialLoadObserver(size_t tab_count, AutomationProvider* automation)
35 : outstanding_tab_count_(tab_count),
36 automation_(automation) {
37 if (outstanding_tab_count_ > 0) {
38 NotificationService* service = NotificationService::current();
39 service->AddObserver(this, NOTIFY_LOAD_START,
40 NotificationService::AllSources());
41 service->AddObserver(this, NOTIFY_LOAD_STOP,
42 NotificationService::AllSources());
43 }
44 }
45
46 ~InitialLoadObserver() {
47 Unregister();
48 }
49
50 void ConditionMet() {
51 Unregister();
52 automation_->Send(new AutomationMsg_InitialLoadsComplete(0));
53 }
54
55 void Unregister() {
56 NotificationService* service = NotificationService::current();
57 service->RemoveObserver(this, NOTIFY_LOAD_START,
58 NotificationService::AllSources());
59 service->RemoveObserver(this, NOTIFY_LOAD_STOP,
60 NotificationService::AllSources());
61 }
62
63 virtual void Observe(NotificationType type,
64 const NotificationSource& source,
65 const NotificationDetails& details) {
66 if (type == NOTIFY_LOAD_START) {
67 if (outstanding_tab_count_ > loading_tabs_.size())
68 loading_tabs_.insert(source.map_key());
69 } else if (type == NOTIFY_LOAD_STOP) {
70 if (outstanding_tab_count_ > finished_tabs_.size()) {
71 if (loading_tabs_.find(source.map_key()) != loading_tabs_.end())
72 finished_tabs_.insert(source.map_key());
73 if (outstanding_tab_count_ == finished_tabs_.size())
74 ConditionMet();
75 }
76 } else {
77 NOTREACHED();
78 }
79 }
80
81 private:
82 typedef std::set<uintptr_t> TabSet;
83
84 AutomationProvider* automation_;
85 size_t outstanding_tab_count_;
86 TabSet loading_tabs_;
87 TabSet finished_tabs_;
88};
89
90// Watches for NewTabUI page loads for performance timing purposes.
91class NewTabUILoadObserver : public NotificationObserver {
92 public:
93 explicit NewTabUILoadObserver(AutomationProvider* automation)
94 : automation_(automation) {
95 NotificationService::current()->
96 AddObserver(this, NOTIFY_INITIAL_NEW_TAB_UI_LOAD,
97 NotificationService::AllSources());
98 }
99
100 ~NewTabUILoadObserver() {
101 Unregister();
102 }
103
104 void Unregister() {
105 NotificationService::current()->
106 RemoveObserver(this, NOTIFY_INITIAL_NEW_TAB_UI_LOAD,
107 NotificationService::AllSources());
108 }
109
110 virtual void Observe(NotificationType type,
111 const NotificationSource& source,
112 const NotificationDetails& details) {
113 if (type == NOTIFY_INITIAL_NEW_TAB_UI_LOAD) {
114 Details<int> load_time(details);
115 automation_->Send(
116 new AutomationMsg_InitialNewTabUILoadComplete(0, *load_time.ptr()));
117 } else {
118 NOTREACHED();
119 }
120 }
121
122 private:
123 AutomationProvider* automation_;
124};
125
126class NavigationControllerRestoredObserver : public NotificationObserver {
127 public:
128 NavigationControllerRestoredObserver(AutomationProvider* automation,
129 NavigationController* controller,
130 int32 routing_id)
131 : automation_(automation),
132 controller_(controller),
133 routing_id_(routing_id) {
134 if (FinishedRestoring()) {
135 registered_ = false;
136 SendDone();
137 } else {
138 registered_ = true;
139 NotificationService* service = NotificationService::current();
140 service->AddObserver(this, NOTIFY_LOAD_STOP,
141 NotificationService::AllSources());
142 }
143 }
144
145 ~NavigationControllerRestoredObserver() {
146 if (registered_)
147 Unregister();
148 }
149
150 virtual void Observe(NotificationType type,
151 const NotificationSource& source,
152 const NotificationDetails& details) {
153 if (FinishedRestoring()) {
154 SendDone();
155 Unregister();
156 }
157 }
158
159 private:
160 void Unregister() {
161 NotificationService* service = NotificationService::current();
162 service->RemoveObserver(this, NOTIFY_LOAD_STOP,
163 NotificationService::AllSources());
164 registered_ = false;
165 }
166
167 bool FinishedRestoring() {
168 return (!controller_->needs_reload() && !controller_->GetPendingEntry() &&
169 !controller_->active_contents()->IsLoading());
170 }
171
172 void SendDone() {
173 automation_->Send(new AutomationMsg_TabFinishedRestoring(routing_id_));
174 }
175
176 bool registered_;
177 AutomationProvider* automation_;
178 NavigationController* controller_;
179 const int routing_id_;
180
181 DISALLOW_EVIL_CONSTRUCTORS(NavigationControllerRestoredObserver);
182};
183
184
185class NavigationNotificationObserver : public NotificationObserver {
186 public:
187 NavigationNotificationObserver(NavigationController* controller,
188 AutomationProvider* automation,
189 IPC::Message* completed_response,
190 IPC::Message* auth_needed_response)
191 : automation_(automation),
192 completed_response_(completed_response),
193 auth_needed_response_(auth_needed_response),
194 controller_(controller),
195 navigation_started_(false) {
196 NotificationService* service = NotificationService::current();
197 service->AddObserver(this, NOTIFY_LOAD_START,
198 Source<NavigationController>(controller_));
199 service->AddObserver(this, NOTIFY_LOAD_STOP,
200 Source<NavigationController>(controller_));
201 service->AddObserver(this, NOTIFY_AUTH_NEEDED,
202 Source<NavigationController>(controller_));
203 service->AddObserver(this, NOTIFY_AUTH_SUPPLIED,
204 Source<NavigationController>(controller_));
205 }
206
207 ~NavigationNotificationObserver() {
208 if (completed_response_) delete completed_response_;
209 if (auth_needed_response_) delete auth_needed_response_;
210 Unregister();
211 }
212
213 void ConditionMet(IPC::Message** response) {
214 if (*response) {
215 automation_->Send(*response);
216 *response = NULL; // *response is deleted by Send.
217 }
218 automation_->RemoveNavigationStatusListener(this);
219 delete this;
220 }
221
222 void Unregister() {
223 NotificationService* service = NotificationService::current();
224 service->RemoveObserver(this, NOTIFY_LOAD_START,
225 Source<NavigationController>(controller_));
226 service->RemoveObserver(this, NOTIFY_LOAD_STOP,
227 Source<NavigationController>(controller_));
228 service->RemoveObserver(this, NOTIFY_AUTH_NEEDED,
229 Source<NavigationController>(controller_));
230 service->RemoveObserver(this, NOTIFY_AUTH_SUPPLIED,
231 Source<NavigationController>(controller_));
232 }
233
234 virtual void Observe(NotificationType type,
235 const NotificationSource& source,
236 const NotificationDetails& details) {
237 if (type == NOTIFY_LOAD_START) {
238 navigation_started_ = true;
239 } else if (type == NOTIFY_LOAD_STOP) {
240 if (navigation_started_) {
241 navigation_started_ = false;
242 ConditionMet(&completed_response_);
243 }
244 } else if (type == NOTIFY_AUTH_SUPPLIED) {
245 // The LoginHandler for this tab is no longer valid.
246 automation_->RemoveLoginHandler(controller_);
247
248 // Treat this as if navigation started again, since load start/stop don't
249 // occur while authentication is ongoing.
250 navigation_started_ = true;
251 } else if (type == NOTIFY_AUTH_NEEDED) {
252 if (navigation_started_) {
253 // Remember the login handler that wants authentication.
254 LoginHandler* handler =
255 Details<LoginNotificationDetails>(details)->handler();
256 automation_->AddLoginHandler(controller_, handler);
257
258 // Respond that authentication is needed.
259 navigation_started_ = false;
260 ConditionMet(&auth_needed_response_);
261 } else {
262 NOTREACHED();
263 }
264 } else {
265 NOTREACHED();
266 }
267 }
268
269 private:
270 AutomationProvider* automation_;
271 IPC::Message* completed_response_;
272 IPC::Message* auth_needed_response_;
273 NavigationController* controller_;
274 bool navigation_started_;
275};
276
277class TabStripNotificationObserver : public NotificationObserver {
278 public:
279 TabStripNotificationObserver(Browser* parent, NotificationType notification,
280 AutomationProvider* automation, int32 routing_id)
281 : automation_(automation),
282 notification_(notification),
283 parent_(parent),
284 routing_id_(routing_id) {
285 NotificationService::current()->
286 AddObserver(this, notification_, NotificationService::AllSources());
287 }
288
289 virtual ~TabStripNotificationObserver() {
290 Unregister();
291 }
292
293 void Unregister() {
294 NotificationService::current()->
295 RemoveObserver(this, notification_, NotificationService::AllSources());
296 }
297
298 virtual void Observe(NotificationType type,
299 const NotificationSource& source,
300 const NotificationDetails& details) {
301 if (type == notification_) {
302 ObserveTab(Source<NavigationController>(source).ptr());
303
304 // If verified, no need to observe anymore
305 automation_->RemoveTabStripObserver(this);
306 delete this;
307 } else {
308 NOTREACHED();
309 }
310 }
311
312 virtual void ObserveTab(NavigationController* controller) = 0;
313
314 protected:
315 AutomationProvider* automation_;
316 Browser* parent_;
317 NotificationType notification_;
318 int32 routing_id_;
319};
320
321class TabAppendedNotificationObserver : public TabStripNotificationObserver {
322 public:
323 TabAppendedNotificationObserver(Browser* parent,
324 AutomationProvider* automation, int32 routing_id)
[email protected]534e54b2008-08-13 15:40:09325 : TabStripNotificationObserver(parent, NOTIFY_TAB_PARENTED, automation,
initial.commit09911bf2008-07-26 23:55:29326 routing_id) {
327 }
328
329 virtual void ObserveTab(NavigationController* controller) {
330 int tab_index =
331 automation_->GetIndexForNavigationController(controller, parent_);
332 if (tab_index == TabStripModel::kNoTab) {
333 // This tab notification doesn't belong to the parent_
334 return;
335 }
336
337 // Give the same response even if auth is needed, since it doesn't matter.
338 automation_->AddNavigationStatusListener(controller,
339 new AutomationMsg_AppendTabResponse(routing_id_, tab_index),
340 new AutomationMsg_AppendTabResponse(routing_id_, tab_index));
341 }
342};
343
344class TabClosedNotificationObserver : public TabStripNotificationObserver {
345 public:
346 TabClosedNotificationObserver(Browser* parent,
347 AutomationProvider* automation,
348 int32 routing_id,
349 bool wait_until_closed)
350 : TabStripNotificationObserver(parent,
351 wait_until_closed ? NOTIFY_TAB_CLOSED :
352 NOTIFY_TAB_CLOSING,
353 automation,
354 routing_id) {
355 }
356
357 virtual void ObserveTab(NavigationController* controller) {
358 automation_->Send(new AutomationMsg_CloseTabResponse(routing_id_, true));
359 }
360};
361
362class BrowserClosedNotificationObserver : public NotificationObserver {
363 public:
364 BrowserClosedNotificationObserver(Browser* browser,
365 AutomationProvider* automation,
366 int32 routing_id)
367 : automation_(automation),
368 routing_id_(routing_id) {
369 NotificationService::current()->
370 AddObserver(this, NOTIFY_BROWSER_CLOSED, Source<Browser>(browser));
371 }
372
373 virtual void Observe(NotificationType type,
374 const NotificationSource& source,
375 const NotificationDetails& details) {
376 DCHECK(type == NOTIFY_BROWSER_CLOSED);
377 Details<bool> close_app(details);
378 automation_->Send(
379 new AutomationMsg_CloseBrowserResponse(routing_id_,
380 true,
381 *(close_app.ptr())));
382 delete this;
383 }
384
385 private:
386 AutomationProvider* automation_;
387 int32 routing_id_;
388};
389
390class FindInPageNotificationObserver : public NotificationObserver {
391 public:
392 FindInPageNotificationObserver(AutomationProvider* automation,
393 TabContents* parent_tab,
394 int32 routing_id)
395 : automation_(automation),
396 parent_tab_(parent_tab),
397 routing_id_(routing_id) {
398 NotificationService::current()->
399 AddObserver(this, NOTIFY_FIND_RESULT_AVAILABLE,
400 Source<TabContents>(parent_tab_));
401 }
402
403 ~FindInPageNotificationObserver() {
404 Unregister();
405 }
406
407 void Unregister() {
408 NotificationService::current()->
409 RemoveObserver(this, NOTIFY_FIND_RESULT_AVAILABLE,
410 Source<TabContents>(parent_tab_));
411 }
412
413 virtual void Observe(NotificationType type, const NotificationSource& source,
414 const NotificationDetails& details) {
415 if (type == NOTIFY_FIND_RESULT_AVAILABLE) {
416 Details<FindNotificationDetails> find_details(details);
417 if (find_details->request_id() == kFindInPageRequestId) {
418 if (find_details->final_update()) {
419 automation_->Send(new AutomationMsg_FindInPageResponse(routing_id_,
420 find_details->number_of_matches()));
421 } else {
422 DLOG(INFO) << "Ignoring, since we only care about the final message";
423 }
424 }
425 } else {
426 NOTREACHED();
427 }
428 }
429
430 // The Find mechanism is over asynchronous IPC, so a search is kicked off and
431 // we wait for notification to find out what the results are. As the user is
432 // typing, new search requests can be issued and the Request ID helps us make
433 // sense of whether this is the current request or an old one. The unit tests,
434 // however, which uses this constant issues only one search at a time, so we
435 // don't need a rolling id to identify each search. But, we still need to
436 // specify one, so we just use a fixed one - its value does not matter.
437 static const int kFindInPageRequestId;
438 private:
439 AutomationProvider* automation_;
440 TabContents* parent_tab_;
441 int32 routing_id_;
442};
443
444const int FindInPageNotificationObserver::kFindInPageRequestId = -1;
445
446class DomOperationNotificationObserver : public NotificationObserver {
447 public:
448 explicit DomOperationNotificationObserver(AutomationProvider* automation)
449 : automation_(automation) {
450 NotificationService::current()->
451 AddObserver(this, NOTIFY_DOM_OPERATION_RESPONSE,
452 NotificationService::AllSources());
453 }
454
455 ~DomOperationNotificationObserver() {
456 NotificationService::current()->
457 RemoveObserver(this, NOTIFY_DOM_OPERATION_RESPONSE,
458 NotificationService::AllSources());
459 }
460
461 virtual void Observe(NotificationType type, const NotificationSource& source,
462 const NotificationDetails& details) {
463 if (NOTIFY_DOM_OPERATION_RESPONSE == type) {
464 Details<DomOperationNotificationDetails> dom_op_details(details);
465 automation_->Send(new AutomationMsg_DomOperationResponse(
466 dom_op_details->automation_id(),
467 dom_op_details->json()));
468 }
469 }
470 private:
471 AutomationProvider* automation_;
472};
473
474class DomInspectorNotificationObserver : public NotificationObserver {
475 public:
476 explicit DomInspectorNotificationObserver(AutomationProvider* automation)
477 : automation_(automation) {
478 NotificationService::current()->
479 AddObserver(this, NOTIFY_DOM_INSPECT_ELEMENT_RESPONSE,
480 NotificationService::AllSources());
481 }
482
483 ~DomInspectorNotificationObserver() {
484 NotificationService::current()->
485 RemoveObserver(this, NOTIFY_DOM_INSPECT_ELEMENT_RESPONSE,
486 NotificationService::AllSources());
487 }
488
489 virtual void Observe(NotificationType type, const NotificationSource& source,
490 const NotificationDetails& details) {
491 if (NOTIFY_DOM_INSPECT_ELEMENT_RESPONSE == type) {
492 Details<int> dom_inspect_details(details);
493 automation_->ReceivedInspectElementResponse(*(dom_inspect_details.ptr()));
494 }
495 }
496
497 private:
498 AutomationProvider* automation_;
499};
500
501class DocumentPrintedNotificationObserver : public NotificationObserver {
502 public:
503 DocumentPrintedNotificationObserver(AutomationProvider* automation,
504 int32 routing_id)
505 : automation_(automation),
506 routing_id_(routing_id),
507 success_(false) {
508 NotificationService::current()->
509 AddObserver(this, NOTIFY_PRINT_JOB_EVENT,
510 NotificationService::AllSources());
511 }
512
513 ~DocumentPrintedNotificationObserver() {
514 automation_->Send(
515 new AutomationMsg_PrintNowResponse(routing_id_, success_));
516 automation_->RemoveNavigationStatusListener(this);
517 NotificationService::current()->
518 RemoveObserver(this, NOTIFY_PRINT_JOB_EVENT,
519 NotificationService::AllSources());
520 }
521
522 virtual void Observe(NotificationType type, const NotificationSource& source,
523 const NotificationDetails& details) {
524 using namespace printing;
525 DCHECK(type == NOTIFY_PRINT_JOB_EVENT);
526 switch (Details<JobEventDetails>(details)->type()) {
527 case JobEventDetails::JOB_DONE: {
528 // Succeeded.
529 success_ = true;
530 delete this;
531 break;
532 }
533 case JobEventDetails::USER_INIT_CANCELED:
534 case JobEventDetails::FAILED: {
535 // Failed.
536 delete this;
537 break;
538 }
539 case JobEventDetails::NEW_DOC:
540 case JobEventDetails::USER_INIT_DONE:
541 case JobEventDetails::DEFAULT_INIT_DONE:
542 case JobEventDetails::NEW_PAGE:
543 case JobEventDetails::PAGE_DONE:
544 case JobEventDetails::DOC_DONE:
545 case JobEventDetails::ALL_PAGES_REQUESTED: {
546 // Don't care.
547 break;
548 }
549 default: {
550 NOTREACHED();
551 break;
552 }
553 }
554 }
555
556 private:
557 scoped_refptr<AutomationProvider> automation_;
558 int32 routing_id_;
559 bool success_;
560};
561
562AutomationProvider::AutomationProvider(Profile* profile)
[email protected]295039bd2008-08-15 04:32:57563 : redirect_query_(0),
initial.commit09911bf2008-07-26 23:55:29564 profile_(profile) {
initial.commit09911bf2008-07-26 23:55:29565 browser_tracker_.reset(new AutomationBrowserTracker(this));
566 window_tracker_.reset(new AutomationWindowTracker(this));
567 tab_tracker_.reset(new AutomationTabTracker(this));
568 autocomplete_edit_tracker_.reset(
569 new AutomationAutocompleteEditTracker(this));
570 cwindow_tracker_.reset(new AutomationConstrainedWindowTracker(this));
571 new_tab_ui_load_observer_.reset(new NewTabUILoadObserver(this));
572 dom_operation_observer_.reset(new DomOperationNotificationObserver(this));
573 dom_inspector_observer_.reset(new DomInspectorNotificationObserver(this));
574}
575
576AutomationProvider::~AutomationProvider() {
[email protected]0da050b92008-08-19 19:29:47577 // Make sure that any outstanding NotificationObservers also get destroyed.
578 ObserverList<NotificationObserver>::Iterator it(notification_observer_list_);
579 NotificationObserver* observer;
580 while ((observer = it.GetNext()) != NULL)
581 delete observer;
initial.commit09911bf2008-07-26 23:55:29582}
583
584void AutomationProvider::ConnectToChannel(const std::wstring& channel_id) {
[email protected]295039bd2008-08-15 04:32:57585 channel_.reset(
586 new IPC::ChannelProxy(channel_id, IPC::Channel::MODE_CLIENT, this, NULL,
587 g_browser_process->io_thread()->message_loop()));
588 channel_->Send(new AutomationMsg_Hello(0));
initial.commit09911bf2008-07-26 23:55:29589}
590
591void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) {
592 if (expected_tabs == 0) {
593 Send(new AutomationMsg_InitialLoadsComplete(0));
594 } else {
595 initial_load_observer_.reset(new InitialLoadObserver(expected_tabs, this));
596 }
597}
598
599NotificationObserver* AutomationProvider::AddNavigationStatusListener(
600 NavigationController* tab, IPC::Message* completed_response,
601 IPC::Message* auth_needed_response) {
602 NotificationObserver* observer =
603 new NavigationNotificationObserver(tab, this, completed_response,
604 auth_needed_response);
605 notification_observer_list_.AddObserver(observer);
606
607 return observer;
608}
609
610void AutomationProvider::RemoveNavigationStatusListener(
611 NotificationObserver* obs) {
612 notification_observer_list_.RemoveObserver(obs);
613}
614
615NotificationObserver* AutomationProvider::AddTabStripObserver(
616 Browser* parent, int32 routing_id) {
617 NotificationObserver* observer = new
618 TabAppendedNotificationObserver(parent, this, routing_id);
619 notification_observer_list_.AddObserver(observer);
620
621 return observer;
622}
623
624void AutomationProvider::RemoveTabStripObserver(NotificationObserver* obs) {
625 notification_observer_list_.RemoveObserver(obs);
626}
627
628void AutomationProvider::AddLoginHandler(NavigationController* tab,
629 LoginHandler* handler) {
630 login_handler_map_[tab] = handler;
631}
632
633void AutomationProvider::RemoveLoginHandler(NavigationController* tab) {
634 DCHECK(login_handler_map_[tab]);
635 login_handler_map_.erase(tab);
636}
637
638int AutomationProvider::GetIndexForNavigationController(
639 const NavigationController* controller, const Browser* parent) const {
640 DCHECK(parent);
641 return parent->GetIndexOfController(controller);
642}
643
644void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
645 IPC_BEGIN_MESSAGE_MAP(AutomationProvider, message)
646 IPC_MESSAGE_HANDLER(AutomationMsg_CloseBrowserRequest, CloseBrowser)
647 IPC_MESSAGE_HANDLER(AutomationMsg_ActivateTabRequest, ActivateTab)
648 IPC_MESSAGE_HANDLER(AutomationMsg_ActiveTabIndexRequest, GetActiveTabIndex)
649 IPC_MESSAGE_HANDLER(AutomationMsg_AppendTabRequest, AppendTab)
650 IPC_MESSAGE_HANDLER(AutomationMsg_CloseTabRequest, CloseTab)
651 IPC_MESSAGE_HANDLER(AutomationMsg_GetCookiesRequest, GetCookies)
652 IPC_MESSAGE_HANDLER(AutomationMsg_SetCookieRequest, SetCookie)
653 IPC_MESSAGE_HANDLER(AutomationMsg_NavigateToURLRequest, NavigateToURL)
654 IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsyncRequest, NavigationAsync)
655 IPC_MESSAGE_HANDLER(AutomationMsg_GoBackRequest, GoBack)
656 IPC_MESSAGE_HANDLER(AutomationMsg_GoForwardRequest, GoForward)
657 IPC_MESSAGE_HANDLER(AutomationMsg_ReloadRequest, Reload)
658 IPC_MESSAGE_HANDLER(AutomationMsg_SetAuthRequest, SetAuth)
659 IPC_MESSAGE_HANDLER(AutomationMsg_CancelAuthRequest, CancelAuth)
660 IPC_MESSAGE_HANDLER(AutomationMsg_NeedsAuthRequest, NeedsAuth)
661 IPC_MESSAGE_HANDLER(AutomationMsg_RedirectsFromRequest, GetRedirectsFrom)
662 IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowCountRequest,
663 GetBrowserWindowCount)
664 IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowRequest, GetBrowserWindow)
665 IPC_MESSAGE_HANDLER(AutomationMsg_LastActiveBrowserWindowRequest,
666 GetLastActiveBrowserWindow)
667 IPC_MESSAGE_HANDLER(AutomationMsg_ActiveWindowRequest, GetActiveWindow)
668 IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowActiveRequest, IsWindowActive)
669 IPC_MESSAGE_HANDLER(AutomationMsg_ActivateWindow, ActivateWindow);
670 IPC_MESSAGE_HANDLER(AutomationMsg_WindowHWNDRequest, GetWindowHWND)
[email protected]4ae62752008-08-04 23:28:47671 IPC_MESSAGE_HANDLER(AutomationMsg_WindowExecuteCommandRequest,
672 ExecuteBrowserCommand)
initial.commit09911bf2008-07-26 23:55:29673 IPC_MESSAGE_HANDLER(AutomationMsg_WindowViewBoundsRequest,
674 WindowGetViewBounds)
675 IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowVisibleRequest, SetWindowVisible)
676 IPC_MESSAGE_HANDLER(AutomationMsg_WindowClickRequest, WindowSimulateClick)
677 IPC_MESSAGE_HANDLER(AutomationMsg_WindowKeyPressRequest,
678 WindowSimulateKeyPress)
679 IPC_MESSAGE_HANDLER(AutomationMsg_WindowDragRequest, WindowSimulateDrag)
680 IPC_MESSAGE_HANDLER(AutomationMsg_TabCountRequest, GetTabCount)
681 IPC_MESSAGE_HANDLER(AutomationMsg_TabRequest, GetTab)
682 IPC_MESSAGE_HANDLER(AutomationMsg_TabHWNDRequest, GetTabHWND)
683 IPC_MESSAGE_HANDLER(AutomationMsg_TabProcessIDRequest, GetTabProcessID)
684 IPC_MESSAGE_HANDLER(AutomationMsg_TabTitleRequest, GetTabTitle)
685 IPC_MESSAGE_HANDLER(AutomationMsg_TabURLRequest, GetTabURL)
686 IPC_MESSAGE_HANDLER(AutomationMsg_ShelfVisibilityRequest,
687 GetShelfVisibility)
688 IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused)
689 IPC_MESSAGE_HANDLER(AutomationMsg_ApplyAcceleratorRequest, ApplyAccelerator)
690 IPC_MESSAGE_HANDLER(AutomationMsg_DomOperationRequest, ExecuteJavascript)
691 IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowCountRequest,
692 GetConstrainedWindowCount)
693 IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowRequest,
694 GetConstrainedWindow)
695 IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedTitleRequest,
696 GetConstrainedTitle)
697 IPC_MESSAGE_HANDLER(AutomationMsg_FindInPageRequest,
698 HandleFindInPageRequest)
699 IPC_MESSAGE_HANDLER(AutomationMsg_GetFocusedViewIDRequest, GetFocusedViewID)
700 IPC_MESSAGE_HANDLER(AutomationMsg_InspectElementRequest,
701 HandleInspectElementRequest)
702 IPC_MESSAGE_HANDLER(AutomationMsg_SetFilteredInet,
703 SetFilteredInet);
704 IPC_MESSAGE_HANDLER(AutomationMsg_DownloadDirectoryRequest,
705 GetDownloadDirectory);
706 IPC_MESSAGE_HANDLER(AutomationMsg_OpenNewBrowserWindow,
707 OpenNewBrowserWindow);
708 IPC_MESSAGE_HANDLER(AutomationMsg_WindowForBrowserRequest,
709 GetWindowForBrowser);
710 IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditForBrowserRequest,
711 GetAutocompleteEditForBrowser);
712 IPC_MESSAGE_HANDLER(AutomationMsg_BrowserForWindowRequest,
713 GetBrowserForWindow);
714 IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab)
715 IPC_MESSAGE_HANDLER(AutomationMsg_NavigateInExternalTabRequest,
716 NavigateInExternalTab)
717 IPC_MESSAGE_HANDLER(AutomationMsg_ShowInterstitialPageRequest,
718 ShowInterstitialPage);
719 IPC_MESSAGE_HANDLER(AutomationMsg_HideInterstitialPageRequest,
720 HideInterstitialPage);
721 IPC_MESSAGE_HANDLER(AutomationMsg_SetAcceleratorsForTab,
722 SetAcceleratorsForTab)
723 IPC_MESSAGE_HANDLER(AutomationMsg_ProcessUnhandledAccelerator,
724 ProcessUnhandledAccelerator)
725 IPC_MESSAGE_HANDLER(AutomationMsg_WaitForTabToBeRestored,
726 WaitForTabToBeRestored)
727 IPC_MESSAGE_HANDLER(AutomationMsg_GetSecurityState,
728 GetSecurityState)
729 IPC_MESSAGE_HANDLER(AutomationMsg_GetPageType,
730 GetPageType)
731 IPC_MESSAGE_HANDLER(AutomationMsg_ActionOnSSLBlockingPage,
732 ActionOnSSLBlockingPage)
733 IPC_MESSAGE_HANDLER(AutomationMsg_BringBrowserToFront, BringBrowserToFront)
734 IPC_MESSAGE_HANDLER(AutomationMsg_IsPageMenuCommandEnabled,
735 IsPageMenuCommandEnabled)
736 IPC_MESSAGE_HANDLER(AutomationMsg_PrintNowRequest, PrintNow)
737 IPC_MESSAGE_HANDLER(AutomationMsg_SavePageRequest, SavePage)
738 IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetTextRequest,
739 GetAutocompleteEditText)
740 IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditSetTextRequest,
741 SetAutocompleteEditText)
742 IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditIsQueryInProgressRequest,
743 AutocompleteEditIsQueryInProgress)
744 IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetMatchesRequest,
745 AutocompleteEditGetMatches)
746 IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowBoundsRequest,
747 GetConstrainedWindowBounds)
[email protected]5f8af2a2008-08-06 22:49:45748 IPC_MESSAGE_HANDLER(AutomationMsg_OpenFindInPageRequest,
749 HandleOpenFindInPageRequest)
[email protected]18cb2572008-08-21 20:34:45750 IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost,
751 OnMessageFromExternalHost)
initial.commit09911bf2008-07-26 23:55:29752 IPC_END_MESSAGE_MAP()
753}
754
755void AutomationProvider::ActivateTab(const IPC::Message& message,
756 int handle, int at_index) {
757 int status = -1;
758 if (browser_tracker_->ContainsHandle(handle) && at_index > -1) {
759 Browser* browser = browser_tracker_->GetResource(handle);
760 if (at_index >= 0 && at_index < browser->tab_count()) {
761 browser->SelectTabContentsAt(at_index, true);
762 status = 0;
763 }
764 }
765 Send(new AutomationMsg_ActivateTabResponse(message.routing_id(), status));
766}
767
768void AutomationProvider::AppendTab(const IPC::Message& message,
769 int handle, const GURL& url) {
770 int append_tab_response = -1; // -1 is the error code
771 NotificationObserver* observer = NULL;
772
773 if (browser_tracker_->ContainsHandle(handle)) {
774 Browser* browser = browser_tracker_->GetResource(handle);
775 observer = AddTabStripObserver(browser, message.routing_id());
776 TabContents* tab_contents =
777 browser->AddTabWithURL(url, PageTransition::TYPED, true, NULL);
778 if (tab_contents) {
779 append_tab_response =
780 GetIndexForNavigationController(tab_contents->controller(), browser);
781 }
782 }
783
784 if (append_tab_response < 0) {
785 // The append tab failed. Remove the TabStripObserver
786 if (observer) {
787 RemoveTabStripObserver(observer);
788 delete observer;
789 }
790
791 // This will be reached only if the tab could not be appended. In case of a
792 // successful tab append, a successful navigation notification triggers the
793 // send.
794 Send(new AutomationMsg_AppendTabResponse(message.routing_id(),
795 append_tab_response));
796 }
797}
798
799void AutomationProvider::NavigateToURL(const IPC::Message& message,
800 int handle, const GURL& url) {
801 int status = AUTOMATION_MSG_NAVIGATION_ERROR;
802
803 if (tab_tracker_->ContainsHandle(handle)) {
804 NavigationController* tab = tab_tracker_->GetResource(handle);
805
806 // Simulate what a user would do. Activate the tab and then navigate.
807 // We could allow navigating in a background tab in future.
808 Browser* browser = FindAndActivateTab(tab);
809
810 if (browser) {
811 AddNavigationStatusListener(tab,
812 new AutomationMsg_NavigateToURLResponse(
813 message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
814 new AutomationMsg_NavigateToURLResponse(
815 message.routing_id(), AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED));
816 // TODO(darin): avoid conversion to GURL
817 browser->OpenURL(url, CURRENT_TAB, PageTransition::TYPED);
818 return;
819 }
820 }
821 Send(new AutomationMsg_NavigateToURLResponse(
822 message.routing_id(), AUTOMATION_MSG_NAVIGATION_ERROR));
823}
824
825void AutomationProvider::NavigationAsync(const IPC::Message& message,
826 int handle, const GURL& url) {
827 bool status = false;
828
829 if (tab_tracker_->ContainsHandle(handle)) {
830 NavigationController* tab = tab_tracker_->GetResource(handle);
831
832 // Simulate what a user would do. Activate the tab and then navigate.
833 // We could allow navigating in a background tab in future.
834 Browser* browser = FindAndActivateTab(tab);
835
836 if (browser) {
837 // Don't add any listener unless a callback mechanism is desired.
838 // TODO(vibhor): Do this if such a requirement arises in future.
839 browser->OpenURL(url, CURRENT_TAB, PageTransition::TYPED);
840 status = true;
841 }
842 }
843
844 Send(new AutomationMsg_NavigationAsyncResponse(message.routing_id(), status));
845}
846
847void AutomationProvider::GoBack(const IPC::Message& message, int handle) {
848 if (tab_tracker_->ContainsHandle(handle)) {
849 NavigationController* tab = tab_tracker_->GetResource(handle);
850 Browser* browser = FindAndActivateTab(tab);
851 if (browser && browser->IsCommandEnabled(IDC_BACK)) {
852 AddNavigationStatusListener(tab,
853 new AutomationMsg_GoBackResponse(
854 message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
855 new AutomationMsg_GoBackResponse(
856 message.routing_id(), AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED));
857 browser->GoBack();
858 return;
859 }
860 }
861 Send(new AutomationMsg_GoBackResponse(message.routing_id(),
862 AUTOMATION_MSG_NAVIGATION_ERROR));
863}
864
865void AutomationProvider::GoForward(const IPC::Message& message, int handle) {
866 if (tab_tracker_->ContainsHandle(handle)) {
867 NavigationController* tab = tab_tracker_->GetResource(handle);
868 Browser* browser = FindAndActivateTab(tab);
869 if (browser && browser->IsCommandEnabled(IDC_FORWARD)) {
870 AddNavigationStatusListener(tab,
871 new AutomationMsg_GoForwardResponse(
872 message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
873 new AutomationMsg_GoForwardResponse(
874 message.routing_id(), AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED));
875 browser->GoForward();
876 return;
877 }
878 }
879 Send(new AutomationMsg_GoForwardResponse(message.routing_id(),
880 AUTOMATION_MSG_NAVIGATION_ERROR));
881}
882
883void AutomationProvider::Reload(const IPC::Message& message, int handle) {
884 if (tab_tracker_->ContainsHandle(handle)) {
885 NavigationController* tab = tab_tracker_->GetResource(handle);
886 Browser* browser = FindAndActivateTab(tab);
887 if (browser && browser->IsCommandEnabled(IDC_RELOAD)) {
888 AddNavigationStatusListener(tab,
889 new AutomationMsg_ReloadResponse(
890 message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
891 new AutomationMsg_ReloadResponse(
892 message.routing_id(), AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED));
893 browser->Reload();
894 return;
895 }
896 }
897 Send(new AutomationMsg_ReloadResponse(message.routing_id(),
898 AUTOMATION_MSG_NAVIGATION_ERROR));
899}
900
901void AutomationProvider::SetAuth(const IPC::Message& message, int tab_handle,
902 const std::wstring& username,
903 const std::wstring& password) {
904 int status = -1;
905
906 if (tab_tracker_->ContainsHandle(tab_handle)) {
907 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
908 LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
909
910 if (iter != login_handler_map_.end()) {
911 // If auth is needed again after this, assume login has failed. This is
912 // not strictly correct, because a navigation can require both proxy and
913 // server auth, but it should be OK for now.
914 LoginHandler* handler = iter->second;
915 AddNavigationStatusListener(tab,
916 new AutomationMsg_SetAuthResponse(message.routing_id(), 0),
917 new AutomationMsg_SetAuthResponse(message.routing_id(), -1));
918 handler->SetAuth(username, password);
919 status = 0;
920 }
921 }
922 if (status < 0) {
923 Send(new AutomationMsg_SetAuthResponse(message.routing_id(), status));
924 }
925}
926
927void AutomationProvider::CancelAuth(const IPC::Message& message,
928 int tab_handle) {
929 int status = -1;
930
931 if (tab_tracker_->ContainsHandle(tab_handle)) {
932 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
933 LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
934
935 if (iter != login_handler_map_.end()) {
936 // If auth is needed again after this, something is screwy.
937 LoginHandler* handler = iter->second;
938 AddNavigationStatusListener(tab,
939 new AutomationMsg_CancelAuthResponse(message.routing_id(), 0),
940 new AutomationMsg_CancelAuthResponse(message.routing_id(), -1));
941 handler->CancelAuth();
942 status = 0;
943 }
944 }
945 if (status < 0) {
946 Send(new AutomationMsg_CancelAuthResponse(message.routing_id(), status));
947 }
948}
949
950void AutomationProvider::NeedsAuth(const IPC::Message& message,
951 int tab_handle) {
952 bool needs_auth = false;
953
954 if (tab_tracker_->ContainsHandle(tab_handle)) {
955 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
956 LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
957
958 if (iter != login_handler_map_.end()) {
959 // The LoginHandler will be in our map IFF the tab needs auth.
960 needs_auth = true;
961 }
962 }
963
964 Send(new AutomationMsg_NeedsAuthResponse(message.routing_id(), needs_auth));
965}
966
967void AutomationProvider::GetRedirectsFrom(const IPC::Message& message,
968 int tab_handle,
969 const GURL& source_url) {
970 DCHECK(!redirect_query_) << "Can only handle one redirect query at once.";
971 if (tab_tracker_->ContainsHandle(tab_handle)) {
972 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
973 HistoryService* history_service =
974 tab->profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
975
976 DCHECK(history_service) << "Tab " << tab_handle << "'s profile " <<
977 "has no history service";
978 if (history_service) {
979 // Schedule a history query for redirects. The response will be sent
980 // asynchronously from the callback the history system uses to notify us
981 // that it's done: OnRedirectQueryComplete.
982 redirect_query_routing_id_ = message.routing_id();
983 redirect_query_ = history_service->QueryRedirectsFrom(
984 source_url, &consumer_,
985 NewCallback(this, &AutomationProvider::OnRedirectQueryComplete));
986 return; // Response will be sent when query completes.
987 }
988 }
989
990 // Send failure response.
991 IPC::Message* msg = new IPC::Message(
992 message.routing_id(), AutomationMsg_RedirectsFromResponse::ID,
993 IPC::Message::PRIORITY_NORMAL);
994 msg->WriteInt(-1); // Negative string count indicates an error.
995 Send(msg);
996}
997
998void AutomationProvider::GetActiveTabIndex(const IPC::Message& message,
999 int handle) {
1000 int active_tab_index = -1; // -1 is the error code
1001 if (browser_tracker_->ContainsHandle(handle)) {
1002 Browser* browser = browser_tracker_->GetResource(handle);
1003 active_tab_index = browser->selected_index();
1004 }
1005 Send(new AutomationMsg_ActiveTabIndexResponse(message.routing_id(),
1006 active_tab_index));
1007}
1008
1009void AutomationProvider::GetBrowserWindowCount(const IPC::Message& message) {
1010 Send(new AutomationMsg_BrowserWindowCountResponse(
1011 message.routing_id(), static_cast<int>(BrowserList::size())));
1012}
1013
1014void AutomationProvider::GetBrowserWindow(const IPC::Message& message,
1015 int index) {
1016 int handle = 0;
1017 if (index >= 0) {
1018 BrowserList::const_iterator iter = BrowserList::begin();
1019
1020 for (; (iter != BrowserList::end()) && (index > 0); ++iter, --index);
1021 if (iter != BrowserList::end()) {
1022 handle = browser_tracker_->Add(*iter);
1023 }
1024 }
1025
1026 Send(new AutomationMsg_BrowserWindowResponse(message.routing_id(), handle));
1027}
1028
1029void AutomationProvider::GetLastActiveBrowserWindow(
1030 const IPC::Message& message) {
1031 int handle = 0;
1032 Browser* browser = BrowserList::GetLastActive();
1033 if (browser)
1034 handle = browser_tracker_->Add(browser);
1035 Send(new AutomationMsg_LastActiveBrowserWindowResponse(message.routing_id(),
1036 handle));
1037}
1038
1039BOOL CALLBACK EnumThreadWndProc(HWND hwnd, LPARAM l_param) {
1040 if (hwnd == reinterpret_cast<HWND>(l_param)) {
1041 return FALSE;
1042 }
1043 return TRUE;
1044}
1045
1046void AutomationProvider::GetActiveWindow(const IPC::Message& message) {
1047 HWND window = GetForegroundWindow();
1048
1049 // Let's make sure this window belongs to our process.
1050 if (EnumThreadWindows(::GetCurrentThreadId(),
1051 EnumThreadWndProc,
1052 reinterpret_cast<LPARAM>(window))) {
1053 // We enumerated all the windows and did not find the foreground window,
1054 // it is not our window, ignore it.
1055 Send(new AutomationMsg_ActiveWindowResponse(message.routing_id(), 0));
1056 return;
1057 }
1058
1059 int handle = window_tracker_->Add(window);
1060 Send(new AutomationMsg_ActiveWindowResponse(message.routing_id(), handle));
1061}
1062
1063void AutomationProvider::GetWindowHWND(const IPC::Message& message,
1064 int handle) {
1065 HWND win32_handle = window_tracker_->GetResource(handle);
1066 Send(new AutomationMsg_WindowHWNDResponse(message.routing_id(),
1067 win32_handle));
1068}
1069
[email protected]4ae62752008-08-04 23:28:471070void AutomationProvider::ExecuteBrowserCommand(const IPC::Message& message,
1071 int handle,
1072 int command) {
[email protected]4ae62752008-08-04 23:28:471073 bool success = false;
1074 if (browser_tracker_->ContainsHandle(handle)) {
1075 Browser* browser = browser_tracker_->GetResource(handle);
1076 if (browser->SupportsCommand(command) &&
1077 browser->IsCommandEnabled(command)) {
1078 browser->ExecuteCommand(command);
1079 success = true;
1080 }
1081 }
1082 Send(new AutomationMsg_WindowExecuteCommandResponse(message.routing_id(),
1083 success));
1084}
1085
initial.commit09911bf2008-07-26 23:55:291086void AutomationProvider::WindowGetViewBounds(const IPC::Message& message,
1087 int handle,
1088 int view_id,
1089 bool screen_coordinates) {
1090 bool succeeded = false;
1091 CRect bounds;
1092 bounds.SetRect(0, 0, 0, 0);
1093
1094 void* iter = NULL;
1095 if (window_tracker_->ContainsHandle(handle)) {
1096 HWND hwnd = window_tracker_->GetResource(handle);
1097 ChromeViews::RootView* root_view =
1098 ChromeViews::HWNDViewContainer::FindRootView(hwnd);
1099 if (root_view) {
1100 ChromeViews::View* view = root_view->GetViewByID(view_id);
1101 if (view) {
1102 succeeded = true;
1103 CPoint point(0, 0);
1104 if (screen_coordinates)
1105 ChromeViews::View::ConvertPointToScreen(view, &point);
1106 else
1107 ChromeViews::View::ConvertPointToView(view, root_view, &point);
1108 view->GetLocalBounds(&bounds, false);
1109 bounds.MoveToXY(point.x, point.y);
1110 }
1111 }
1112 }
1113
1114 Send(new AutomationMsg_WindowViewBoundsResponse(
1115 message.routing_id(), succeeded, gfx::Rect(bounds)));
1116}
1117
1118// This task enqueues a mouse event on the event loop, so that the view
1119// that it's being sent to can do the requisite post-processing.
1120class MouseEventTask : public Task {
1121 public:
1122 MouseEventTask(ChromeViews::View* view,
1123 ChromeViews::Event::EventType type,
1124 POINT point,
1125 int flags)
1126 : view_(view), type_(type), point_(point), flags_(flags) {}
1127 virtual ~MouseEventTask() {}
1128
1129 virtual void Run() {
1130 ChromeViews::MouseEvent event(type_, point_.x, point_.y, flags_);
1131 // We need to set the cursor position before we process the event because
1132 // some code (tab dragging, for instance) queries the actual cursor location
1133 // rather than the location of the mouse event. Note that the reason why
1134 // the drag code moved away from using mouse event locations was because
1135 // our conversion to screen location doesn't work well with multiple
1136 // monitors, so this only works reliably in a single monitor setup.
1137 CPoint screen_location = CPoint(point_.x, point_.y);
1138 view_->ConvertPointToScreen(view_, &screen_location);
1139 ::SetCursorPos(screen_location.x, screen_location.y);
1140 switch (type_) {
1141 case ChromeViews::Event::ET_MOUSE_PRESSED:
1142 view_->OnMousePressed(event);
1143 break;
1144
1145 case ChromeViews::Event::ET_MOUSE_DRAGGED:
1146 view_->OnMouseDragged(event);
1147 break;
1148
1149 case ChromeViews::Event::ET_MOUSE_RELEASED:
1150 view_->OnMouseReleased(event, false);
1151 break;
1152
1153 default:
1154 NOTREACHED();
1155 }
1156 }
1157
1158 private:
1159 ChromeViews::View* view_;
1160 ChromeViews::Event::EventType type_;
1161 POINT point_;
1162 int flags_;
1163
1164 DISALLOW_EVIL_CONSTRUCTORS(MouseEventTask);
1165};
1166
1167void AutomationProvider::ScheduleMouseEvent(ChromeViews::View* view,
1168 ChromeViews::Event::EventType type,
1169 POINT point,
1170 int flags) {
1171 MessageLoop::current()->PostTask(FROM_HERE,
1172 new MouseEventTask(view, type, point, flags));
1173}
1174
1175// This task just adds another task to the event queue. This is useful if
1176// you want to ensure that any tasks added to the event queue after this one
1177// have already been processed by the time |task| is run.
1178class InvokeTaskLaterTask : public Task {
1179 public:
1180 explicit InvokeTaskLaterTask(Task* task) : task_(task) {}
1181 virtual ~InvokeTaskLaterTask() {}
1182
1183 virtual void Run() {
1184 MessageLoop::current()->PostTask(FROM_HERE, task_);
1185 }
1186
1187 private:
1188 Task* task_;
1189
1190 DISALLOW_EVIL_CONSTRUCTORS(InvokeTaskLaterTask);
1191};
1192
1193// This task sends a WindowDragResponse message with the appropriate
1194// routing ID to the automation proxy. This is implemented as a task so that
1195// we know that the mouse events (and any tasks that they spawn on the message
1196// loop) have been processed by the time this is sent.
1197class WindowDragResponseTask : public Task {
1198 public:
1199 WindowDragResponseTask(AutomationProvider* provider, int routing_id)
1200 : provider_(provider), routing_id_(routing_id) {}
1201 virtual ~WindowDragResponseTask() {}
1202
1203 virtual void Run() {
1204 provider_->Send(new AutomationMsg_WindowDragResponse(routing_id_, true));
1205 }
1206
1207 private:
1208 AutomationProvider* provider_;
1209 int routing_id_;
1210
1211 DISALLOW_EVIL_CONSTRUCTORS(WindowDragResponseTask);
1212};
1213
1214void AutomationProvider::WindowSimulateClick(const IPC::Message& message,
1215 int handle,
1216 POINT click,
1217 int flags) {
1218 HWND hwnd = 0;
1219
1220 if (window_tracker_->ContainsHandle(handle)) {
1221 hwnd = window_tracker_->GetResource(handle);
1222
1223 BOOL r = ::ClientToScreen(hwnd, &click);
1224 DCHECK(r);
1225 ui_controls::SendMouseMove(click.x, click.y);
1226
1227 ui_controls::MouseButton button = ui_controls::LEFT;
1228 if ((flags & ChromeViews::Event::EF_LEFT_BUTTON_DOWN) ==
1229 ChromeViews::Event::EF_LEFT_BUTTON_DOWN) {
1230 button = ui_controls::LEFT;
1231 } else if ((flags & ChromeViews::Event::EF_RIGHT_BUTTON_DOWN) ==
1232 ChromeViews::Event::EF_RIGHT_BUTTON_DOWN) {
1233 button = ui_controls::RIGHT;
1234 } else if ((flags & ChromeViews::Event::EF_MIDDLE_BUTTON_DOWN) ==
1235 ChromeViews::Event::EF_MIDDLE_BUTTON_DOWN) {
1236 button = ui_controls::MIDDLE;
1237 } else {
1238 NOTREACHED();
1239 }
1240 ui_controls::SendMouseClick(button);
1241 }
1242}
1243
1244void AutomationProvider::WindowSimulateDrag(const IPC::Message& message,
1245 int handle,
1246 std::vector<POINT> drag_path,
[email protected]5e0f30c2008-08-14 22:52:441247 int flags,
1248 bool press_escape_en_route) {
initial.commit09911bf2008-07-26 23:55:291249 bool succeeded = false;
1250 if (browser_tracker_->ContainsHandle(handle) && (drag_path.size() > 1)) {
1251 succeeded = true;
1252
[email protected]0307076a2008-08-01 20:42:271253 UINT down_message = 0;
1254 UINT up_message = 0;
1255 WPARAM wparam_flags = 0;
1256 if (flags & ChromeViews::Event::EF_SHIFT_DOWN)
1257 wparam_flags |= MK_SHIFT;
1258 if (flags & ChromeViews::Event::EF_CONTROL_DOWN)
1259 wparam_flags |= MK_CONTROL;
1260 if (flags & ChromeViews::Event::EF_LEFT_BUTTON_DOWN) {
1261 wparam_flags |= MK_LBUTTON;
1262 down_message = WM_LBUTTONDOWN;
1263 up_message = WM_LBUTTONUP;
1264 }
1265 if (flags & ChromeViews::Event::EF_MIDDLE_BUTTON_DOWN) {
1266 wparam_flags |= MK_MBUTTON;
1267 down_message = WM_MBUTTONDOWN;
1268 up_message = WM_MBUTTONUP;
1269 }
1270 if (flags & ChromeViews::Event::EF_RIGHT_BUTTON_DOWN) {
1271 wparam_flags |= MK_RBUTTON;
1272 down_message = WM_LBUTTONDOWN;
1273 up_message = WM_LBUTTONUP;
1274 }
1275
initial.commit09911bf2008-07-26 23:55:291276 Browser* browser = browser_tracker_->GetResource(handle);
1277 DCHECK(browser);
[email protected]0307076a2008-08-01 20:42:271278 HWND top_level_hwnd = browser->GetTopLevelHWND();
1279 SetCursorPos(drag_path[0].x, drag_path[0].y);
1280 SendMessage(top_level_hwnd, down_message, wparam_flags,
1281 MAKELPARAM(drag_path[0].x, drag_path[0].y));
initial.commit09911bf2008-07-26 23:55:291282 for (int i = 1; i < static_cast<int>(drag_path.size()); ++i) {
[email protected]0307076a2008-08-01 20:42:271283 SetCursorPos(drag_path[i].x, drag_path[i].y);
1284 SendMessage(top_level_hwnd, WM_MOUSEMOVE, wparam_flags,
1285 MAKELPARAM(drag_path[i].x, drag_path[i].y));
initial.commit09911bf2008-07-26 23:55:291286 }
1287 POINT end = drag_path[drag_path.size() - 1];
[email protected]0307076a2008-08-01 20:42:271288 SetCursorPos(end.x, end.y);
[email protected]5e0f30c2008-08-14 22:52:441289
1290 if (press_escape_en_route) {
1291 // Press Escape.
1292 ui_controls::SendKeyPress(VK_ESCAPE,
1293 ((flags & ChromeViews::Event::EF_CONTROL_DOWN)
1294 == ChromeViews::Event::EF_CONTROL_DOWN),
1295 ((flags & ChromeViews::Event::EF_SHIFT_DOWN) ==
1296 ChromeViews::Event::EF_SHIFT_DOWN),
1297 ((flags & ChromeViews::Event::EF_ALT_DOWN) ==
1298 ChromeViews::Event::EF_ALT_DOWN));
1299 }
[email protected]0307076a2008-08-01 20:42:271300 SendMessage(top_level_hwnd, up_message, wparam_flags,
1301 MAKELPARAM(end.x, end.y));
initial.commit09911bf2008-07-26 23:55:291302
1303 MessageLoop::current()->PostTask(FROM_HERE,
1304 new InvokeTaskLaterTask(
1305 new WindowDragResponseTask(this, message.routing_id())));
1306 } else {
1307 Send(new AutomationMsg_WindowDragResponse(message.routing_id(), true));
1308 }
1309}
1310
1311void AutomationProvider::WindowSimulateKeyPress(const IPC::Message& message,
1312 int handle,
1313 wchar_t key,
1314 int flags) {
1315 if (!window_tracker_->ContainsHandle(handle))
1316 return;
1317
1318 // The key event is sent to whatever window is active.
1319 ui_controls::SendKeyPress(key,
1320 ((flags & ChromeViews::Event::EF_CONTROL_DOWN) ==
1321 ChromeViews::Event::EF_CONTROL_DOWN),
1322 ((flags & ChromeViews::Event::EF_SHIFT_DOWN) ==
1323 ChromeViews::Event::EF_SHIFT_DOWN),
1324 ((flags & ChromeViews::Event::EF_ALT_DOWN) ==
1325 ChromeViews::Event::EF_ALT_DOWN));
1326}
1327
1328void AutomationProvider::GetFocusedViewID(const IPC::Message& message,
1329 int handle) {
1330 int view_id = -1;
1331 if (window_tracker_->ContainsHandle(handle)) {
1332 HWND hwnd = window_tracker_->GetResource(handle);
1333 ChromeViews::FocusManager* focus_manager =
1334 ChromeViews::FocusManager::GetFocusManager(hwnd);
1335 DCHECK(focus_manager);
1336 ChromeViews::View* focused_view = focus_manager->GetFocusedView();
1337 if (focused_view)
1338 view_id = focused_view->GetID();
1339 }
1340 Send(new AutomationMsg_GetFocusedViewIDResponse(message.routing_id(),
1341 view_id));
1342}
1343
1344void AutomationProvider::SetWindowVisible(const IPC::Message& message,
1345 int handle, bool visible) {
1346 if (window_tracker_->ContainsHandle(handle)) {
1347 HWND hwnd = window_tracker_->GetResource(handle);
1348 ::ShowWindow(hwnd, visible ? SW_SHOW : SW_HIDE);
1349 Send(new AutomationMsg_SetWindowVisibleResponse(message.routing_id(),
1350 true));
1351 } else {
1352 Send(new AutomationMsg_SetWindowVisibleResponse(message.routing_id(),
1353 false));
1354 }
1355}
1356
1357void AutomationProvider::IsWindowActive(const IPC::Message& message,
1358 int handle) {
1359 if (window_tracker_->ContainsHandle(handle)) {
1360 HWND hwnd = window_tracker_->GetResource(handle);
1361 bool is_active = ::GetForegroundWindow() == hwnd;
1362 Send(new AutomationMsg_IsWindowActiveResponse(
1363 message.routing_id(), true, is_active));
1364 } else {
1365 Send(new AutomationMsg_IsWindowActiveResponse(message.routing_id(),
1366 false, false));
1367 }
1368}
1369
1370void AutomationProvider::ActivateWindow(const IPC::Message& message,
1371 int handle) {
1372 if (window_tracker_->ContainsHandle(handle)) {
1373 ::SetActiveWindow(window_tracker_->GetResource(handle));
1374 }
1375}
1376
1377void AutomationProvider::GetTabCount(const IPC::Message& message, int handle) {
1378 int tab_count = -1; // -1 is the error code
1379
1380 if (browser_tracker_->ContainsHandle(handle)) {
1381 Browser* browser = browser_tracker_->GetResource(handle);
1382 tab_count = browser->tab_count();
1383 }
1384
1385 Send(new AutomationMsg_TabCountResponse(message.routing_id(), tab_count));
1386}
1387
1388void AutomationProvider::GetTab(const IPC::Message& message,
1389 int win_handle, int tab_index) {
1390 void* iter = NULL;
1391 int tab_handle = 0;
1392 if (browser_tracker_->ContainsHandle(win_handle) && (tab_index >= 0)) {
1393 Browser* browser = browser_tracker_->GetResource(win_handle);
1394 if (tab_index < browser->tab_count()) {
1395 TabContents* tab_contents =
1396 browser->GetTabContentsAt(tab_index);
1397 tab_handle = tab_tracker_->Add(tab_contents->controller());
1398 }
1399 }
1400
1401 Send(new AutomationMsg_TabResponse(message.routing_id(), tab_handle));
1402}
1403
1404void AutomationProvider::GetTabTitle(const IPC::Message& message, int handle) {
1405 int title_string_size = -1; // -1 is the error code
1406 std::wstring title;
1407 if (tab_tracker_->ContainsHandle(handle)) {
1408 NavigationController* tab = tab_tracker_->GetResource(handle);
1409 title = tab->GetActiveEntry()->GetTitle();
1410 title_string_size = static_cast<int>(title.size());
1411 }
1412
1413 Send(new AutomationMsg_TabTitleResponse(message.routing_id(),
1414 title_string_size, title));
1415}
1416
1417void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) {
1418 if (window_tracker_->ContainsHandle(handle)) {
1419 window_tracker_->Remove(window_tracker_->GetResource(handle));
1420 }
1421}
1422
1423void AutomationProvider::OnChannelError() {
1424 LOG(ERROR) << "AutomationProxy went away, shutting down app.";
[email protected]295039bd2008-08-15 04:32:571425 AutomationProviderList::GetInstance()->RemoveProvider(this);
initial.commit09911bf2008-07-26 23:55:291426}
1427
1428// TODO(brettw) change this to accept GURLs when history supports it
1429void AutomationProvider::OnRedirectQueryComplete(
1430 HistoryService::Handle request_handle,
1431 GURL from_url,
1432 bool success,
1433 HistoryService::RedirectList* redirects) {
1434 DCHECK(request_handle == redirect_query_);
1435
1436 // Respond to the pending request for the redirect list.
1437 IPC::Message* msg = new IPC::Message(redirect_query_routing_id_,
1438 AutomationMsg_RedirectsFromResponse::ID,
1439 IPC::Message::PRIORITY_NORMAL);
1440 if (success) {
1441 msg->WriteInt(static_cast<int>(redirects->size()));
1442 for (size_t i = 0; i < redirects->size(); i++)
1443 IPC::ParamTraits<GURL>::Write(msg, redirects->at(i));
1444 } else {
1445 msg->WriteInt(-1); // Negative count indicates failure.
1446 }
1447
1448 Send(msg);
1449 redirect_query_ = NULL;
1450}
1451
1452bool AutomationProvider::Send(IPC::Message* msg) {
[email protected]295039bd2008-08-15 04:32:571453 DCHECK(channel_.get());
1454 return channel_->Send(msg);
initial.commit09911bf2008-07-26 23:55:291455}
1456
1457Browser* AutomationProvider::FindAndActivateTab(
1458 NavigationController* controller) {
1459 int tab_index;
1460 Browser* browser = Browser::GetBrowserForController(controller, &tab_index);
1461 if (browser)
1462 browser->SelectTabContentsAt(tab_index, true);
1463
1464 return browser;
1465}
1466
1467void AutomationProvider::GetCookies(const IPC::Message& message,
1468 const GURL& url, int handle) {
1469 std::string value;
1470
1471 if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
1472 NavigationController* tab = tab_tracker_->GetResource(handle);
1473 value =
1474 tab->profile()->GetRequestContext()->cookie_store()->GetCookies(url);
1475 }
1476
1477 Send(new AutomationMsg_GetCookiesResponse(message.routing_id(),
1478 static_cast<int>(value.size()), value));
1479}
1480
1481void AutomationProvider::SetCookie(const IPC::Message& message,
1482 const GURL& url,
1483 const std::string value,
1484 int handle) {
1485 int response_value = -1;
1486
1487 if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
1488 NavigationController* tab = tab_tracker_->GetResource(handle);
1489 URLRequestContext* context = tab->profile()->GetRequestContext();
1490 if (context->cookie_store()->SetCookie(url, value))
1491 response_value = 1;
1492 }
1493
1494 Send(new AutomationMsg_SetCookieResponse(message.routing_id(),
1495 response_value));
1496}
1497
1498void AutomationProvider::GetTabURL(const IPC::Message& message, int handle) {
1499 bool success = false;
1500 GURL url;
1501 if (tab_tracker_->ContainsHandle(handle)) {
1502 NavigationController* tab = tab_tracker_->GetResource(handle);
1503 // Return what the user would see in the location bar.
1504 url = tab->GetActiveEntry()->GetDisplayURL();
1505 success = true;
1506 }
1507
1508 Send(new AutomationMsg_TabURLResponse(message.routing_id(), success, url));
1509}
1510
1511void AutomationProvider::GetTabHWND(const IPC::Message& message, int handle) {
1512 HWND tab_hwnd = NULL;
1513
1514 if (tab_tracker_->ContainsHandle(handle)) {
1515 NavigationController* tab = tab_tracker_->GetResource(handle);
1516 tab_hwnd = tab->active_contents()->GetContainerHWND();
1517 }
1518
1519 Send(new AutomationMsg_TabHWNDResponse(message.routing_id(), tab_hwnd));
1520}
1521
1522void AutomationProvider::GetTabProcessID(
1523 const IPC::Message& message, int handle) {
1524 int process_id = -1;
1525
1526 if (tab_tracker_->ContainsHandle(handle)) {
1527 process_id = 0;
1528 NavigationController* tab = tab_tracker_->GetResource(handle);
1529 if (tab->active_contents()->AsWebContents()) {
1530 WebContents* web_contents = tab->active_contents()->AsWebContents();
1531 if (web_contents->process()) {
1532 process_id =
1533 process_util::GetProcId(web_contents->process()->process());
1534 }
1535 }
1536 }
1537
1538 Send(new AutomationMsg_TabProcessIDResponse(message.routing_id(),
1539 process_id));
1540}
1541
1542void AutomationProvider::ApplyAccelerator(int handle, int id) {
1543 if (browser_tracker_->ContainsHandle(handle)) {
1544 Browser* browser = browser_tracker_->GetResource(handle);
1545 browser->controller()->ExecuteCommand(id);
1546 }
1547}
1548
1549void AutomationProvider::ExecuteJavascript(const IPC::Message& message,
1550 int handle,
1551 const std::wstring& frame_xpath,
1552 const std::wstring& script) {
1553 bool succeeded = false;
1554 if (tab_tracker_->ContainsHandle(handle)) {
1555 NavigationController* tab = tab_tracker_->GetResource(handle);
1556 TabContents* tab_contents = tab->active_contents();
1557 if (tab_contents && tab_contents->type() == TAB_CONTENTS_WEB) {
1558 WebContents* web_contents = tab_contents->AsWebContents();
1559
1560 // Set the routing id of this message with the controller.
1561 // This routing id needs to be remembered for the reverse
1562 // communication while sending back the response of
1563 // this javascript execution.
1564 std::wstring url;
1565 SStringPrintf(&url,
1566 L"javascript:void(window.domAutomationController.setAutomationId(%d));",
1567 message.routing_id());
1568
1569 web_contents->ExecuteJavascriptInWebFrame(frame_xpath, url);
1570 web_contents->ExecuteJavascriptInWebFrame(frame_xpath, script);
1571 succeeded = true;
1572 }
1573 }
1574
1575 if (!succeeded) {
1576 Send(new AutomationMsg_DomOperationResponse(message.routing_id(), ""));
1577 }
1578}
1579
1580void AutomationProvider::GetShelfVisibility(const IPC::Message& message,
1581 int handle) {
1582 bool visible = false;
1583 if (tab_tracker_->ContainsHandle(handle)) {
1584 NavigationController* tab = tab_tracker_->GetResource(handle);
1585 TabContents* tab_contents = tab->active_contents();
1586 if (tab_contents && tab_contents->type() == TAB_CONTENTS_WEB) {
1587 WebContents* web_contents = tab_contents->AsWebContents();
1588 visible = web_contents->IsDownloadShelfVisible();
1589 }
1590 }
1591
1592 Send(new AutomationMsg_ShelfVisibilityResponse(message.routing_id(),
1593 visible));
1594}
1595
1596void AutomationProvider::GetConstrainedWindowCount(const IPC::Message& message,
1597 int handle) {
1598 int count = -1; // -1 is the error code
1599 if (tab_tracker_->ContainsHandle(handle)) {
1600 NavigationController* nav_controller = tab_tracker_->GetResource(handle);
1601 TabContents* tab_contents = nav_controller->active_contents();
1602 if (tab_contents) {
1603 count = static_cast<int>(tab_contents->child_windows_.size());
1604 }
1605 }
1606
1607 Send(new AutomationMsg_ConstrainedWindowCountResponse(message.routing_id(),
1608 count));
1609}
1610
1611void AutomationProvider::GetConstrainedWindow(const IPC::Message& message,
1612 int handle, int index) {
1613 int cwindow_handle = 0;
1614 if (tab_tracker_->ContainsHandle(handle) && index >= 0) {
1615 NavigationController* nav_controller =
1616 tab_tracker_->GetResource(handle);
1617 TabContents* tab = nav_controller->active_contents();
1618 if (tab && index < static_cast<int>(tab->child_windows().size())) {
1619 ConstrainedWindow* window = tab->child_windows()[index];
1620 cwindow_handle = cwindow_tracker_->Add(window);
1621 }
1622 }
1623
1624 Send(new AutomationMsg_ConstrainedWindowResponse(message.routing_id(),
1625 cwindow_handle));
1626}
1627
1628void AutomationProvider::GetConstrainedTitle(const IPC::Message& message,
1629 int handle) {
1630 int title_string_size = -1; // -1 is the error code
1631 std::wstring title;
1632 if (cwindow_tracker_->ContainsHandle(handle)) {
1633 ConstrainedWindow* window = cwindow_tracker_->GetResource(handle);
1634 title = window->GetWindowTitle();
1635 title_string_size = static_cast<int>(title.size());
1636 }
1637
1638 Send(new AutomationMsg_ConstrainedTitleResponse(message.routing_id(),
1639 title_string_size, title));
1640}
1641
1642void AutomationProvider::GetConstrainedWindowBounds(const IPC::Message& message,
1643 int handle) {
1644 bool exists = false;
1645 gfx::Rect rect(0, 0, 0, 0);
1646 if (cwindow_tracker_->ContainsHandle(handle)) {
1647 ConstrainedWindow* window = cwindow_tracker_->GetResource(handle);
1648 if (window) {
1649 exists = true;
1650 rect = window->GetCurrentBounds();
1651 }
1652 }
1653
1654 Send(new AutomationMsg_ConstrainedWindowBoundsResponse(message.routing_id(),
1655 exists, rect));
1656}
1657
1658void AutomationProvider::HandleFindInPageRequest(
1659 const IPC::Message& message, int handle, const std::wstring& find_request,
1660 int forward, int match_case) {
1661 if (!tab_tracker_->ContainsHandle(handle)) {
1662 Send(new AutomationMsg_FindInPageResponse(message.routing_id(), -1));
1663 return;
1664 }
1665
1666 NavigationController* nav = tab_tracker_->GetResource(handle);
1667 TabContents* tab_contents = nav->active_contents();
1668
1669 find_in_page_observer_.reset(new
1670 FindInPageNotificationObserver(this, tab_contents, message.routing_id()));
1671
[email protected]edc28612008-08-14 20:23:361672 // The find in page dialog must be up for us to get the notification that the
1673 // find was complete
1674 if (tab_contents->AsWebContents()) {
1675 NavigationController* tab = tab_tracker_->GetResource(handle);
1676 Browser* browser = Browser::GetBrowserForController(tab, NULL);
1677 tab_contents->AsWebContents()->OpenFindInPageWindow(*browser);
1678 }
1679
initial.commit09911bf2008-07-26 23:55:291680 // The explicit comparison to TRUE avoids a warning (C4800).
1681 tab_contents->StartFinding(
1682 FindInPageNotificationObserver::kFindInPageRequestId,
1683 find_request, forward == TRUE, match_case == TRUE,
1684 false); // Not a FindNext operation.
1685}
1686
[email protected]5f8af2a2008-08-06 22:49:451687void AutomationProvider::HandleOpenFindInPageRequest(
1688 const IPC::Message& message, int handle) {
1689 if (tab_tracker_->ContainsHandle(handle)) {
1690 NavigationController* tab = tab_tracker_->GetResource(handle);
1691 Browser* browser = Browser::GetBrowserForController(tab, NULL);
1692 if (tab->active_contents()->AsWebContents()) {
1693 WebContents* web_contents = tab->active_contents()->AsWebContents();
1694 web_contents->OpenFindInPageWindow(*browser);
1695 }
1696 }
1697}
1698
initial.commit09911bf2008-07-26 23:55:291699void AutomationProvider::HandleInspectElementRequest(
1700 const IPC::Message& message, int handle, int x, int y) {
1701 if (!tab_tracker_->ContainsHandle(handle)) {
1702 Send(new AutomationMsg_InspectElementResponse(message.routing_id(), -1));
1703 return;
1704 }
1705
1706 NavigationController* nav = tab_tracker_->GetResource(handle);
1707 TabContents* tab_contents = nav->active_contents();
1708 if (tab_contents->type() == TAB_CONTENTS_WEB) {
1709 WebContents* web_contents = tab_contents->AsWebContents();
1710 web_contents->InspectElementAt(x, y);
1711 inspect_element_routing_id_ = message.routing_id();
1712 } else {
1713 Send(new AutomationMsg_InspectElementResponse(message.routing_id(), -1));
1714 }
1715}
1716
1717void AutomationProvider::ReceivedInspectElementResponse(int num_resources) {
1718 Send(new AutomationMsg_InspectElementResponse(inspect_element_routing_id_,
1719 num_resources));
1720}
1721
1722// Helper class for making changes to the URLRequest ProtocolFactory on the
1723// IO thread.
1724class SetFilteredInetTask : public Task {
1725 public:
1726 explicit SetFilteredInetTask(bool enabled) : enabled_(enabled) { }
1727 virtual void Run() {
1728 if (enabled_) {
1729 URLRequestFilter::GetInstance()->ClearHandlers();
1730
1731 URLRequestFailedDnsJob::AddUITestUrls();
1732 URLRequestSlowDownloadJob::AddUITestUrls();
1733
1734 std::wstring root_http;
1735 PathService::Get(chrome::DIR_TEST_DATA, &root_http);
1736 URLRequestMockHTTPJob::AddUITestUrls(root_http);
1737 } else {
1738 // Revert to the default handlers.
1739 URLRequestFilter::GetInstance()->ClearHandlers();
1740 }
1741 }
1742 private:
1743 bool enabled_;
1744};
1745
1746void AutomationProvider::SetFilteredInet(const IPC::Message& message,
1747 bool enabled) {
1748 // Since this involves changing the URLRequest ProtocolFactory, we want to
1749 // run on the main thread.
1750 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
1751 new SetFilteredInetTask(enabled));
1752}
1753
1754void AutomationProvider::GetDownloadDirectory(const IPC::Message& message,
1755 int handle) {
1756 DLOG(INFO) << "Handling download directory request";
1757 std::wstring download_directory;
1758 if (tab_tracker_->ContainsHandle(handle)) {
1759 NavigationController* tab = tab_tracker_->GetResource(handle);
1760 DownloadManager* dlm = tab->profile()->GetDownloadManager();
1761 DCHECK(dlm);
1762 download_directory = dlm->download_path();
1763 }
1764
1765 Send(new AutomationMsg_DownloadDirectoryResponse(message.routing_id(),
1766 download_directory));
1767}
1768
1769void AutomationProvider::OpenNewBrowserWindow(int show_command) {
1770 // We may have no current browser windows open so don't rely on
1771 // asking an existing browser to execute the IDC_NEWWINDOW command
1772 Browser::OpenNewBrowserWindow(profile_, show_command);
1773}
1774
1775void AutomationProvider::GetWindowForBrowser(const IPC::Message& message,
1776 int browser_handle) {
1777 bool success = false;
1778 int window_handle = 0;
1779
1780 if (browser_tracker_->ContainsHandle(browser_handle)) {
1781 Browser* browser = browser_tracker_->GetResource(browser_handle);
1782 HWND hwnd = browser->GetTopLevelHWND();
1783 // Add() returns the existing handle for the resource if any.
1784 window_handle = window_tracker_->Add(hwnd);
1785 success = true;
1786 }
1787 Send(new AutomationMsg_WindowForBrowserResponse(message.routing_id(),
1788 success, window_handle));
1789}
1790
1791void AutomationProvider::GetAutocompleteEditForBrowser(
1792 const IPC::Message& message,
1793 int browser_handle) {
1794 bool success = false;
1795 int autocomplete_edit_handle = 0;
1796
1797 if (browser_tracker_->ContainsHandle(browser_handle)) {
1798 Browser* browser = browser_tracker_->GetResource(browser_handle);
1799 LocationBarView* loc_bar_view = browser->GetLocationBarView();
1800 AutocompleteEdit* autocomplete_edit = loc_bar_view->location_entry();
1801 // Add() returns the existing handle for the resource if any.
1802 autocomplete_edit_handle =
1803 autocomplete_edit_tracker_->Add(autocomplete_edit);
1804 success = true;
1805 }
1806 Send(new AutomationMsg_AutocompleteEditForBrowserResponse(
1807 message.routing_id(), success, autocomplete_edit_handle));
1808}
1809
1810void AutomationProvider::GetBrowserForWindow(const IPC::Message& message,
1811 int window_handle) {
1812 bool success = false;
1813 int browser_handle = 0;
1814
1815 if (window_tracker_->ContainsHandle(window_handle)) {
1816 HWND window = window_tracker_->GetResource(window_handle);
1817 BrowserList::const_iterator iter = BrowserList::begin();
1818 Browser* browser = NULL;
1819 for (;iter != BrowserList::end(); ++iter) {
1820 if (window == (*iter)->GetTopLevelHWND()) {
1821 browser = *iter;
1822 break;
1823 }
1824 }
1825 if (browser) {
1826 // Add() returns the existing handle for the resource if any.
1827 browser_handle = browser_tracker_->Add(browser);
1828 success = true;
1829 }
1830 }
1831 Send(new AutomationMsg_BrowserForWindowResponse(message.routing_id(),
1832 success, browser_handle));
1833}
1834
1835void AutomationProvider::ShowInterstitialPage(const IPC::Message& message,
1836 int tab_handle,
1837 const std::string& html_text) {
1838 if (tab_tracker_->ContainsHandle(tab_handle)) {
1839 NavigationController* controller = tab_tracker_->GetResource(tab_handle);
1840 TabContents* tab_contents = controller->active_contents();
1841 if (tab_contents->type() == TAB_CONTENTS_WEB) {
1842 AddNavigationStatusListener(controller,
1843 new AutomationMsg_ShowInterstitialPageResponse(message.routing_id(),
1844 true),
1845 NULL);
1846 WebContents* web_contents = tab_contents->AsWebContents();
1847 web_contents->ShowInterstitialPage(html_text, NULL);
1848 return;
1849 }
1850 }
1851 Send(new AutomationMsg_ShowInterstitialPageResponse(message.routing_id(),
1852 false));
1853}
1854
1855void AutomationProvider::HideInterstitialPage(const IPC::Message& message,
1856 int tab_handle) {
1857 if (tab_tracker_->ContainsHandle(tab_handle)) {
1858 NavigationController* controller = tab_tracker_->GetResource(tab_handle);
1859 TabContents* tab_contents = controller->active_contents();
1860 if (tab_contents->type() == TAB_CONTENTS_WEB) {
1861 WebContents* web_contents = tab_contents->AsWebContents();
1862 web_contents->HideInterstitialPage(false, false);
1863 Send(new AutomationMsg_HideInterstitialPageResponse(message.routing_id(),
1864 true));
1865 return;
1866 }
1867 }
1868 Send(new AutomationMsg_HideInterstitialPageResponse(message.routing_id(),
1869 false));
1870}
1871
1872void AutomationProvider::CloseTab(const IPC::Message& message,
1873 int tab_handle,
1874 bool wait_until_closed) {
1875 if (tab_tracker_->ContainsHandle(tab_handle)) {
1876 NavigationController* controller = tab_tracker_->GetResource(tab_handle);
1877 int index;
1878 Browser* browser = Browser::GetBrowserForController(controller, &index);
1879 DCHECK(browser);
1880 TabClosedNotificationObserver* observer =
1881 new TabClosedNotificationObserver(browser, this, message.routing_id(),
1882 wait_until_closed);
1883 browser->CloseContents(controller->active_contents());
1884 } else {
1885 Send(new AutomationMsg_CloseTabResponse(message.routing_id(), false));
1886 }
1887}
1888
1889void AutomationProvider::CloseBrowser(const IPC::Message& message,
1890 int browser_handle) {
1891 if (browser_tracker_->ContainsHandle(browser_handle)) {
1892 Browser* browser = browser_tracker_->GetResource(browser_handle);
1893 new BrowserClosedNotificationObserver(browser, this, message.routing_id());
[email protected]f3e99e32008-07-30 04:48:391894 browser->window()->Close();
initial.commit09911bf2008-07-26 23:55:291895 } else {
1896 NOTREACHED();
1897 }
1898}
1899
1900void AutomationProvider::CreateExternalTab(const IPC::Message& message) {
1901 int tab_handle = 0;
1902 HWND tab_container_window = NULL;
1903 ExternalTabContainer *external_tab_container =
1904 new ExternalTabContainer(this);
1905 external_tab_container->Init(profile_);
1906 TabContents* tab_contents = external_tab_container->tab_contents();
1907 if (tab_contents) {
1908 tab_handle = tab_tracker_->Add(tab_contents->controller());
1909 tab_container_window = *external_tab_container;
1910 }
1911 Send(new AutomationMsg_CreateExternalTabResponse(message.routing_id(),
1912 tab_container_window,
1913 tab_handle));
1914}
1915
1916void AutomationProvider::NavigateInExternalTab(const IPC::Message& message,
1917 int handle, const GURL& url) {
1918 bool status = false;
1919
1920 if (tab_tracker_->ContainsHandle(handle)) {
1921 NavigationController* tab = tab_tracker_->GetResource(handle);
1922 tab->LoadURL(url, PageTransition::TYPED);
1923 status = true;
1924 }
1925
1926 Send(new AutomationMsg_NavigateInExternalTabResponse(message.routing_id(),
1927 status));
1928}
1929
1930void AutomationProvider::SetAcceleratorsForTab(const IPC::Message& message,
1931 int handle,
1932 HACCEL accel_table,
1933 int accel_entry_count) {
1934 bool status = false;
1935 if (tab_tracker_->ContainsHandle(handle)) {
1936 NavigationController* tab = tab_tracker_->GetResource(handle);
1937 TabContents* tab_contents = tab->GetTabContents(TAB_CONTENTS_WEB);
1938 ExternalTabContainer* external_tab_container =
1939 ExternalTabContainer::GetContainerForTab(
1940 tab_contents->GetContainerHWND());
1941 // This call is only valid on an externally hosted tab
1942 if (external_tab_container) {
1943 external_tab_container->SetAccelerators(accel_table,
1944 accel_entry_count);
1945 status = true;
1946 }
1947 }
1948 Send(new AutomationMsg_SetAcceleratorsForTabResponse(message.routing_id(),
1949 status));
1950}
1951
1952void AutomationProvider::ProcessUnhandledAccelerator(
1953 const IPC::Message& message, int handle, const MSG& msg) {
1954 if (tab_tracker_->ContainsHandle(handle)) {
1955 NavigationController* tab = tab_tracker_->GetResource(handle);
1956 TabContents* tab_contents = tab->GetTabContents(TAB_CONTENTS_WEB);
1957 ExternalTabContainer* external_tab_container =
1958 ExternalTabContainer::GetContainerForTab(
1959 tab_contents->GetContainerHWND());
1960 // This call is only valid on an externally hosted tab
1961 if (external_tab_container) {
1962 external_tab_container->ProcessUnhandledAccelerator(msg);
1963 }
1964 }
1965 // This message expects no response.
1966}
1967
1968void AutomationProvider::WaitForTabToBeRestored(
1969 const IPC::Message& message,
1970 int tab_handle) {
1971 if (tab_tracker_->ContainsHandle(tab_handle)) {
1972 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
1973 restore_tracker_.reset(
1974 new NavigationControllerRestoredObserver(this, tab,
1975 message.routing_id()));
1976 }
1977}
1978
1979void AutomationProvider::GetSecurityState(const IPC::Message& message,
1980 int handle) {
1981 if (tab_tracker_->ContainsHandle(handle)) {
1982 NavigationController* tab = tab_tracker_->GetResource(handle);
1983 NavigationEntry* entry = tab->GetActiveEntry();
1984 Send(new AutomationMsg_GetSecurityStateResponse(message.routing_id(), true,
[email protected]eb34392b2008-08-19 15:42:201985 entry->ssl().security_style(), entry->ssl().cert_status(),
1986 entry->ssl().content_status()));
initial.commit09911bf2008-07-26 23:55:291987 } else {
1988 Send(new AutomationMsg_GetSecurityStateResponse(message.routing_id(), false,
1989 SECURITY_STYLE_UNKNOWN,
1990 0, 0));
1991 }
1992}
1993
1994void AutomationProvider::GetPageType(const IPC::Message& message, int handle) {
1995 if (tab_tracker_->ContainsHandle(handle)) {
1996 NavigationController* tab = tab_tracker_->GetResource(handle);
1997 NavigationEntry* entry = tab->GetActiveEntry();
1998 NavigationEntry::PageType page_type = entry->GetPageType();
1999 // In order to return the proper result when an interstitial is shown and
2000 // no navigation entry were created for it we need to ask the WebContents.
2001 if (page_type == NavigationEntry::NORMAL_PAGE &&
2002 tab->active_contents()->AsWebContents() &&
[email protected]b6e09ac2008-08-12 16:11:092003 tab->active_contents()->AsWebContents()->showing_interstitial_page())
initial.commit09911bf2008-07-26 23:55:292004 page_type = NavigationEntry::INTERSTITIAL_PAGE;
2005
2006 Send(new AutomationMsg_GetPageTypeResponse(message.routing_id(), true,
2007 page_type));
2008 } else {
2009 Send(new AutomationMsg_GetPageTypeResponse(message.routing_id(), false,
2010 NavigationEntry::NORMAL_PAGE));
2011 }
2012}
2013
2014void AutomationProvider::ActionOnSSLBlockingPage(const IPC::Message& message,
2015 int handle, bool proceed) {
2016 if (tab_tracker_->ContainsHandle(handle)) {
2017 NavigationController* tab = tab_tracker_->GetResource(handle);
2018 NavigationEntry* entry = tab->GetActiveEntry();
2019 if (entry->GetPageType() == NavigationEntry::INTERSTITIAL_PAGE) {
2020 TabContents* tab_contents = tab->GetTabContents(TAB_CONTENTS_WEB);
2021 SSLBlockingPage* ssl_blocking_page =
2022 SSLBlockingPage::GetSSLBlockingPage(tab_contents);
2023 if (ssl_blocking_page) {
2024 if (proceed) {
2025 AddNavigationStatusListener(tab,
2026 new AutomationMsg_ActionOnSSLBlockingPageResponse(
2027 message.routing_id(), true),
2028 new AutomationMsg_ActionOnSSLBlockingPageResponse(
2029 message.routing_id(), true));
2030 ssl_blocking_page->Proceed();
2031 return;
2032 }
2033 ssl_blocking_page->DontProceed();
2034 Send(new AutomationMsg_ActionOnSSLBlockingPageResponse(
2035 message.routing_id(), true));
2036 return;
2037 }
2038 }
2039 }
2040 // We failed.
2041 Send(new AutomationMsg_ActionOnSSLBlockingPageResponse(message.routing_id(),
2042 false));
2043}
2044
2045void AutomationProvider::BringBrowserToFront(const IPC::Message& message,
2046 int browser_handle) {
2047 if (browser_tracker_->ContainsHandle(browser_handle)) {
2048 Browser* browser = browser_tracker_->GetResource(browser_handle);
2049 browser->MoveToFront(true);
2050 Send(new AutomationMsg_BringBrowserToFrontResponse(message.routing_id(),
2051 true));
2052 } else {
2053 Send(new AutomationMsg_BringBrowserToFrontResponse(message.routing_id(),
2054 false));
2055 }
2056}
2057
2058void AutomationProvider::IsPageMenuCommandEnabled(const IPC::Message& message,
2059 int browser_handle,
2060 int message_num) {
2061 if (browser_tracker_->ContainsHandle(browser_handle)) {
2062 Browser* browser = browser_tracker_->GetResource(browser_handle);
2063 bool menu_item_enabled =
2064 browser->controller()->IsCommandEnabled(message_num);
2065 Send(new AutomationMsg_IsPageMenuCommandEnabledResponse(
2066 message.routing_id(), menu_item_enabled));
2067 } else {
2068 Send(new AutomationMsg_IsPageMenuCommandEnabledResponse(
2069 message.routing_id(), false));
2070 }
2071}
2072
2073void AutomationProvider::PrintNow(const IPC::Message& message, int tab_handle) {
2074 if (tab_tracker_->ContainsHandle(tab_handle)) {
2075 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
2076 FindAndActivateTab(tab);
2077 WebContents* const web_contents = tab->active_contents()->AsWebContents();
2078 if (web_contents) {
2079 notification_observer_list_.AddObserver(
2080 new DocumentPrintedNotificationObserver(this, message.routing_id()));
2081 if (web_contents->PrintNow())
2082 return;
2083 }
2084 }
2085 Send(new AutomationMsg_PrintNowResponse(message.routing_id(), false));
2086}
2087
2088void AutomationProvider::SavePage(const IPC::Message& message,
2089 int tab_handle,
2090 const std::wstring& file_name,
2091 const std::wstring& dir_path,
2092 int type) {
2093 if (!tab_tracker_->ContainsHandle(tab_handle)) {
2094 Send(new AutomationMsg_SavePageResponse(message.routing_id(), false));
2095 return;
2096 }
2097
2098 NavigationController* nav = tab_tracker_->GetResource(tab_handle);
2099 Browser* browser = FindAndActivateTab(nav);
2100 DCHECK(browser);
2101 if (!browser->IsCommandEnabled(IDC_SAVEPAGE)) {
2102 Send(new AutomationMsg_SavePageResponse(message.routing_id(), false));
2103 return;
2104 }
2105
2106 TabContents* tab_contents = nav->active_contents();
2107 if (tab_contents->type() != TAB_CONTENTS_WEB) {
2108 Send(new AutomationMsg_SavePageResponse(message.routing_id(), false));
2109 return;
2110 }
2111
2112 SavePackage::SavePackageType save_type =
2113 static_cast<SavePackage::SavePackageType>(type);
2114 DCHECK(save_type >= SavePackage::SAVE_AS_ONLY_HTML &&
2115 save_type <= SavePackage::SAVE_AS_COMPLETE_HTML);
2116 tab_contents->AsWebContents()->SavePage(file_name, dir_path, save_type);
2117
2118 Send(new AutomationMsg_SavePageResponse(
2119 message.routing_id(), true));
2120}
2121
2122void AutomationProvider::GetAutocompleteEditText(const IPC::Message& message,
2123 int autocomplete_edit_handle) {
2124 bool success = false;
2125 std::wstring text;
2126 if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
2127 AutocompleteEdit* edit = autocomplete_edit_tracker_->GetResource(
2128 autocomplete_edit_handle);
2129 text = edit->GetText();
2130 success = true;
2131 }
2132 Send(new AutomationMsg_AutocompleteEditGetTextResponse(message.routing_id(),
2133 success, text));
2134}
2135
2136void AutomationProvider::SetAutocompleteEditText(const IPC::Message& message,
2137 int autocomplete_edit_handle,
2138 const std::wstring& text) {
2139 bool success = false;
2140 if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
2141 AutocompleteEdit* edit = autocomplete_edit_tracker_->GetResource(
2142 autocomplete_edit_handle);
2143 edit->SetUserText(text);
2144 success = true;
2145 }
2146 Send(new AutomationMsg_AutocompleteEditSetTextResponse(
2147 message.routing_id(), success));
2148}
2149
2150void AutomationProvider::AutocompleteEditGetMatches(
2151 const IPC::Message& message,
2152 int autocomplete_edit_handle) {
2153 bool success = false;
2154 std::vector<AutocompleteMatchData> matches;
2155 if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
2156 AutocompleteEdit* edit =
2157 autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle);
2158 const AutocompleteResult* result = edit->latest_result();
2159 for (AutocompleteResult::const_iterator i = result->begin();
2160 i != result->end(); ++i)
2161 matches.push_back(AutocompleteMatchData(*i));
2162 success = true;
2163 }
2164 Send(new AutomationMsg_AutocompleteEditGetMatchesResponse(
2165 message.routing_id(), success, matches));
2166}
2167
2168void AutomationProvider::AutocompleteEditIsQueryInProgress(
2169 const IPC::Message& message,
2170 int autocomplete_edit_handle) {
2171 bool success = false;
2172 bool query_in_progress = false;
2173 if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
2174 AutocompleteEdit* edit =
2175 autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle);
2176 query_in_progress = edit->query_in_progress();
2177 success = true;
2178 }
2179 Send(new AutomationMsg_AutocompleteEditIsQueryInProgressResponse(
2180 message.routing_id(), success, query_in_progress));
2181}
2182
[email protected]18cb2572008-08-21 20:34:452183void AutomationProvider::OnMessageFromExternalHost(
2184 int handle, const std::string& target, const std::string& message) {
[email protected]fa83e762008-08-15 21:41:392185 if (tab_tracker_->ContainsHandle(handle)) {
2186 NavigationController* tab = tab_tracker_->GetResource(handle);
2187 if (!tab) {
2188 NOTREACHED();
2189 return;
2190 }
2191 TabContents* tab_contents = tab->GetTabContents(TAB_CONTENTS_WEB);
2192 if (!tab_contents) {
2193 NOTREACHED();
2194 return;
2195 }
2196
2197 WebContents* web_contents = tab_contents->AsWebContents();
2198 if (!web_contents) {
2199 NOTREACHED();
2200 return;
2201 }
2202
2203 RenderViewHost* view_host = web_contents->render_view_host();
2204 if (!view_host) {
2205 return;
2206 }
2207
[email protected]18cb2572008-08-21 20:34:452208 view_host->ForwardMessageFromExternalHost(target, message);
[email protected]fa83e762008-08-15 21:41:392209 }
2210}
2211
initial.commit09911bf2008-07-26 23:55:292212TestingAutomationProvider::TestingAutomationProvider(Profile* profile)
2213 : AutomationProvider(profile) {
2214 BrowserList::AddObserver(this);
2215 NotificationService::current()->AddObserver(this, NOTIFY_SESSION_END,
2216 NotificationService::AllSources());
2217}
2218
2219TestingAutomationProvider::~TestingAutomationProvider() {
2220 NotificationService::current()->RemoveObserver(this, NOTIFY_SESSION_END,
2221 NotificationService::AllSources());
2222 BrowserList::RemoveObserver(this);
2223}
2224
2225void TestingAutomationProvider::OnChannelError() {
2226 BrowserList::CloseAllBrowsers(true);
2227 AutomationProvider::OnChannelError();
2228}
2229
2230void TestingAutomationProvider::OnBrowserRemoving(const Browser* browser) {
2231 // For backwards compatibility with the testing automation interface, we
2232 // want the automation provider (and hence the process) to go away when the
2233 // last browser goes away.
2234 if (BrowserList::size() == 1) {
2235 // If you change this, update Observer for NOTIFY_SESSION_END below.
[email protected]295039bd2008-08-15 04:32:572236 MessageLoop::current()->PostTask(FROM_HERE,
2237 NewRunnableMethod(this, &TestingAutomationProvider::OnRemoveProvider));
initial.commit09911bf2008-07-26 23:55:292238 }
2239}
2240
2241void TestingAutomationProvider::Observe(NotificationType type,
2242 const NotificationSource& source,
2243 const NotificationDetails& details) {
2244 DCHECK(type == NOTIFY_SESSION_END);
2245 // OnBrowserRemoving does a ReleaseLater. When session end is received we exit
2246 // before the task runs resulting in this object not being deleted. This
2247 // Release balance out the Release scheduled by OnBrowserRemoving.
2248 Release();
2249}
[email protected]295039bd2008-08-15 04:32:572250
2251void TestingAutomationProvider::OnRemoveProvider() {
2252 AutomationProviderList::GetInstance()->RemoveProvider(this);
2253}
license.botbf09a502008-08-24 00:55:552254