blob: aaf7978a74816707777b85d3f0f5cd48d4256818 [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]9e0534b2008-10-21 15:03:018#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"
[email protected]cdaa8652008-09-13 02:48:5916#include "chrome/browser/download/download_manager.h"
[email protected]37936ee2008-09-14 01:09:5017#include "chrome/browser/download/save_package.h"
initial.commit09911bf2008-07-26 23:55:2918#include "chrome/browser/external_tab_container.h"
19#include "chrome/browser/find_notification_details.h"
20#include "chrome/browser/login_prompt.h"
21#include "chrome/browser/navigation_entry.h"
22#include "chrome/browser/printing/print_job.h"
[email protected]fa83e762008-08-15 21:41:3923#include "chrome/browser/render_view_host.h"
[email protected]8a3422c92008-09-24 17:42:4224#include "chrome/browser/ssl_manager.h"
initial.commit09911bf2008-07-26 23:55:2925#include "chrome/browser/ssl_blocking_page.h"
[email protected]1eb89e82008-08-15 12:27:0326#include "chrome/browser/web_contents.h"
[email protected]9e0534b2008-10-21 15:03:0127#include "chrome/browser/web_contents_view.h"
[email protected]c2cbeb92008-09-05 21:36:5728#include "chrome/browser/views/bookmark_bar_view.h"
[email protected]195442e2008-07-31 22:41:2829#include "chrome/browser/views/location_bar_view.h"
initial.commit09911bf2008-07-26 23:55:2930#include "chrome/common/chrome_paths.h"
[email protected]8a3422c92008-09-24 17:42:4231#include "chrome/common/pref_service.h"
initial.commit09911bf2008-07-26 23:55:2932#include "chrome/test/automation/automation_messages.h"
33#include "net/base/cookie_monster.h"
34#include "net/url_request/url_request_filter.h"
35
[email protected]e1acf6f2008-10-27 20:43:3336using base::Time;
37
initial.commit09911bf2008-07-26 23:55:2938class InitialLoadObserver : public NotificationObserver {
39 public:
40 InitialLoadObserver(size_t tab_count, AutomationProvider* automation)
41 : outstanding_tab_count_(tab_count),
42 automation_(automation) {
43 if (outstanding_tab_count_ > 0) {
44 NotificationService* service = NotificationService::current();
45 service->AddObserver(this, NOTIFY_LOAD_START,
46 NotificationService::AllSources());
47 service->AddObserver(this, NOTIFY_LOAD_STOP,
48 NotificationService::AllSources());
49 }
50 }
51
52 ~InitialLoadObserver() {
53 Unregister();
54 }
55
56 void ConditionMet() {
57 Unregister();
58 automation_->Send(new AutomationMsg_InitialLoadsComplete(0));
59 }
60
61 void Unregister() {
62 NotificationService* service = NotificationService::current();
63 service->RemoveObserver(this, NOTIFY_LOAD_START,
64 NotificationService::AllSources());
65 service->RemoveObserver(this, NOTIFY_LOAD_STOP,
66 NotificationService::AllSources());
67 }
68
69 virtual void Observe(NotificationType type,
70 const NotificationSource& source,
71 const NotificationDetails& details) {
72 if (type == NOTIFY_LOAD_START) {
73 if (outstanding_tab_count_ > loading_tabs_.size())
74 loading_tabs_.insert(source.map_key());
75 } else if (type == NOTIFY_LOAD_STOP) {
76 if (outstanding_tab_count_ > finished_tabs_.size()) {
77 if (loading_tabs_.find(source.map_key()) != loading_tabs_.end())
78 finished_tabs_.insert(source.map_key());
79 if (outstanding_tab_count_ == finished_tabs_.size())
80 ConditionMet();
81 }
82 } else {
83 NOTREACHED();
84 }
85 }
86
87 private:
88 typedef std::set<uintptr_t> TabSet;
89
90 AutomationProvider* automation_;
91 size_t outstanding_tab_count_;
92 TabSet loading_tabs_;
93 TabSet finished_tabs_;
94};
95
96// Watches for NewTabUI page loads for performance timing purposes.
97class NewTabUILoadObserver : public NotificationObserver {
98 public:
99 explicit NewTabUILoadObserver(AutomationProvider* automation)
100 : automation_(automation) {
101 NotificationService::current()->
102 AddObserver(this, NOTIFY_INITIAL_NEW_TAB_UI_LOAD,
103 NotificationService::AllSources());
104 }
105
106 ~NewTabUILoadObserver() {
107 Unregister();
108 }
109
110 void Unregister() {
111 NotificationService::current()->
112 RemoveObserver(this, NOTIFY_INITIAL_NEW_TAB_UI_LOAD,
113 NotificationService::AllSources());
114 }
115
116 virtual void Observe(NotificationType type,
117 const NotificationSource& source,
118 const NotificationDetails& details) {
119 if (type == NOTIFY_INITIAL_NEW_TAB_UI_LOAD) {
120 Details<int> load_time(details);
121 automation_->Send(
122 new AutomationMsg_InitialNewTabUILoadComplete(0, *load_time.ptr()));
123 } else {
124 NOTREACHED();
125 }
126 }
127
128 private:
129 AutomationProvider* automation_;
130};
131
132class NavigationControllerRestoredObserver : public NotificationObserver {
133 public:
134 NavigationControllerRestoredObserver(AutomationProvider* automation,
135 NavigationController* controller,
136 int32 routing_id)
137 : automation_(automation),
138 controller_(controller),
139 routing_id_(routing_id) {
140 if (FinishedRestoring()) {
141 registered_ = false;
142 SendDone();
143 } else {
144 registered_ = true;
145 NotificationService* service = NotificationService::current();
146 service->AddObserver(this, NOTIFY_LOAD_STOP,
147 NotificationService::AllSources());
148 }
149 }
150
151 ~NavigationControllerRestoredObserver() {
152 if (registered_)
153 Unregister();
154 }
155
156 virtual void Observe(NotificationType type,
157 const NotificationSource& source,
158 const NotificationDetails& details) {
159 if (FinishedRestoring()) {
160 SendDone();
161 Unregister();
162 }
163 }
164
165 private:
166 void Unregister() {
167 NotificationService* service = NotificationService::current();
168 service->RemoveObserver(this, NOTIFY_LOAD_STOP,
169 NotificationService::AllSources());
170 registered_ = false;
171 }
172
173 bool FinishedRestoring() {
174 return (!controller_->needs_reload() && !controller_->GetPendingEntry() &&
[email protected]d5f942ba2008-09-26 19:30:34175 !controller_->active_contents()->is_loading());
initial.commit09911bf2008-07-26 23:55:29176 }
177
178 void SendDone() {
179 automation_->Send(new AutomationMsg_TabFinishedRestoring(routing_id_));
180 }
181
182 bool registered_;
183 AutomationProvider* automation_;
184 NavigationController* controller_;
185 const int routing_id_;
186
[email protected]5a52f162008-08-27 04:15:31187 DISALLOW_COPY_AND_ASSIGN(NavigationControllerRestoredObserver);
initial.commit09911bf2008-07-26 23:55:29188};
189
initial.commit09911bf2008-07-26 23:55:29190class NavigationNotificationObserver : public NotificationObserver {
191 public:
192 NavigationNotificationObserver(NavigationController* controller,
193 AutomationProvider* automation,
194 IPC::Message* completed_response,
195 IPC::Message* auth_needed_response)
196 : automation_(automation),
197 completed_response_(completed_response),
198 auth_needed_response_(auth_needed_response),
199 controller_(controller),
200 navigation_started_(false) {
201 NotificationService* service = NotificationService::current();
[email protected]8a3422c92008-09-24 17:42:42202 service->AddObserver(this, NOTIFY_NAV_ENTRY_COMMITTED,
203 Source<NavigationController>(controller_));
initial.commit09911bf2008-07-26 23:55:29204 service->AddObserver(this, NOTIFY_LOAD_START,
205 Source<NavigationController>(controller_));
206 service->AddObserver(this, NOTIFY_LOAD_STOP,
207 Source<NavigationController>(controller_));
208 service->AddObserver(this, NOTIFY_AUTH_NEEDED,
209 Source<NavigationController>(controller_));
210 service->AddObserver(this, NOTIFY_AUTH_SUPPLIED,
211 Source<NavigationController>(controller_));
212 }
213
214 ~NavigationNotificationObserver() {
215 if (completed_response_) delete completed_response_;
216 if (auth_needed_response_) delete auth_needed_response_;
217 Unregister();
218 }
219
220 void ConditionMet(IPC::Message** response) {
221 if (*response) {
222 automation_->Send(*response);
223 *response = NULL; // *response is deleted by Send.
224 }
[email protected]d5798082008-09-29 21:02:03225 automation_->RemoveNavigationStatusListener(this);
initial.commit09911bf2008-07-26 23:55:29226 delete this;
227 }
228
229 void Unregister() {
230 NotificationService* service = NotificationService::current();
[email protected]8a3422c92008-09-24 17:42:42231 service->RemoveObserver(this, NOTIFY_NAV_ENTRY_COMMITTED,
232 Source<NavigationController>(controller_));
initial.commit09911bf2008-07-26 23:55:29233 service->RemoveObserver(this, NOTIFY_LOAD_START,
234 Source<NavigationController>(controller_));
235 service->RemoveObserver(this, NOTIFY_LOAD_STOP,
236 Source<NavigationController>(controller_));
237 service->RemoveObserver(this, NOTIFY_AUTH_NEEDED,
238 Source<NavigationController>(controller_));
239 service->RemoveObserver(this, NOTIFY_AUTH_SUPPLIED,
240 Source<NavigationController>(controller_));
241 }
242
243 virtual void Observe(NotificationType type,
244 const NotificationSource& source,
245 const NotificationDetails& details) {
[email protected]8a3422c92008-09-24 17:42:42246 // We listen for 2 events to determine when the navigation started because:
247 // - when this is used by the WaitForNavigation method, we might be invoked
248 // afer the load has started (but not after the entry was committed, as
249 // WaitForNavigation compares times of the last navigation).
250 // - when this is used with a page requiring authentication, we will not get
251 // a NOTIFY_NAV_ENTRY_COMMITTED until after we authenticate, so we need the
252 // NOTIFY_LOAD_START.
253 if (type == NOTIFY_NAV_ENTRY_COMMITTED || type == NOTIFY_LOAD_START) {
initial.commit09911bf2008-07-26 23:55:29254 navigation_started_ = true;
255 } else if (type == NOTIFY_LOAD_STOP) {
256 if (navigation_started_) {
257 navigation_started_ = false;
258 ConditionMet(&completed_response_);
259 }
260 } else if (type == NOTIFY_AUTH_SUPPLIED) {
261 // The LoginHandler for this tab is no longer valid.
262 automation_->RemoveLoginHandler(controller_);
263
264 // Treat this as if navigation started again, since load start/stop don't
265 // occur while authentication is ongoing.
266 navigation_started_ = true;
267 } else if (type == NOTIFY_AUTH_NEEDED) {
268 if (navigation_started_) {
269 // Remember the login handler that wants authentication.
270 LoginHandler* handler =
271 Details<LoginNotificationDetails>(details)->handler();
272 automation_->AddLoginHandler(controller_, handler);
273
274 // Respond that authentication is needed.
275 navigation_started_ = false;
276 ConditionMet(&auth_needed_response_);
277 } else {
278 NOTREACHED();
279 }
280 } else {
281 NOTREACHED();
282 }
283 }
284
285 private:
286 AutomationProvider* automation_;
287 IPC::Message* completed_response_;
288 IPC::Message* auth_needed_response_;
289 NavigationController* controller_;
290 bool navigation_started_;
291};
292
293class TabStripNotificationObserver : public NotificationObserver {
294 public:
295 TabStripNotificationObserver(Browser* parent, NotificationType notification,
296 AutomationProvider* automation, int32 routing_id)
297 : automation_(automation),
298 notification_(notification),
299 parent_(parent),
300 routing_id_(routing_id) {
301 NotificationService::current()->
302 AddObserver(this, notification_, NotificationService::AllSources());
303 }
304
305 virtual ~TabStripNotificationObserver() {
306 Unregister();
307 }
308
309 void Unregister() {
310 NotificationService::current()->
311 RemoveObserver(this, notification_, NotificationService::AllSources());
312 }
313
314 virtual void Observe(NotificationType type,
315 const NotificationSource& source,
316 const NotificationDetails& details) {
317 if (type == notification_) {
318 ObserveTab(Source<NavigationController>(source).ptr());
319
320 // If verified, no need to observe anymore
321 automation_->RemoveTabStripObserver(this);
322 delete this;
323 } else {
324 NOTREACHED();
325 }
326 }
327
328 virtual void ObserveTab(NavigationController* controller) = 0;
329
330 protected:
331 AutomationProvider* automation_;
332 Browser* parent_;
333 NotificationType notification_;
334 int32 routing_id_;
335};
336
337class TabAppendedNotificationObserver : public TabStripNotificationObserver {
338 public:
339 TabAppendedNotificationObserver(Browser* parent,
340 AutomationProvider* automation, int32 routing_id)
[email protected]534e54b2008-08-13 15:40:09341 : TabStripNotificationObserver(parent, NOTIFY_TAB_PARENTED, automation,
initial.commit09911bf2008-07-26 23:55:29342 routing_id) {
343 }
344
345 virtual void ObserveTab(NavigationController* controller) {
346 int tab_index =
347 automation_->GetIndexForNavigationController(controller, parent_);
348 if (tab_index == TabStripModel::kNoTab) {
349 // This tab notification doesn't belong to the parent_
350 return;
351 }
352
353 // Give the same response even if auth is needed, since it doesn't matter.
354 automation_->AddNavigationStatusListener(controller,
355 new AutomationMsg_AppendTabResponse(routing_id_, tab_index),
356 new AutomationMsg_AppendTabResponse(routing_id_, tab_index));
357 }
358};
359
360class TabClosedNotificationObserver : public TabStripNotificationObserver {
361 public:
362 TabClosedNotificationObserver(Browser* parent,
363 AutomationProvider* automation,
364 int32 routing_id,
365 bool wait_until_closed)
366 : TabStripNotificationObserver(parent,
367 wait_until_closed ? NOTIFY_TAB_CLOSED :
368 NOTIFY_TAB_CLOSING,
369 automation,
370 routing_id) {
371 }
372
373 virtual void ObserveTab(NavigationController* controller) {
374 automation_->Send(new AutomationMsg_CloseTabResponse(routing_id_, true));
375 }
376};
377
378class BrowserClosedNotificationObserver : public NotificationObserver {
379 public:
380 BrowserClosedNotificationObserver(Browser* browser,
381 AutomationProvider* automation,
382 int32 routing_id)
383 : automation_(automation),
384 routing_id_(routing_id) {
385 NotificationService::current()->
386 AddObserver(this, NOTIFY_BROWSER_CLOSED, Source<Browser>(browser));
387 }
388
389 virtual void Observe(NotificationType type,
390 const NotificationSource& source,
391 const NotificationDetails& details) {
392 DCHECK(type == NOTIFY_BROWSER_CLOSED);
393 Details<bool> close_app(details);
394 automation_->Send(
395 new AutomationMsg_CloseBrowserResponse(routing_id_,
396 true,
397 *(close_app.ptr())));
398 delete this;
399 }
400
401 private:
402 AutomationProvider* automation_;
403 int32 routing_id_;
404};
405
406class FindInPageNotificationObserver : public NotificationObserver {
407 public:
408 FindInPageNotificationObserver(AutomationProvider* automation,
409 TabContents* parent_tab,
410 int32 routing_id)
411 : automation_(automation),
412 parent_tab_(parent_tab),
413 routing_id_(routing_id) {
414 NotificationService::current()->
415 AddObserver(this, NOTIFY_FIND_RESULT_AVAILABLE,
416 Source<TabContents>(parent_tab_));
417 }
418
419 ~FindInPageNotificationObserver() {
420 Unregister();
421 }
422
423 void Unregister() {
424 NotificationService::current()->
425 RemoveObserver(this, NOTIFY_FIND_RESULT_AVAILABLE,
426 Source<TabContents>(parent_tab_));
427 }
428
429 virtual void Observe(NotificationType type, const NotificationSource& source,
430 const NotificationDetails& details) {
431 if (type == NOTIFY_FIND_RESULT_AVAILABLE) {
432 Details<FindNotificationDetails> find_details(details);
433 if (find_details->request_id() == kFindInPageRequestId) {
434 if (find_details->final_update()) {
435 automation_->Send(new AutomationMsg_FindInPageResponse(routing_id_,
436 find_details->number_of_matches()));
437 } else {
438 DLOG(INFO) << "Ignoring, since we only care about the final message";
439 }
440 }
441 } else {
442 NOTREACHED();
443 }
444 }
445
446 // The Find mechanism is over asynchronous IPC, so a search is kicked off and
447 // we wait for notification to find out what the results are. As the user is
448 // typing, new search requests can be issued and the Request ID helps us make
449 // sense of whether this is the current request or an old one. The unit tests,
450 // however, which uses this constant issues only one search at a time, so we
451 // don't need a rolling id to identify each search. But, we still need to
452 // specify one, so we just use a fixed one - its value does not matter.
453 static const int kFindInPageRequestId;
454 private:
455 AutomationProvider* automation_;
456 TabContents* parent_tab_;
457 int32 routing_id_;
458};
459
460const int FindInPageNotificationObserver::kFindInPageRequestId = -1;
461
462class DomOperationNotificationObserver : public NotificationObserver {
463 public:
464 explicit DomOperationNotificationObserver(AutomationProvider* automation)
465 : automation_(automation) {
466 NotificationService::current()->
467 AddObserver(this, NOTIFY_DOM_OPERATION_RESPONSE,
468 NotificationService::AllSources());
469 }
470
471 ~DomOperationNotificationObserver() {
472 NotificationService::current()->
473 RemoveObserver(this, NOTIFY_DOM_OPERATION_RESPONSE,
474 NotificationService::AllSources());
475 }
476
477 virtual void Observe(NotificationType type, const NotificationSource& source,
478 const NotificationDetails& details) {
479 if (NOTIFY_DOM_OPERATION_RESPONSE == type) {
480 Details<DomOperationNotificationDetails> dom_op_details(details);
481 automation_->Send(new AutomationMsg_DomOperationResponse(
482 dom_op_details->automation_id(),
483 dom_op_details->json()));
484 }
485 }
486 private:
487 AutomationProvider* automation_;
488};
489
490class DomInspectorNotificationObserver : public NotificationObserver {
491 public:
492 explicit DomInspectorNotificationObserver(AutomationProvider* automation)
493 : automation_(automation) {
494 NotificationService::current()->
495 AddObserver(this, NOTIFY_DOM_INSPECT_ELEMENT_RESPONSE,
496 NotificationService::AllSources());
497 }
498
499 ~DomInspectorNotificationObserver() {
500 NotificationService::current()->
501 RemoveObserver(this, NOTIFY_DOM_INSPECT_ELEMENT_RESPONSE,
502 NotificationService::AllSources());
503 }
504
505 virtual void Observe(NotificationType type, const NotificationSource& source,
506 const NotificationDetails& details) {
507 if (NOTIFY_DOM_INSPECT_ELEMENT_RESPONSE == type) {
508 Details<int> dom_inspect_details(details);
509 automation_->ReceivedInspectElementResponse(*(dom_inspect_details.ptr()));
510 }
511 }
512
513 private:
514 AutomationProvider* automation_;
515};
516
517class DocumentPrintedNotificationObserver : public NotificationObserver {
518 public:
519 DocumentPrintedNotificationObserver(AutomationProvider* automation,
520 int32 routing_id)
521 : automation_(automation),
522 routing_id_(routing_id),
523 success_(false) {
524 NotificationService::current()->
525 AddObserver(this, NOTIFY_PRINT_JOB_EVENT,
526 NotificationService::AllSources());
527 }
528
529 ~DocumentPrintedNotificationObserver() {
530 automation_->Send(
531 new AutomationMsg_PrintNowResponse(routing_id_, success_));
532 automation_->RemoveNavigationStatusListener(this);
533 NotificationService::current()->
534 RemoveObserver(this, NOTIFY_PRINT_JOB_EVENT,
535 NotificationService::AllSources());
536 }
537
538 virtual void Observe(NotificationType type, const NotificationSource& source,
539 const NotificationDetails& details) {
540 using namespace printing;
541 DCHECK(type == NOTIFY_PRINT_JOB_EVENT);
542 switch (Details<JobEventDetails>(details)->type()) {
543 case JobEventDetails::JOB_DONE: {
544 // Succeeded.
545 success_ = true;
546 delete this;
547 break;
548 }
549 case JobEventDetails::USER_INIT_CANCELED:
550 case JobEventDetails::FAILED: {
551 // Failed.
552 delete this;
553 break;
554 }
555 case JobEventDetails::NEW_DOC:
556 case JobEventDetails::USER_INIT_DONE:
557 case JobEventDetails::DEFAULT_INIT_DONE:
558 case JobEventDetails::NEW_PAGE:
559 case JobEventDetails::PAGE_DONE:
560 case JobEventDetails::DOC_DONE:
561 case JobEventDetails::ALL_PAGES_REQUESTED: {
562 // Don't care.
563 break;
564 }
565 default: {
566 NOTREACHED();
567 break;
568 }
569 }
570 }
571
572 private:
573 scoped_refptr<AutomationProvider> automation_;
574 int32 routing_id_;
575 bool success_;
576};
577
[email protected]cbab76d2008-10-13 22:42:47578class AutomationInterstitialPage : public InterstitialPage {
579 public:
580 AutomationInterstitialPage(TabContents* tab,
581 const GURL& url,
582 const std::string& contents)
583 : InterstitialPage(tab, true, url),
584 contents_(contents) {
585 }
586
587 virtual std::string GetHTMLContents() { return contents_; }
588
589 private:
590 std::string contents_;
591
592 DISALLOW_COPY_AND_ASSIGN(AutomationInterstitialPage);
593};
594
initial.commit09911bf2008-07-26 23:55:29595AutomationProvider::AutomationProvider(Profile* profile)
[email protected]295039bd2008-08-15 04:32:57596 : redirect_query_(0),
initial.commit09911bf2008-07-26 23:55:29597 profile_(profile) {
initial.commit09911bf2008-07-26 23:55:29598 browser_tracker_.reset(new AutomationBrowserTracker(this));
599 window_tracker_.reset(new AutomationWindowTracker(this));
600 tab_tracker_.reset(new AutomationTabTracker(this));
601 autocomplete_edit_tracker_.reset(
602 new AutomationAutocompleteEditTracker(this));
603 cwindow_tracker_.reset(new AutomationConstrainedWindowTracker(this));
604 new_tab_ui_load_observer_.reset(new NewTabUILoadObserver(this));
605 dom_operation_observer_.reset(new DomOperationNotificationObserver(this));
606 dom_inspector_observer_.reset(new DomInspectorNotificationObserver(this));
607}
608
609AutomationProvider::~AutomationProvider() {
[email protected]0da050b92008-08-19 19:29:47610 // Make sure that any outstanding NotificationObservers also get destroyed.
611 ObserverList<NotificationObserver>::Iterator it(notification_observer_list_);
[email protected]5a52f162008-08-27 04:15:31612 NotificationObserver* observer;
[email protected]0da050b92008-08-19 19:29:47613 while ((observer = it.GetNext()) != NULL)
614 delete observer;
initial.commit09911bf2008-07-26 23:55:29615}
616
617void AutomationProvider::ConnectToChannel(const std::wstring& channel_id) {
[email protected]295039bd2008-08-15 04:32:57618 channel_.reset(
619 new IPC::ChannelProxy(channel_id, IPC::Channel::MODE_CLIENT, this, NULL,
620 g_browser_process->io_thread()->message_loop()));
621 channel_->Send(new AutomationMsg_Hello(0));
initial.commit09911bf2008-07-26 23:55:29622}
623
624void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) {
625 if (expected_tabs == 0) {
626 Send(new AutomationMsg_InitialLoadsComplete(0));
627 } else {
628 initial_load_observer_.reset(new InitialLoadObserver(expected_tabs, this));
629 }
630}
631
632NotificationObserver* AutomationProvider::AddNavigationStatusListener(
633 NavigationController* tab, IPC::Message* completed_response,
634 IPC::Message* auth_needed_response) {
635 NotificationObserver* observer =
636 new NavigationNotificationObserver(tab, this, completed_response,
637 auth_needed_response);
638 notification_observer_list_.AddObserver(observer);
639
640 return observer;
641}
642
643void AutomationProvider::RemoveNavigationStatusListener(
644 NotificationObserver* obs) {
645 notification_observer_list_.RemoveObserver(obs);
646}
647
648NotificationObserver* AutomationProvider::AddTabStripObserver(
649 Browser* parent, int32 routing_id) {
650 NotificationObserver* observer = new
651 TabAppendedNotificationObserver(parent, this, routing_id);
652 notification_observer_list_.AddObserver(observer);
653
654 return observer;
655}
656
657void AutomationProvider::RemoveTabStripObserver(NotificationObserver* obs) {
658 notification_observer_list_.RemoveObserver(obs);
659}
660
661void AutomationProvider::AddLoginHandler(NavigationController* tab,
662 LoginHandler* handler) {
663 login_handler_map_[tab] = handler;
664}
665
666void AutomationProvider::RemoveLoginHandler(NavigationController* tab) {
667 DCHECK(login_handler_map_[tab]);
668 login_handler_map_.erase(tab);
669}
670
671int AutomationProvider::GetIndexForNavigationController(
672 const NavigationController* controller, const Browser* parent) const {
673 DCHECK(parent);
674 return parent->GetIndexOfController(controller);
675}
676
677void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
678 IPC_BEGIN_MESSAGE_MAP(AutomationProvider, message)
679 IPC_MESSAGE_HANDLER(AutomationMsg_CloseBrowserRequest, CloseBrowser)
680 IPC_MESSAGE_HANDLER(AutomationMsg_ActivateTabRequest, ActivateTab)
681 IPC_MESSAGE_HANDLER(AutomationMsg_ActiveTabIndexRequest, GetActiveTabIndex)
682 IPC_MESSAGE_HANDLER(AutomationMsg_AppendTabRequest, AppendTab)
683 IPC_MESSAGE_HANDLER(AutomationMsg_CloseTabRequest, CloseTab)
684 IPC_MESSAGE_HANDLER(AutomationMsg_GetCookiesRequest, GetCookies)
685 IPC_MESSAGE_HANDLER(AutomationMsg_SetCookieRequest, SetCookie)
686 IPC_MESSAGE_HANDLER(AutomationMsg_NavigateToURLRequest, NavigateToURL)
687 IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsyncRequest, NavigationAsync)
688 IPC_MESSAGE_HANDLER(AutomationMsg_GoBackRequest, GoBack)
689 IPC_MESSAGE_HANDLER(AutomationMsg_GoForwardRequest, GoForward)
690 IPC_MESSAGE_HANDLER(AutomationMsg_ReloadRequest, Reload)
691 IPC_MESSAGE_HANDLER(AutomationMsg_SetAuthRequest, SetAuth)
692 IPC_MESSAGE_HANDLER(AutomationMsg_CancelAuthRequest, CancelAuth)
693 IPC_MESSAGE_HANDLER(AutomationMsg_NeedsAuthRequest, NeedsAuth)
694 IPC_MESSAGE_HANDLER(AutomationMsg_RedirectsFromRequest, GetRedirectsFrom)
695 IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowCountRequest,
696 GetBrowserWindowCount)
697 IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowRequest, GetBrowserWindow)
698 IPC_MESSAGE_HANDLER(AutomationMsg_LastActiveBrowserWindowRequest,
699 GetLastActiveBrowserWindow)
700 IPC_MESSAGE_HANDLER(AutomationMsg_ActiveWindowRequest, GetActiveWindow)
701 IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowActiveRequest, IsWindowActive)
702 IPC_MESSAGE_HANDLER(AutomationMsg_ActivateWindow, ActivateWindow);
703 IPC_MESSAGE_HANDLER(AutomationMsg_WindowHWNDRequest, GetWindowHWND)
[email protected]4ae62752008-08-04 23:28:47704 IPC_MESSAGE_HANDLER(AutomationMsg_WindowExecuteCommandRequest,
705 ExecuteBrowserCommand)
initial.commit09911bf2008-07-26 23:55:29706 IPC_MESSAGE_HANDLER(AutomationMsg_WindowViewBoundsRequest,
707 WindowGetViewBounds)
708 IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowVisibleRequest, SetWindowVisible)
709 IPC_MESSAGE_HANDLER(AutomationMsg_WindowClickRequest, WindowSimulateClick)
710 IPC_MESSAGE_HANDLER(AutomationMsg_WindowKeyPressRequest,
711 WindowSimulateKeyPress)
712 IPC_MESSAGE_HANDLER(AutomationMsg_WindowDragRequest, WindowSimulateDrag)
713 IPC_MESSAGE_HANDLER(AutomationMsg_TabCountRequest, GetTabCount)
714 IPC_MESSAGE_HANDLER(AutomationMsg_TabRequest, GetTab)
715 IPC_MESSAGE_HANDLER(AutomationMsg_TabHWNDRequest, GetTabHWND)
716 IPC_MESSAGE_HANDLER(AutomationMsg_TabProcessIDRequest, GetTabProcessID)
717 IPC_MESSAGE_HANDLER(AutomationMsg_TabTitleRequest, GetTabTitle)
718 IPC_MESSAGE_HANDLER(AutomationMsg_TabURLRequest, GetTabURL)
719 IPC_MESSAGE_HANDLER(AutomationMsg_ShelfVisibilityRequest,
720 GetShelfVisibility)
721 IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused)
722 IPC_MESSAGE_HANDLER(AutomationMsg_ApplyAcceleratorRequest, ApplyAccelerator)
723 IPC_MESSAGE_HANDLER(AutomationMsg_DomOperationRequest, ExecuteJavascript)
724 IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowCountRequest,
725 GetConstrainedWindowCount)
726 IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowRequest,
727 GetConstrainedWindow)
728 IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedTitleRequest,
729 GetConstrainedTitle)
730 IPC_MESSAGE_HANDLER(AutomationMsg_FindInPageRequest,
731 HandleFindInPageRequest)
732 IPC_MESSAGE_HANDLER(AutomationMsg_GetFocusedViewIDRequest, GetFocusedViewID)
733 IPC_MESSAGE_HANDLER(AutomationMsg_InspectElementRequest,
734 HandleInspectElementRequest)
735 IPC_MESSAGE_HANDLER(AutomationMsg_SetFilteredInet,
736 SetFilteredInet);
737 IPC_MESSAGE_HANDLER(AutomationMsg_DownloadDirectoryRequest,
738 GetDownloadDirectory);
739 IPC_MESSAGE_HANDLER(AutomationMsg_OpenNewBrowserWindow,
740 OpenNewBrowserWindow);
741 IPC_MESSAGE_HANDLER(AutomationMsg_WindowForBrowserRequest,
742 GetWindowForBrowser);
743 IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditForBrowserRequest,
744 GetAutocompleteEditForBrowser);
745 IPC_MESSAGE_HANDLER(AutomationMsg_BrowserForWindowRequest,
746 GetBrowserForWindow);
747 IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab)
748 IPC_MESSAGE_HANDLER(AutomationMsg_NavigateInExternalTabRequest,
749 NavigateInExternalTab)
750 IPC_MESSAGE_HANDLER(AutomationMsg_ShowInterstitialPageRequest,
751 ShowInterstitialPage);
752 IPC_MESSAGE_HANDLER(AutomationMsg_HideInterstitialPageRequest,
753 HideInterstitialPage);
754 IPC_MESSAGE_HANDLER(AutomationMsg_SetAcceleratorsForTab,
755 SetAcceleratorsForTab)
756 IPC_MESSAGE_HANDLER(AutomationMsg_ProcessUnhandledAccelerator,
757 ProcessUnhandledAccelerator)
758 IPC_MESSAGE_HANDLER(AutomationMsg_WaitForTabToBeRestored,
759 WaitForTabToBeRestored)
760 IPC_MESSAGE_HANDLER(AutomationMsg_GetSecurityState,
761 GetSecurityState)
762 IPC_MESSAGE_HANDLER(AutomationMsg_GetPageType,
763 GetPageType)
764 IPC_MESSAGE_HANDLER(AutomationMsg_ActionOnSSLBlockingPage,
765 ActionOnSSLBlockingPage)
766 IPC_MESSAGE_HANDLER(AutomationMsg_BringBrowserToFront, BringBrowserToFront)
767 IPC_MESSAGE_HANDLER(AutomationMsg_IsPageMenuCommandEnabled,
768 IsPageMenuCommandEnabled)
769 IPC_MESSAGE_HANDLER(AutomationMsg_PrintNowRequest, PrintNow)
770 IPC_MESSAGE_HANDLER(AutomationMsg_SavePageRequest, SavePage)
771 IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetTextRequest,
772 GetAutocompleteEditText)
773 IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditSetTextRequest,
774 SetAutocompleteEditText)
775 IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditIsQueryInProgressRequest,
776 AutocompleteEditIsQueryInProgress)
777 IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetMatchesRequest,
778 AutocompleteEditGetMatches)
779 IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowBoundsRequest,
780 GetConstrainedWindowBounds)
[email protected]5f8af2a2008-08-06 22:49:45781 IPC_MESSAGE_HANDLER(AutomationMsg_OpenFindInPageRequest,
782 HandleOpenFindInPageRequest)
[email protected]18cb2572008-08-21 20:34:45783 IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost,
784 OnMessageFromExternalHost)
[email protected]5a52f162008-08-27 04:15:31785 IPC_MESSAGE_HANDLER(AutomationMsg_FindRequest,
786 HandleFindRequest)
[email protected]20e93d12008-08-28 16:31:57787 IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowVisibilityRequest,
788 GetFindWindowVisibility)
789 IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowLocationRequest,
790 HandleFindWindowLocationRequest)
[email protected]c2cbeb92008-09-05 21:36:57791 IPC_MESSAGE_HANDLER(AutomationMsg_BookmarkBarVisibilityRequest,
792 GetBookmarkBarVisitility)
[email protected]8a3422c92008-09-24 17:42:42793 IPC_MESSAGE_HANDLER(AutomationMsg_GetSSLInfoBarCountRequest,
794 GetSSLInfoBarCount)
795 IPC_MESSAGE_HANDLER(AutomationMsg_ClickSSLInfoBarLinkRequest,
796 ClickSSLInfoBarLink)
797 IPC_MESSAGE_HANDLER(AutomationMsg_GetLastNavigationTimeRequest,
798 GetLastNavigationTime)
799 IPC_MESSAGE_HANDLER(AutomationMsg_WaitForNavigationRequest,
800 WaitForNavigation)
801 IPC_MESSAGE_HANDLER(AutomationMsg_SetIntPreferenceRequest,
802 SetIntPreference)
[email protected]c274acc2008-11-11 20:13:44803 IPC_MESSAGE_HANDLER(AutomationMsg_ShowingAppModalDialogRequest,
804 GetShowingAppModalDialog)
initial.commit09911bf2008-07-26 23:55:29805 IPC_END_MESSAGE_MAP()
806}
807
808void AutomationProvider::ActivateTab(const IPC::Message& message,
809 int handle, int at_index) {
810 int status = -1;
811 if (browser_tracker_->ContainsHandle(handle) && at_index > -1) {
812 Browser* browser = browser_tracker_->GetResource(handle);
813 if (at_index >= 0 && at_index < browser->tab_count()) {
814 browser->SelectTabContentsAt(at_index, true);
815 status = 0;
816 }
817 }
818 Send(new AutomationMsg_ActivateTabResponse(message.routing_id(), status));
819}
820
821void AutomationProvider::AppendTab(const IPC::Message& message,
822 int handle, const GURL& url) {
823 int append_tab_response = -1; // -1 is the error code
824 NotificationObserver* observer = NULL;
825
826 if (browser_tracker_->ContainsHandle(handle)) {
827 Browser* browser = browser_tracker_->GetResource(handle);
828 observer = AddTabStripObserver(browser, message.routing_id());
829 TabContents* tab_contents =
[email protected]c0588052008-10-27 23:01:50830 browser->AddTabWithURL(url, GURL(), PageTransition::TYPED, true, NULL);
initial.commit09911bf2008-07-26 23:55:29831 if (tab_contents) {
832 append_tab_response =
833 GetIndexForNavigationController(tab_contents->controller(), browser);
834 }
835 }
836
837 if (append_tab_response < 0) {
838 // The append tab failed. Remove the TabStripObserver
839 if (observer) {
840 RemoveTabStripObserver(observer);
841 delete observer;
842 }
843
844 // This will be reached only if the tab could not be appended. In case of a
845 // successful tab append, a successful navigation notification triggers the
846 // send.
847 Send(new AutomationMsg_AppendTabResponse(message.routing_id(),
848 append_tab_response));
849 }
850}
851
852void AutomationProvider::NavigateToURL(const IPC::Message& message,
853 int handle, const GURL& url) {
854 int status = AUTOMATION_MSG_NAVIGATION_ERROR;
855
856 if (tab_tracker_->ContainsHandle(handle)) {
857 NavigationController* tab = tab_tracker_->GetResource(handle);
858
859 // Simulate what a user would do. Activate the tab and then navigate.
860 // We could allow navigating in a background tab in future.
861 Browser* browser = FindAndActivateTab(tab);
862
863 if (browser) {
864 AddNavigationStatusListener(tab,
865 new AutomationMsg_NavigateToURLResponse(
866 message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
867 new AutomationMsg_NavigateToURLResponse(
868 message.routing_id(), AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED));
869 // TODO(darin): avoid conversion to GURL
[email protected]c0588052008-10-27 23:01:50870 browser->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED);
initial.commit09911bf2008-07-26 23:55:29871 return;
872 }
873 }
874 Send(new AutomationMsg_NavigateToURLResponse(
875 message.routing_id(), AUTOMATION_MSG_NAVIGATION_ERROR));
876}
877
878void AutomationProvider::NavigationAsync(const IPC::Message& message,
879 int handle, const GURL& url) {
880 bool status = false;
881
882 if (tab_tracker_->ContainsHandle(handle)) {
883 NavigationController* tab = tab_tracker_->GetResource(handle);
884
885 // Simulate what a user would do. Activate the tab and then navigate.
886 // We could allow navigating in a background tab in future.
887 Browser* browser = FindAndActivateTab(tab);
888
889 if (browser) {
890 // Don't add any listener unless a callback mechanism is desired.
891 // TODO(vibhor): Do this if such a requirement arises in future.
[email protected]c0588052008-10-27 23:01:50892 browser->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED);
initial.commit09911bf2008-07-26 23:55:29893 status = true;
894 }
895 }
896
897 Send(new AutomationMsg_NavigationAsyncResponse(message.routing_id(), status));
898}
899
900void AutomationProvider::GoBack(const IPC::Message& message, int handle) {
901 if (tab_tracker_->ContainsHandle(handle)) {
902 NavigationController* tab = tab_tracker_->GetResource(handle);
903 Browser* browser = FindAndActivateTab(tab);
904 if (browser && browser->IsCommandEnabled(IDC_BACK)) {
905 AddNavigationStatusListener(tab,
906 new AutomationMsg_GoBackResponse(
907 message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
908 new AutomationMsg_GoBackResponse(
909 message.routing_id(), AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED));
910 browser->GoBack();
911 return;
912 }
913 }
914 Send(new AutomationMsg_GoBackResponse(message.routing_id(),
915 AUTOMATION_MSG_NAVIGATION_ERROR));
916}
917
918void AutomationProvider::GoForward(const IPC::Message& message, int handle) {
919 if (tab_tracker_->ContainsHandle(handle)) {
920 NavigationController* tab = tab_tracker_->GetResource(handle);
921 Browser* browser = FindAndActivateTab(tab);
922 if (browser && browser->IsCommandEnabled(IDC_FORWARD)) {
923 AddNavigationStatusListener(tab,
924 new AutomationMsg_GoForwardResponse(
925 message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
926 new AutomationMsg_GoForwardResponse(
927 message.routing_id(), AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED));
928 browser->GoForward();
929 return;
930 }
931 }
932 Send(new AutomationMsg_GoForwardResponse(message.routing_id(),
933 AUTOMATION_MSG_NAVIGATION_ERROR));
934}
935
936void AutomationProvider::Reload(const IPC::Message& message, int handle) {
937 if (tab_tracker_->ContainsHandle(handle)) {
938 NavigationController* tab = tab_tracker_->GetResource(handle);
939 Browser* browser = FindAndActivateTab(tab);
940 if (browser && browser->IsCommandEnabled(IDC_RELOAD)) {
941 AddNavigationStatusListener(tab,
942 new AutomationMsg_ReloadResponse(
943 message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
944 new AutomationMsg_ReloadResponse(
945 message.routing_id(), AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED));
946 browser->Reload();
947 return;
948 }
949 }
950 Send(new AutomationMsg_ReloadResponse(message.routing_id(),
951 AUTOMATION_MSG_NAVIGATION_ERROR));
952}
953
954void AutomationProvider::SetAuth(const IPC::Message& message, int tab_handle,
955 const std::wstring& username,
956 const std::wstring& password) {
957 int status = -1;
958
959 if (tab_tracker_->ContainsHandle(tab_handle)) {
960 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
961 LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
962
963 if (iter != login_handler_map_.end()) {
964 // If auth is needed again after this, assume login has failed. This is
965 // not strictly correct, because a navigation can require both proxy and
966 // server auth, but it should be OK for now.
967 LoginHandler* handler = iter->second;
968 AddNavigationStatusListener(tab,
969 new AutomationMsg_SetAuthResponse(message.routing_id(), 0),
970 new AutomationMsg_SetAuthResponse(message.routing_id(), -1));
971 handler->SetAuth(username, password);
972 status = 0;
973 }
974 }
975 if (status < 0) {
976 Send(new AutomationMsg_SetAuthResponse(message.routing_id(), status));
977 }
978}
979
980void AutomationProvider::CancelAuth(const IPC::Message& message,
981 int tab_handle) {
982 int status = -1;
983
984 if (tab_tracker_->ContainsHandle(tab_handle)) {
985 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
986 LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
987
988 if (iter != login_handler_map_.end()) {
989 // If auth is needed again after this, something is screwy.
990 LoginHandler* handler = iter->second;
991 AddNavigationStatusListener(tab,
992 new AutomationMsg_CancelAuthResponse(message.routing_id(), 0),
993 new AutomationMsg_CancelAuthResponse(message.routing_id(), -1));
994 handler->CancelAuth();
995 status = 0;
996 }
997 }
998 if (status < 0) {
999 Send(new AutomationMsg_CancelAuthResponse(message.routing_id(), status));
1000 }
1001}
1002
1003void AutomationProvider::NeedsAuth(const IPC::Message& message,
1004 int tab_handle) {
1005 bool needs_auth = false;
1006
1007 if (tab_tracker_->ContainsHandle(tab_handle)) {
1008 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
1009 LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
1010
1011 if (iter != login_handler_map_.end()) {
1012 // The LoginHandler will be in our map IFF the tab needs auth.
1013 needs_auth = true;
1014 }
1015 }
1016
1017 Send(new AutomationMsg_NeedsAuthResponse(message.routing_id(), needs_auth));
1018}
1019
1020void AutomationProvider::GetRedirectsFrom(const IPC::Message& message,
1021 int tab_handle,
1022 const GURL& source_url) {
1023 DCHECK(!redirect_query_) << "Can only handle one redirect query at once.";
1024 if (tab_tracker_->ContainsHandle(tab_handle)) {
1025 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
1026 HistoryService* history_service =
1027 tab->profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
1028
1029 DCHECK(history_service) << "Tab " << tab_handle << "'s profile " <<
1030 "has no history service";
1031 if (history_service) {
1032 // Schedule a history query for redirects. The response will be sent
1033 // asynchronously from the callback the history system uses to notify us
1034 // that it's done: OnRedirectQueryComplete.
1035 redirect_query_routing_id_ = message.routing_id();
1036 redirect_query_ = history_service->QueryRedirectsFrom(
1037 source_url, &consumer_,
1038 NewCallback(this, &AutomationProvider::OnRedirectQueryComplete));
1039 return; // Response will be sent when query completes.
1040 }
1041 }
1042
1043 // Send failure response.
1044 IPC::Message* msg = new IPC::Message(
1045 message.routing_id(), AutomationMsg_RedirectsFromResponse::ID,
1046 IPC::Message::PRIORITY_NORMAL);
1047 msg->WriteInt(-1); // Negative string count indicates an error.
1048 Send(msg);
1049}
1050
1051void AutomationProvider::GetActiveTabIndex(const IPC::Message& message,
1052 int handle) {
1053 int active_tab_index = -1; // -1 is the error code
1054 if (browser_tracker_->ContainsHandle(handle)) {
1055 Browser* browser = browser_tracker_->GetResource(handle);
1056 active_tab_index = browser->selected_index();
1057 }
1058 Send(new AutomationMsg_ActiveTabIndexResponse(message.routing_id(),
1059 active_tab_index));
1060}
1061
1062void AutomationProvider::GetBrowserWindowCount(const IPC::Message& message) {
1063 Send(new AutomationMsg_BrowserWindowCountResponse(
1064 message.routing_id(), static_cast<int>(BrowserList::size())));
1065}
1066
[email protected]c274acc2008-11-11 20:13:441067void AutomationProvider::GetShowingAppModalDialog(const IPC::Message& message) {
1068 Send(new AutomationMsg_ShowingAppModalDialogResponse(
1069 message.routing_id(),
1070 static_cast<bool>(BrowserList::IsShowingAppModalDialog())));
1071}
1072
initial.commit09911bf2008-07-26 23:55:291073void AutomationProvider::GetBrowserWindow(const IPC::Message& message,
1074 int index) {
1075 int handle = 0;
1076 if (index >= 0) {
1077 BrowserList::const_iterator iter = BrowserList::begin();
1078
1079 for (; (iter != BrowserList::end()) && (index > 0); ++iter, --index);
1080 if (iter != BrowserList::end()) {
1081 handle = browser_tracker_->Add(*iter);
1082 }
1083 }
1084
1085 Send(new AutomationMsg_BrowserWindowResponse(message.routing_id(), handle));
1086}
1087
1088void AutomationProvider::GetLastActiveBrowserWindow(
1089 const IPC::Message& message) {
1090 int handle = 0;
1091 Browser* browser = BrowserList::GetLastActive();
1092 if (browser)
1093 handle = browser_tracker_->Add(browser);
1094 Send(new AutomationMsg_LastActiveBrowserWindowResponse(message.routing_id(),
1095 handle));
1096}
1097
1098BOOL CALLBACK EnumThreadWndProc(HWND hwnd, LPARAM l_param) {
1099 if (hwnd == reinterpret_cast<HWND>(l_param)) {
1100 return FALSE;
1101 }
1102 return TRUE;
1103}
1104
1105void AutomationProvider::GetActiveWindow(const IPC::Message& message) {
1106 HWND window = GetForegroundWindow();
1107
1108 // Let's make sure this window belongs to our process.
1109 if (EnumThreadWindows(::GetCurrentThreadId(),
1110 EnumThreadWndProc,
1111 reinterpret_cast<LPARAM>(window))) {
1112 // We enumerated all the windows and did not find the foreground window,
1113 // it is not our window, ignore it.
1114 Send(new AutomationMsg_ActiveWindowResponse(message.routing_id(), 0));
1115 return;
1116 }
1117
1118 int handle = window_tracker_->Add(window);
1119 Send(new AutomationMsg_ActiveWindowResponse(message.routing_id(), handle));
1120}
1121
1122void AutomationProvider::GetWindowHWND(const IPC::Message& message,
1123 int handle) {
1124 HWND win32_handle = window_tracker_->GetResource(handle);
1125 Send(new AutomationMsg_WindowHWNDResponse(message.routing_id(),
1126 win32_handle));
1127}
1128
[email protected]4ae62752008-08-04 23:28:471129void AutomationProvider::ExecuteBrowserCommand(const IPC::Message& message,
1130 int handle,
1131 int command) {
[email protected]4ae62752008-08-04 23:28:471132 bool success = false;
1133 if (browser_tracker_->ContainsHandle(handle)) {
1134 Browser* browser = browser_tracker_->GetResource(handle);
1135 if (browser->SupportsCommand(command) &&
1136 browser->IsCommandEnabled(command)) {
1137 browser->ExecuteCommand(command);
1138 success = true;
1139 }
1140 }
1141 Send(new AutomationMsg_WindowExecuteCommandResponse(message.routing_id(),
1142 success));
1143}
1144
initial.commit09911bf2008-07-26 23:55:291145void AutomationProvider::WindowGetViewBounds(const IPC::Message& message,
1146 int handle,
1147 int view_id,
1148 bool screen_coordinates) {
1149 bool succeeded = false;
[email protected]80f8b9f2008-10-16 18:17:471150 gfx::Rect bounds;
initial.commit09911bf2008-07-26 23:55:291151
1152 void* iter = NULL;
1153 if (window_tracker_->ContainsHandle(handle)) {
1154 HWND hwnd = window_tracker_->GetResource(handle);
[email protected]c2dacc92008-10-16 23:51:381155 views::RootView* root_view = views::ContainerWin::FindRootView(hwnd);
initial.commit09911bf2008-07-26 23:55:291156 if (root_view) {
[email protected]c2dacc92008-10-16 23:51:381157 views::View* view = root_view->GetViewByID(view_id);
initial.commit09911bf2008-07-26 23:55:291158 if (view) {
1159 succeeded = true;
[email protected]96b667d2008-10-14 20:58:441160 gfx::Point point;
initial.commit09911bf2008-07-26 23:55:291161 if (screen_coordinates)
[email protected]c2dacc92008-10-16 23:51:381162 views::View::ConvertPointToScreen(view, &point);
initial.commit09911bf2008-07-26 23:55:291163 else
[email protected]c2dacc92008-10-16 23:51:381164 views::View::ConvertPointToView(view, root_view, &point);
[email protected]80f8b9f2008-10-16 18:17:471165 bounds = view->GetLocalBounds(false);
1166 bounds.set_origin(point);
initial.commit09911bf2008-07-26 23:55:291167 }
1168 }
1169 }
1170
[email protected]80f8b9f2008-10-16 18:17:471171 Send(new AutomationMsg_WindowViewBoundsResponse(message.routing_id(),
1172 succeeded, bounds));
initial.commit09911bf2008-07-26 23:55:291173}
1174
1175// This task enqueues a mouse event on the event loop, so that the view
1176// that it's being sent to can do the requisite post-processing.
1177class MouseEventTask : public Task {
1178 public:
[email protected]c2dacc92008-10-16 23:51:381179 MouseEventTask(views::View* view,
1180 views::Event::EventType type,
initial.commit09911bf2008-07-26 23:55:291181 POINT point,
1182 int flags)
1183 : view_(view), type_(type), point_(point), flags_(flags) {}
1184 virtual ~MouseEventTask() {}
1185
1186 virtual void Run() {
[email protected]c2dacc92008-10-16 23:51:381187 views::MouseEvent event(type_, point_.x, point_.y, flags_);
initial.commit09911bf2008-07-26 23:55:291188 // We need to set the cursor position before we process the event because
1189 // some code (tab dragging, for instance) queries the actual cursor location
1190 // rather than the location of the mouse event. Note that the reason why
1191 // the drag code moved away from using mouse event locations was because
1192 // our conversion to screen location doesn't work well with multiple
1193 // monitors, so this only works reliably in a single monitor setup.
[email protected]96b667d2008-10-14 20:58:441194 gfx::Point screen_location(point_.x, point_.y);
initial.commit09911bf2008-07-26 23:55:291195 view_->ConvertPointToScreen(view_, &screen_location);
[email protected]96b667d2008-10-14 20:58:441196 ::SetCursorPos(screen_location.x(), screen_location.y());
initial.commit09911bf2008-07-26 23:55:291197 switch (type_) {
[email protected]c2dacc92008-10-16 23:51:381198 case views::Event::ET_MOUSE_PRESSED:
initial.commit09911bf2008-07-26 23:55:291199 view_->OnMousePressed(event);
1200 break;
1201
[email protected]c2dacc92008-10-16 23:51:381202 case views::Event::ET_MOUSE_DRAGGED:
initial.commit09911bf2008-07-26 23:55:291203 view_->OnMouseDragged(event);
1204 break;
1205
[email protected]c2dacc92008-10-16 23:51:381206 case views::Event::ET_MOUSE_RELEASED:
initial.commit09911bf2008-07-26 23:55:291207 view_->OnMouseReleased(event, false);
1208 break;
1209
1210 default:
1211 NOTREACHED();
1212 }
1213 }
1214
1215 private:
[email protected]c2dacc92008-10-16 23:51:381216 views::View* view_;
1217 views::Event::EventType type_;
initial.commit09911bf2008-07-26 23:55:291218 POINT point_;
1219 int flags_;
1220
[email protected]5a52f162008-08-27 04:15:311221 DISALLOW_COPY_AND_ASSIGN(MouseEventTask);
initial.commit09911bf2008-07-26 23:55:291222};
1223
[email protected]c2dacc92008-10-16 23:51:381224void AutomationProvider::ScheduleMouseEvent(views::View* view,
1225 views::Event::EventType type,
initial.commit09911bf2008-07-26 23:55:291226 POINT point,
1227 int flags) {
1228 MessageLoop::current()->PostTask(FROM_HERE,
1229 new MouseEventTask(view, type, point, flags));
1230}
1231
1232// This task just adds another task to the event queue. This is useful if
1233// you want to ensure that any tasks added to the event queue after this one
1234// have already been processed by the time |task| is run.
1235class InvokeTaskLaterTask : public Task {
1236 public:
1237 explicit InvokeTaskLaterTask(Task* task) : task_(task) {}
1238 virtual ~InvokeTaskLaterTask() {}
1239
1240 virtual void Run() {
1241 MessageLoop::current()->PostTask(FROM_HERE, task_);
1242 }
1243
1244 private:
1245 Task* task_;
1246
[email protected]5a52f162008-08-27 04:15:311247 DISALLOW_COPY_AND_ASSIGN(InvokeTaskLaterTask);
initial.commit09911bf2008-07-26 23:55:291248};
1249
1250// This task sends a WindowDragResponse message with the appropriate
1251// routing ID to the automation proxy. This is implemented as a task so that
1252// we know that the mouse events (and any tasks that they spawn on the message
1253// loop) have been processed by the time this is sent.
1254class WindowDragResponseTask : public Task {
1255 public:
1256 WindowDragResponseTask(AutomationProvider* provider, int routing_id)
1257 : provider_(provider), routing_id_(routing_id) {}
1258 virtual ~WindowDragResponseTask() {}
1259
1260 virtual void Run() {
1261 provider_->Send(new AutomationMsg_WindowDragResponse(routing_id_, true));
1262 }
1263
1264 private:
1265 AutomationProvider* provider_;
1266 int routing_id_;
1267
[email protected]5a52f162008-08-27 04:15:311268 DISALLOW_COPY_AND_ASSIGN(WindowDragResponseTask);
initial.commit09911bf2008-07-26 23:55:291269};
1270
1271void AutomationProvider::WindowSimulateClick(const IPC::Message& message,
1272 int handle,
1273 POINT click,
1274 int flags) {
1275 HWND hwnd = 0;
1276
1277 if (window_tracker_->ContainsHandle(handle)) {
1278 hwnd = window_tracker_->GetResource(handle);
1279
initial.commit09911bf2008-07-26 23:55:291280 ui_controls::SendMouseMove(click.x, click.y);
1281
1282 ui_controls::MouseButton button = ui_controls::LEFT;
[email protected]c2dacc92008-10-16 23:51:381283 if ((flags & views::Event::EF_LEFT_BUTTON_DOWN) ==
1284 views::Event::EF_LEFT_BUTTON_DOWN) {
initial.commit09911bf2008-07-26 23:55:291285 button = ui_controls::LEFT;
[email protected]c2dacc92008-10-16 23:51:381286 } else if ((flags & views::Event::EF_RIGHT_BUTTON_DOWN) ==
1287 views::Event::EF_RIGHT_BUTTON_DOWN) {
initial.commit09911bf2008-07-26 23:55:291288 button = ui_controls::RIGHT;
[email protected]c2dacc92008-10-16 23:51:381289 } else if ((flags & views::Event::EF_MIDDLE_BUTTON_DOWN) ==
1290 views::Event::EF_MIDDLE_BUTTON_DOWN) {
initial.commit09911bf2008-07-26 23:55:291291 button = ui_controls::MIDDLE;
1292 } else {
1293 NOTREACHED();
1294 }
1295 ui_controls::SendMouseClick(button);
1296 }
1297}
1298
[email protected]f7a391a12008-11-10 21:29:341299namespace {
1300
1301// Available mouse buttons.
1302enum Button {
1303 Button_None,
1304 Button_Left,
1305 Button_Middle,
1306 Button_Right
1307};
1308
1309// A type of user gesture for a keyboard or mouse button.
1310enum Gesture {
1311 Gesture_None,
1312 Gesture_Press,
1313 Gesture_Release
1314};
1315
1316// SendInput inserts the messages generated into the message queue, which means
1317// if we want to process these messages immediately we need to force the
1318// message queue to be processed.
1319void PostAndPumpInput(INPUT* input) {
1320 SendInput(1, input, sizeof(INPUT));
1321 MessageLoop::current()->RunAllPending();
1322}
1323
1324// MOUSEINPUT coordinates are described by MSDN to fall within the range
1325// 0..65535 (for the primary monitor). We need to convert the client
1326// coordinates supplied into values in this range.
1327void GetScreenCoordsForSendInput(HWND window, const POINT& client_point,
1328 LONG* x, LONG* y) {
1329 POINT screen_point = client_point;
1330 MapWindowPoints(window, HWND_DESKTOP, &screen_point, 1);
1331
1332 HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY);
1333 MONITORINFO mi;
1334 mi.cbSize = sizeof(mi);
1335 GetMonitorInfo(monitor, &mi);
1336
1337 int monitor_width = mi.rcMonitor.right - mi.rcMonitor.left;
1338 int monitor_height = mi.rcMonitor.bottom - mi.rcMonitor.top;
1339 int point_x = screen_point.x - mi.rcMonitor.left;
1340 int point_y = screen_point.y - mi.rcMonitor.top;
1341
1342 *x = (point_x * 65535) / monitor_width;
1343 *y = (point_y * 65535) / monitor_height;
1344}
1345
1346// Pack up and send a MOUSEINPUT for a mouse press or release action.
1347void SendMouseInput(Button button, HWND window, const POINT& client_point,
1348 Gesture gesture) {
1349 INPUT input;
1350 input.type = INPUT_MOUSE;
1351 GetScreenCoordsForSendInput(window, client_point, &input.mi.dx,
1352 &input.mi.dy);
1353 input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
1354 switch (button) {
1355 case Button_Left:
1356 input.mi.dwFlags |= (gesture == Gesture_Press) ? MOUSEEVENTF_LEFTDOWN
1357 : MOUSEEVENTF_LEFTUP;
1358 break;
1359 case Button_Middle:
1360 input.mi.dwFlags |= (gesture == Gesture_Press) ? MOUSEEVENTF_MIDDLEDOWN
1361 : MOUSEEVENTF_MIDDLEUP;
1362 break;
1363 case Button_Right:
1364 input.mi.dwFlags |= (gesture == Gesture_Press) ? MOUSEEVENTF_RIGHTDOWN
1365 : MOUSEEVENTF_RIGHTUP;
1366 break;
1367 }
1368 input.mi.time = 0;
1369 input.mi.dwExtraInfo = 0;
1370 input.mi.mouseData = 0;
1371 PostAndPumpInput(&input);
1372}
1373
1374// Pack up and send a KEYBDINPUT for a key press or release action.
1375void SendKeyboardInput(WORD vkey, Gesture gesture) {
1376 INPUT input;
1377 input.type = INPUT_KEYBOARD;
1378 input.ki.wVk = vkey;
1379 input.ki.wScan = 0;
1380 input.ki.dwFlags = gesture == Gesture_Release ? KEYEVENTF_KEYUP : 0;
1381 input.ki.dwExtraInfo = 0;
1382 input.ki.time = 0;
1383 PostAndPumpInput(&input);
1384}
1385
1386Button GetButtonFromFlags(int flags) {
1387 if (flags & views::Event::EF_LEFT_BUTTON_DOWN)
1388 return Button_Left;
1389 if (flags & views::Event::EF_MIDDLE_BUTTON_DOWN)
1390 return Button_Middle;
1391 if (flags & views::Event::EF_RIGHT_BUTTON_DOWN)
1392 return Button_Right;
1393 return Button_None;
1394}
1395
1396} // namespace
1397
initial.commit09911bf2008-07-26 23:55:291398void AutomationProvider::WindowSimulateDrag(const IPC::Message& message,
1399 int handle,
[email protected]f7a391a12008-11-10 21:29:341400 const POINT& start_point,
1401 const POINT& end_point,
[email protected]5e0f30c2008-08-14 22:52:441402 int flags,
1403 bool press_escape_en_route) {
initial.commit09911bf2008-07-26 23:55:291404 bool succeeded = false;
[email protected]f7a391a12008-11-10 21:29:341405 if (browser_tracker_->ContainsHandle(handle)) {
1406 // TODO(beng): this probably doesn't even need to be done in this process,
1407 // since SendInput is system-wide.
initial.commit09911bf2008-07-26 23:55:291408 Browser* browser = browser_tracker_->GetResource(handle);
1409 DCHECK(browser);
[email protected]2d46c842008-11-14 19:24:311410 HWND browser_hwnd =
1411 reinterpret_cast<HWND>(browser->window()->GetNativeHandle());
[email protected]86aa36b2008-11-08 00:11:311412
[email protected]f7a391a12008-11-10 21:29:341413 // We can't simulate drags to the non-client area of the window, because
1414 // Windows spawns a nested modal message loop in cases where drags occur
1415 // in many of these locations, so we just don't bother with the test in
1416 // clicks to non-client coordinates.
1417 POINT start_screen_point = start_point;
1418 MapWindowPoints(browser_hwnd, HWND_DESKTOP, &start_screen_point, 1);
1419 LRESULT hittest_code = SendMessage(browser_hwnd, WM_NCHITTEST, 0,
1420 MAKELPARAM(start_screen_point.x,
1421 start_screen_point.y));
1422 if (hittest_code == HTCLIENT) {
1423 succeeded = true;
[email protected]86aa36b2008-11-08 00:11:311424
[email protected]f7a391a12008-11-10 21:29:341425 // Press down any optionally specified modifier keys.
1426 if (flags & views::Event::EF_SHIFT_DOWN)
1427 SendKeyboardInput(VK_SHIFT, Gesture_Press);
1428 if (flags & views::Event::EF_CONTROL_DOWN)
1429 SendKeyboardInput(VK_CONTROL, Gesture_Press);
1430
1431 // Move the mouse along the drag path.
1432 Button button = GetButtonFromFlags(flags);
1433 SendMouseInput(button, browser_hwnd, start_point, Gesture_Press);
1434 SendMouseInput(button, browser_hwnd, end_point, Gesture_Press);
1435
1436 // Optionally press the escape key if requested.
1437 if (press_escape_en_route) {
1438 SendKeyboardInput(VK_ESCAPE, Gesture_Press);
1439 SendKeyboardInput(VK_ESCAPE, Gesture_Release);
1440 }
1441
1442 // Release the specified mouse button.
1443 SendMouseInput(button, browser_hwnd, end_point, Gesture_Release);
1444
1445 // Release any optionally specified modifier keys.
1446 if (flags & views::Event::EF_CONTROL_DOWN)
1447 SendKeyboardInput(VK_CONTROL, Gesture_Release);
1448 if (flags & views::Event::EF_SHIFT_DOWN)
1449 SendKeyboardInput(VK_SHIFT, Gesture_Release);
1450 }
1451 }
1452 if (succeeded) {
initial.commit09911bf2008-07-26 23:55:291453 MessageLoop::current()->PostTask(FROM_HERE,
1454 new InvokeTaskLaterTask(
1455 new WindowDragResponseTask(this, message.routing_id())));
1456 } else {
1457 Send(new AutomationMsg_WindowDragResponse(message.routing_id(), true));
1458 }
1459}
1460
1461void AutomationProvider::WindowSimulateKeyPress(const IPC::Message& message,
1462 int handle,
1463 wchar_t key,
1464 int flags) {
1465 if (!window_tracker_->ContainsHandle(handle))
1466 return;
1467
1468 // The key event is sent to whatever window is active.
1469 ui_controls::SendKeyPress(key,
[email protected]c2dacc92008-10-16 23:51:381470 ((flags & views::Event::EF_CONTROL_DOWN) ==
1471 views::Event::EF_CONTROL_DOWN),
1472 ((flags & views::Event::EF_SHIFT_DOWN) ==
1473 views::Event::EF_SHIFT_DOWN),
1474 ((flags & views::Event::EF_ALT_DOWN) ==
1475 views::Event::EF_ALT_DOWN));
initial.commit09911bf2008-07-26 23:55:291476}
1477
1478void AutomationProvider::GetFocusedViewID(const IPC::Message& message,
1479 int handle) {
1480 int view_id = -1;
1481 if (window_tracker_->ContainsHandle(handle)) {
1482 HWND hwnd = window_tracker_->GetResource(handle);
[email protected]c2dacc92008-10-16 23:51:381483 views::FocusManager* focus_manager =
1484 views::FocusManager::GetFocusManager(hwnd);
initial.commit09911bf2008-07-26 23:55:291485 DCHECK(focus_manager);
[email protected]c2dacc92008-10-16 23:51:381486 views::View* focused_view = focus_manager->GetFocusedView();
initial.commit09911bf2008-07-26 23:55:291487 if (focused_view)
1488 view_id = focused_view->GetID();
1489 }
1490 Send(new AutomationMsg_GetFocusedViewIDResponse(message.routing_id(),
1491 view_id));
1492}
1493
1494void AutomationProvider::SetWindowVisible(const IPC::Message& message,
1495 int handle, bool visible) {
1496 if (window_tracker_->ContainsHandle(handle)) {
1497 HWND hwnd = window_tracker_->GetResource(handle);
1498 ::ShowWindow(hwnd, visible ? SW_SHOW : SW_HIDE);
1499 Send(new AutomationMsg_SetWindowVisibleResponse(message.routing_id(),
1500 true));
1501 } else {
1502 Send(new AutomationMsg_SetWindowVisibleResponse(message.routing_id(),
1503 false));
1504 }
1505}
1506
1507void AutomationProvider::IsWindowActive(const IPC::Message& message,
1508 int handle) {
1509 if (window_tracker_->ContainsHandle(handle)) {
1510 HWND hwnd = window_tracker_->GetResource(handle);
1511 bool is_active = ::GetForegroundWindow() == hwnd;
1512 Send(new AutomationMsg_IsWindowActiveResponse(
1513 message.routing_id(), true, is_active));
1514 } else {
1515 Send(new AutomationMsg_IsWindowActiveResponse(message.routing_id(),
1516 false, false));
1517 }
1518}
1519
1520void AutomationProvider::ActivateWindow(const IPC::Message& message,
1521 int handle) {
1522 if (window_tracker_->ContainsHandle(handle)) {
1523 ::SetActiveWindow(window_tracker_->GetResource(handle));
1524 }
1525}
1526
1527void AutomationProvider::GetTabCount(const IPC::Message& message, int handle) {
1528 int tab_count = -1; // -1 is the error code
1529
1530 if (browser_tracker_->ContainsHandle(handle)) {
1531 Browser* browser = browser_tracker_->GetResource(handle);
1532 tab_count = browser->tab_count();
1533 }
1534
1535 Send(new AutomationMsg_TabCountResponse(message.routing_id(), tab_count));
1536}
1537
1538void AutomationProvider::GetTab(const IPC::Message& message,
1539 int win_handle, int tab_index) {
1540 void* iter = NULL;
1541 int tab_handle = 0;
1542 if (browser_tracker_->ContainsHandle(win_handle) && (tab_index >= 0)) {
1543 Browser* browser = browser_tracker_->GetResource(win_handle);
1544 if (tab_index < browser->tab_count()) {
1545 TabContents* tab_contents =
1546 browser->GetTabContentsAt(tab_index);
1547 tab_handle = tab_tracker_->Add(tab_contents->controller());
1548 }
1549 }
1550
1551 Send(new AutomationMsg_TabResponse(message.routing_id(), tab_handle));
1552}
1553
1554void AutomationProvider::GetTabTitle(const IPC::Message& message, int handle) {
1555 int title_string_size = -1; // -1 is the error code
1556 std::wstring title;
1557 if (tab_tracker_->ContainsHandle(handle)) {
1558 NavigationController* tab = tab_tracker_->GetResource(handle);
[email protected]1e5645ff2008-08-27 18:09:071559 title = tab->GetActiveEntry()->title();
initial.commit09911bf2008-07-26 23:55:291560 title_string_size = static_cast<int>(title.size());
1561 }
1562
1563 Send(new AutomationMsg_TabTitleResponse(message.routing_id(),
1564 title_string_size, title));
1565}
1566
1567void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) {
1568 if (window_tracker_->ContainsHandle(handle)) {
1569 window_tracker_->Remove(window_tracker_->GetResource(handle));
1570 }
1571}
1572
1573void AutomationProvider::OnChannelError() {
1574 LOG(ERROR) << "AutomationProxy went away, shutting down app.";
[email protected]295039bd2008-08-15 04:32:571575 AutomationProviderList::GetInstance()->RemoveProvider(this);
initial.commit09911bf2008-07-26 23:55:291576}
1577
1578// TODO(brettw) change this to accept GURLs when history supports it
1579void AutomationProvider::OnRedirectQueryComplete(
1580 HistoryService::Handle request_handle,
1581 GURL from_url,
1582 bool success,
1583 HistoryService::RedirectList* redirects) {
1584 DCHECK(request_handle == redirect_query_);
1585
1586 // Respond to the pending request for the redirect list.
1587 IPC::Message* msg = new IPC::Message(redirect_query_routing_id_,
1588 AutomationMsg_RedirectsFromResponse::ID,
1589 IPC::Message::PRIORITY_NORMAL);
1590 if (success) {
1591 msg->WriteInt(static_cast<int>(redirects->size()));
1592 for (size_t i = 0; i < redirects->size(); i++)
1593 IPC::ParamTraits<GURL>::Write(msg, redirects->at(i));
1594 } else {
1595 msg->WriteInt(-1); // Negative count indicates failure.
1596 }
1597
1598 Send(msg);
1599 redirect_query_ = NULL;
1600}
1601
1602bool AutomationProvider::Send(IPC::Message* msg) {
[email protected]295039bd2008-08-15 04:32:571603 DCHECK(channel_.get());
1604 return channel_->Send(msg);
initial.commit09911bf2008-07-26 23:55:291605}
1606
1607Browser* AutomationProvider::FindAndActivateTab(
1608 NavigationController* controller) {
1609 int tab_index;
1610 Browser* browser = Browser::GetBrowserForController(controller, &tab_index);
1611 if (browser)
1612 browser->SelectTabContentsAt(tab_index, true);
1613
1614 return browser;
1615}
1616
1617void AutomationProvider::GetCookies(const IPC::Message& message,
1618 const GURL& url, int handle) {
1619 std::string value;
1620
1621 if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
1622 NavigationController* tab = tab_tracker_->GetResource(handle);
1623 value =
1624 tab->profile()->GetRequestContext()->cookie_store()->GetCookies(url);
1625 }
1626
1627 Send(new AutomationMsg_GetCookiesResponse(message.routing_id(),
1628 static_cast<int>(value.size()), value));
1629}
1630
1631void AutomationProvider::SetCookie(const IPC::Message& message,
1632 const GURL& url,
1633 const std::string value,
1634 int handle) {
1635 int response_value = -1;
1636
1637 if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
1638 NavigationController* tab = tab_tracker_->GetResource(handle);
1639 URLRequestContext* context = tab->profile()->GetRequestContext();
1640 if (context->cookie_store()->SetCookie(url, value))
1641 response_value = 1;
1642 }
1643
1644 Send(new AutomationMsg_SetCookieResponse(message.routing_id(),
1645 response_value));
1646}
1647
1648void AutomationProvider::GetTabURL(const IPC::Message& message, int handle) {
1649 bool success = false;
1650 GURL url;
1651 if (tab_tracker_->ContainsHandle(handle)) {
1652 NavigationController* tab = tab_tracker_->GetResource(handle);
1653 // Return what the user would see in the location bar.
[email protected]1e5645ff2008-08-27 18:09:071654 url = tab->GetActiveEntry()->display_url();
initial.commit09911bf2008-07-26 23:55:291655 success = true;
1656 }
1657
1658 Send(new AutomationMsg_TabURLResponse(message.routing_id(), success, url));
1659}
1660
1661void AutomationProvider::GetTabHWND(const IPC::Message& message, int handle) {
1662 HWND tab_hwnd = NULL;
1663
1664 if (tab_tracker_->ContainsHandle(handle)) {
1665 NavigationController* tab = tab_tracker_->GetResource(handle);
1666 tab_hwnd = tab->active_contents()->GetContainerHWND();
1667 }
1668
1669 Send(new AutomationMsg_TabHWNDResponse(message.routing_id(), tab_hwnd));
1670}
1671
1672void AutomationProvider::GetTabProcessID(
1673 const IPC::Message& message, int handle) {
1674 int process_id = -1;
1675
1676 if (tab_tracker_->ContainsHandle(handle)) {
1677 process_id = 0;
1678 NavigationController* tab = tab_tracker_->GetResource(handle);
1679 if (tab->active_contents()->AsWebContents()) {
1680 WebContents* web_contents = tab->active_contents()->AsWebContents();
[email protected]2f15de42008-11-11 22:35:191681 if (web_contents->process())
1682 process_id = web_contents->process()->process().pid();
initial.commit09911bf2008-07-26 23:55:291683 }
1684 }
1685
1686 Send(new AutomationMsg_TabProcessIDResponse(message.routing_id(),
1687 process_id));
1688}
1689
1690void AutomationProvider::ApplyAccelerator(int handle, int id) {
1691 if (browser_tracker_->ContainsHandle(handle)) {
1692 Browser* browser = browser_tracker_->GetResource(handle);
1693 browser->controller()->ExecuteCommand(id);
1694 }
1695}
1696
1697void AutomationProvider::ExecuteJavascript(const IPC::Message& message,
1698 int handle,
1699 const std::wstring& frame_xpath,
1700 const std::wstring& script) {
1701 bool succeeded = false;
[email protected]20e93d12008-08-28 16:31:571702 WebContents* web_contents = GetWebContentsForHandle(handle, NULL);
1703 if (web_contents) {
1704 // Set the routing id of this message with the controller.
1705 // This routing id needs to be remembered for the reverse
1706 // communication while sending back the response of
1707 // this javascript execution.
[email protected]f29acf52008-11-03 20:08:331708 std::wstring set_automation_id;
1709 SStringPrintf(&set_automation_id,
1710 L"window.domAutomationController.setAutomationId(%d);",
[email protected]20e93d12008-08-28 16:31:571711 message.routing_id());
initial.commit09911bf2008-07-26 23:55:291712
[email protected]1f5af4442008-09-25 22:11:061713 web_contents->render_view_host()->ExecuteJavascriptInWebFrame(
[email protected]f29acf52008-11-03 20:08:331714 frame_xpath, set_automation_id);
[email protected]1f5af4442008-09-25 22:11:061715 web_contents->render_view_host()->ExecuteJavascriptInWebFrame(
1716 frame_xpath, script);
[email protected]20e93d12008-08-28 16:31:571717 succeeded = true;
initial.commit09911bf2008-07-26 23:55:291718 }
1719
1720 if (!succeeded) {
1721 Send(new AutomationMsg_DomOperationResponse(message.routing_id(), ""));
1722 }
1723}
1724
1725void AutomationProvider::GetShelfVisibility(const IPC::Message& message,
1726 int handle) {
1727 bool visible = false;
[email protected]20e93d12008-08-28 16:31:571728
1729 WebContents* web_contents = GetWebContentsForHandle(handle, NULL);
1730 if (web_contents)
1731 visible = web_contents->IsDownloadShelfVisible();
initial.commit09911bf2008-07-26 23:55:291732
1733 Send(new AutomationMsg_ShelfVisibilityResponse(message.routing_id(),
1734 visible));
1735}
1736
1737void AutomationProvider::GetConstrainedWindowCount(const IPC::Message& message,
1738 int handle) {
1739 int count = -1; // -1 is the error code
1740 if (tab_tracker_->ContainsHandle(handle)) {
1741 NavigationController* nav_controller = tab_tracker_->GetResource(handle);
1742 TabContents* tab_contents = nav_controller->active_contents();
1743 if (tab_contents) {
1744 count = static_cast<int>(tab_contents->child_windows_.size());
1745 }
1746 }
1747
1748 Send(new AutomationMsg_ConstrainedWindowCountResponse(message.routing_id(),
1749 count));
1750}
1751
1752void AutomationProvider::GetConstrainedWindow(const IPC::Message& message,
1753 int handle, int index) {
1754 int cwindow_handle = 0;
1755 if (tab_tracker_->ContainsHandle(handle) && index >= 0) {
1756 NavigationController* nav_controller =
1757 tab_tracker_->GetResource(handle);
1758 TabContents* tab = nav_controller->active_contents();
[email protected]d5f942ba2008-09-26 19:30:341759 if (tab && index < static_cast<int>(tab->child_windows_.size())) {
1760 ConstrainedWindow* window = tab->child_windows_[index];
initial.commit09911bf2008-07-26 23:55:291761 cwindow_handle = cwindow_tracker_->Add(window);
1762 }
1763 }
1764
1765 Send(new AutomationMsg_ConstrainedWindowResponse(message.routing_id(),
1766 cwindow_handle));
1767}
1768
1769void AutomationProvider::GetConstrainedTitle(const IPC::Message& message,
1770 int handle) {
1771 int title_string_size = -1; // -1 is the error code
1772 std::wstring title;
1773 if (cwindow_tracker_->ContainsHandle(handle)) {
1774 ConstrainedWindow* window = cwindow_tracker_->GetResource(handle);
1775 title = window->GetWindowTitle();
1776 title_string_size = static_cast<int>(title.size());
1777 }
1778
1779 Send(new AutomationMsg_ConstrainedTitleResponse(message.routing_id(),
1780 title_string_size, title));
1781}
1782
1783void AutomationProvider::GetConstrainedWindowBounds(const IPC::Message& message,
1784 int handle) {
1785 bool exists = false;
1786 gfx::Rect rect(0, 0, 0, 0);
1787 if (cwindow_tracker_->ContainsHandle(handle)) {
1788 ConstrainedWindow* window = cwindow_tracker_->GetResource(handle);
1789 if (window) {
1790 exists = true;
1791 rect = window->GetCurrentBounds();
1792 }
1793 }
1794
1795 Send(new AutomationMsg_ConstrainedWindowBoundsResponse(message.routing_id(),
1796 exists, rect));
1797}
1798
1799void AutomationProvider::HandleFindInPageRequest(
1800 const IPC::Message& message, int handle, const std::wstring& find_request,
1801 int forward, int match_case) {
[email protected]5a52f162008-08-27 04:15:311802 NOTREACHED() << "This function has been deprecated."
1803 << "Please use HandleFindRequest instead.";
1804 Send(new AutomationMsg_FindInPageResponse(message.routing_id(), -1));
1805 return;
1806}
1807
1808void AutomationProvider::HandleFindRequest(const IPC::Message& message,
1809 int handle, const FindInPageRequest& request) {
initial.commit09911bf2008-07-26 23:55:291810 if (!tab_tracker_->ContainsHandle(handle)) {
1811 Send(new AutomationMsg_FindInPageResponse(message.routing_id(), -1));
1812 return;
1813 }
1814
1815 NavigationController* nav = tab_tracker_->GetResource(handle);
1816 TabContents* tab_contents = nav->active_contents();
1817
1818 find_in_page_observer_.reset(new
1819 FindInPageNotificationObserver(this, tab_contents, message.routing_id()));
1820
[email protected]edc28612008-08-14 20:23:361821 // The find in page dialog must be up for us to get the notification that the
[email protected]9e0534b2008-10-21 15:03:011822 // find was complete.
1823 WebContents* web_contents = tab_contents->AsWebContents();
1824 if (web_contents) {
[email protected]edc28612008-08-14 20:23:361825 NavigationController* tab = tab_tracker_->GetResource(handle);
1826 Browser* browser = Browser::GetBrowserForController(tab, NULL);
[email protected]9e0534b2008-10-21 15:03:011827 web_contents->view()->FindInPage(*browser, true, request.forward);
[email protected]edc28612008-08-14 20:23:361828
[email protected]9e0534b2008-10-21 15:03:011829 web_contents->render_view_host()->StartFinding(
1830 FindInPageNotificationObserver::kFindInPageRequestId,
1831 request.search_string, request.forward, request.match_case,
1832 request.find_next);
1833 }
initial.commit09911bf2008-07-26 23:55:291834}
1835
[email protected]5f8af2a2008-08-06 22:49:451836void AutomationProvider::HandleOpenFindInPageRequest(
1837 const IPC::Message& message, int handle) {
[email protected]20e93d12008-08-28 16:31:571838 NavigationController* tab = NULL;
1839 WebContents* web_contents = GetWebContentsForHandle(handle, &tab);
1840 if (web_contents) {
[email protected]5f8af2a2008-08-06 22:49:451841 Browser* browser = Browser::GetBrowserForController(tab, NULL);
[email protected]9e0534b2008-10-21 15:03:011842 web_contents->view()->FindInPage(*browser, false, false);
[email protected]5f8af2a2008-08-06 22:49:451843 }
1844}
1845
[email protected]20e93d12008-08-28 16:31:571846void AutomationProvider::GetFindWindowVisibility(const IPC::Message& message,
1847 int handle) {
[email protected]9e0534b2008-10-21 15:03:011848 gfx::Point position;
[email protected]20e93d12008-08-28 16:31:571849 bool visible = false;
1850 WebContents* web_contents = GetWebContentsForHandle(handle, NULL);
1851 if (web_contents)
[email protected]6fd1a4e22008-10-21 18:08:091852 web_contents->view()->GetFindBarWindowInfo(&position, &visible);
[email protected]20e93d12008-08-28 16:31:571853
1854 Send(new AutomationMsg_FindWindowVisibilityResponse(message.routing_id(),
1855 visible));
1856}
1857
1858void AutomationProvider::HandleFindWindowLocationRequest(
1859 const IPC::Message& message, int handle) {
[email protected]9e0534b2008-10-21 15:03:011860 gfx::Point position(0, 0);
1861 bool visible = false;
[email protected]20e93d12008-08-28 16:31:571862 WebContents* web_contents = GetWebContentsForHandle(handle, NULL);
1863 if (web_contents)
[email protected]6fd1a4e22008-10-21 18:08:091864 web_contents->view()->GetFindBarWindowInfo(&position, &visible);
[email protected]20e93d12008-08-28 16:31:571865
1866 Send(new AutomationMsg_FindWindowLocationResponse(message.routing_id(),
[email protected]9e0534b2008-10-21 15:03:011867 position.x(),
1868 position.y()));
[email protected]20e93d12008-08-28 16:31:571869}
1870
[email protected]c2cbeb92008-09-05 21:36:571871void AutomationProvider::GetBookmarkBarVisitility(const IPC::Message& message,
1872 int handle) {
1873 bool visible = false;
1874 bool animating = false;
1875
1876 void* iter = NULL;
1877 if (browser_tracker_->ContainsHandle(handle)) {
1878 Browser* browser = browser_tracker_->GetResource(handle);
1879 if (browser) {
1880 BookmarkBarView* bookmark_bar = browser->window()->GetBookmarkBarView();
1881 if (bookmark_bar) {
1882 animating = bookmark_bar->IsAnimating();
1883 visible = browser->window()->IsBookmarkBarVisible();
1884 }
1885 }
1886 }
1887
1888 Send(new AutomationMsg_BookmarkBarVisibilityResponse(message.routing_id(),
1889 visible, animating));
1890}
1891
initial.commit09911bf2008-07-26 23:55:291892void AutomationProvider::HandleInspectElementRequest(
1893 const IPC::Message& message, int handle, int x, int y) {
[email protected]20e93d12008-08-28 16:31:571894 WebContents* web_contents = GetWebContentsForHandle(handle, NULL);
1895 if (web_contents) {
[email protected]1f5af4442008-09-25 22:11:061896 web_contents->render_view_host()->InspectElementAt(x, y);
initial.commit09911bf2008-07-26 23:55:291897 inspect_element_routing_id_ = message.routing_id();
1898 } else {
1899 Send(new AutomationMsg_InspectElementResponse(message.routing_id(), -1));
1900 }
1901}
1902
1903void AutomationProvider::ReceivedInspectElementResponse(int num_resources) {
1904 Send(new AutomationMsg_InspectElementResponse(inspect_element_routing_id_,
1905 num_resources));
1906}
1907
1908// Helper class for making changes to the URLRequest ProtocolFactory on the
1909// IO thread.
1910class SetFilteredInetTask : public Task {
1911 public:
1912 explicit SetFilteredInetTask(bool enabled) : enabled_(enabled) { }
1913 virtual void Run() {
1914 if (enabled_) {
1915 URLRequestFilter::GetInstance()->ClearHandlers();
1916
1917 URLRequestFailedDnsJob::AddUITestUrls();
1918 URLRequestSlowDownloadJob::AddUITestUrls();
1919
1920 std::wstring root_http;
1921 PathService::Get(chrome::DIR_TEST_DATA, &root_http);
1922 URLRequestMockHTTPJob::AddUITestUrls(root_http);
1923 } else {
1924 // Revert to the default handlers.
1925 URLRequestFilter::GetInstance()->ClearHandlers();
1926 }
1927 }
1928 private:
1929 bool enabled_;
1930};
1931
1932void AutomationProvider::SetFilteredInet(const IPC::Message& message,
1933 bool enabled) {
1934 // Since this involves changing the URLRequest ProtocolFactory, we want to
1935 // run on the main thread.
1936 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
1937 new SetFilteredInetTask(enabled));
1938}
1939
1940void AutomationProvider::GetDownloadDirectory(const IPC::Message& message,
1941 int handle) {
1942 DLOG(INFO) << "Handling download directory request";
1943 std::wstring download_directory;
1944 if (tab_tracker_->ContainsHandle(handle)) {
1945 NavigationController* tab = tab_tracker_->GetResource(handle);
1946 DownloadManager* dlm = tab->profile()->GetDownloadManager();
1947 DCHECK(dlm);
1948 download_directory = dlm->download_path();
1949 }
1950
1951 Send(new AutomationMsg_DownloadDirectoryResponse(message.routing_id(),
1952 download_directory));
1953}
1954
1955void AutomationProvider::OpenNewBrowserWindow(int show_command) {
1956 // We may have no current browser windows open so don't rely on
1957 // asking an existing browser to execute the IDC_NEWWINDOW command
[email protected]15952e462008-11-14 00:29:051958 Browser* browser = Browser::Create(profile_);
1959 browser->AddBlankTab(true);
1960 if (show_command != SW_HIDE)
1961 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:291962}
1963
1964void AutomationProvider::GetWindowForBrowser(const IPC::Message& message,
1965 int browser_handle) {
1966 bool success = false;
1967 int window_handle = 0;
1968
1969 if (browser_tracker_->ContainsHandle(browser_handle)) {
1970 Browser* browser = browser_tracker_->GetResource(browser_handle);
[email protected]2d46c842008-11-14 19:24:311971 HWND hwnd = reinterpret_cast<HWND>(browser->window()->GetNativeHandle());
initial.commit09911bf2008-07-26 23:55:291972 // Add() returns the existing handle for the resource if any.
1973 window_handle = window_tracker_->Add(hwnd);
1974 success = true;
1975 }
1976 Send(new AutomationMsg_WindowForBrowserResponse(message.routing_id(),
1977 success, window_handle));
1978}
1979
1980void AutomationProvider::GetAutocompleteEditForBrowser(
1981 const IPC::Message& message,
1982 int browser_handle) {
1983 bool success = false;
1984 int autocomplete_edit_handle = 0;
1985
1986 if (browser_tracker_->ContainsHandle(browser_handle)) {
1987 Browser* browser = browser_tracker_->GetResource(browser_handle);
1988 LocationBarView* loc_bar_view = browser->GetLocationBarView();
[email protected]81c21222008-09-10 19:35:521989 AutocompleteEditView* edit_view = loc_bar_view->location_entry();
initial.commit09911bf2008-07-26 23:55:291990 // Add() returns the existing handle for the resource if any.
[email protected]81c21222008-09-10 19:35:521991 autocomplete_edit_handle = autocomplete_edit_tracker_->Add(edit_view);
initial.commit09911bf2008-07-26 23:55:291992 success = true;
1993 }
1994 Send(new AutomationMsg_AutocompleteEditForBrowserResponse(
1995 message.routing_id(), success, autocomplete_edit_handle));
1996}
1997
1998void AutomationProvider::GetBrowserForWindow(const IPC::Message& message,
1999 int window_handle) {
2000 bool success = false;
2001 int browser_handle = 0;
2002
2003 if (window_tracker_->ContainsHandle(window_handle)) {
2004 HWND window = window_tracker_->GetResource(window_handle);
2005 BrowserList::const_iterator iter = BrowserList::begin();
2006 Browser* browser = NULL;
2007 for (;iter != BrowserList::end(); ++iter) {
[email protected]2d46c842008-11-14 19:24:312008 HWND hwnd = reinterpret_cast<HWND>((*iter)->window()->GetNativeHandle());
2009 if (window == hwnd) {
initial.commit09911bf2008-07-26 23:55:292010 browser = *iter;
2011 break;
2012 }
2013 }
2014 if (browser) {
2015 // Add() returns the existing handle for the resource if any.
2016 browser_handle = browser_tracker_->Add(browser);
2017 success = true;
2018 }
2019 }
2020 Send(new AutomationMsg_BrowserForWindowResponse(message.routing_id(),
2021 success, browser_handle));
2022}
2023
2024void AutomationProvider::ShowInterstitialPage(const IPC::Message& message,
2025 int tab_handle,
2026 const std::string& html_text) {
2027 if (tab_tracker_->ContainsHandle(tab_handle)) {
2028 NavigationController* controller = tab_tracker_->GetResource(tab_handle);
2029 TabContents* tab_contents = controller->active_contents();
2030 if (tab_contents->type() == TAB_CONTENTS_WEB) {
2031 AddNavigationStatusListener(controller,
2032 new AutomationMsg_ShowInterstitialPageResponse(message.routing_id(),
2033 true),
2034 NULL);
2035 WebContents* web_contents = tab_contents->AsWebContents();
[email protected]cbab76d2008-10-13 22:42:472036 AutomationInterstitialPage* interstitial =
2037 new AutomationInterstitialPage(web_contents,
2038 GURL("about:interstitial"),
2039 html_text);
2040 web_contents->ShowInterstitialPage(interstitial);
initial.commit09911bf2008-07-26 23:55:292041 return;
2042 }
2043 }
2044 Send(new AutomationMsg_ShowInterstitialPageResponse(message.routing_id(),
2045 false));
2046}
2047
2048void AutomationProvider::HideInterstitialPage(const IPC::Message& message,
2049 int tab_handle) {
[email protected]20e93d12008-08-28 16:31:572050 WebContents* web_contents = GetWebContentsForHandle(tab_handle, NULL);
2051 if (web_contents) {
2052 web_contents->HideInterstitialPage(false, false);
2053 Send(new AutomationMsg_HideInterstitialPageResponse(message.routing_id(),
2054 true));
2055 return;
initial.commit09911bf2008-07-26 23:55:292056 }
2057 Send(new AutomationMsg_HideInterstitialPageResponse(message.routing_id(),
2058 false));
2059}
2060
2061void AutomationProvider::CloseTab(const IPC::Message& message,
2062 int tab_handle,
2063 bool wait_until_closed) {
2064 if (tab_tracker_->ContainsHandle(tab_handle)) {
2065 NavigationController* controller = tab_tracker_->GetResource(tab_handle);
2066 int index;
2067 Browser* browser = Browser::GetBrowserForController(controller, &index);
2068 DCHECK(browser);
2069 TabClosedNotificationObserver* observer =
2070 new TabClosedNotificationObserver(browser, this, message.routing_id(),
2071 wait_until_closed);
2072 browser->CloseContents(controller->active_contents());
2073 } else {
2074 Send(new AutomationMsg_CloseTabResponse(message.routing_id(), false));
2075 }
2076}
2077
2078void AutomationProvider::CloseBrowser(const IPC::Message& message,
2079 int browser_handle) {
2080 if (browser_tracker_->ContainsHandle(browser_handle)) {
2081 Browser* browser = browser_tracker_->GetResource(browser_handle);
2082 new BrowserClosedNotificationObserver(browser, this, message.routing_id());
[email protected]f3e99e32008-07-30 04:48:392083 browser->window()->Close();
initial.commit09911bf2008-07-26 23:55:292084 } else {
2085 NOTREACHED();
2086 }
2087}
2088
2089void AutomationProvider::CreateExternalTab(const IPC::Message& message) {
2090 int tab_handle = 0;
2091 HWND tab_container_window = NULL;
2092 ExternalTabContainer *external_tab_container =
2093 new ExternalTabContainer(this);
2094 external_tab_container->Init(profile_);
2095 TabContents* tab_contents = external_tab_container->tab_contents();
2096 if (tab_contents) {
2097 tab_handle = tab_tracker_->Add(tab_contents->controller());
2098 tab_container_window = *external_tab_container;
2099 }
2100 Send(new AutomationMsg_CreateExternalTabResponse(message.routing_id(),
2101 tab_container_window,
2102 tab_handle));
2103}
2104
2105void AutomationProvider::NavigateInExternalTab(const IPC::Message& message,
2106 int handle, const GURL& url) {
2107 bool status = false;
2108
2109 if (tab_tracker_->ContainsHandle(handle)) {
2110 NavigationController* tab = tab_tracker_->GetResource(handle);
[email protected]c0588052008-10-27 23:01:502111 tab->LoadURL(url, GURL(), PageTransition::TYPED);
initial.commit09911bf2008-07-26 23:55:292112 status = true;
2113 }
2114
2115 Send(new AutomationMsg_NavigateInExternalTabResponse(message.routing_id(),
2116 status));
2117}
2118
2119void AutomationProvider::SetAcceleratorsForTab(const IPC::Message& message,
2120 int handle,
2121 HACCEL accel_table,
2122 int accel_entry_count) {
2123 bool status = false;
2124 if (tab_tracker_->ContainsHandle(handle)) {
2125 NavigationController* tab = tab_tracker_->GetResource(handle);
2126 TabContents* tab_contents = tab->GetTabContents(TAB_CONTENTS_WEB);
2127 ExternalTabContainer* external_tab_container =
2128 ExternalTabContainer::GetContainerForTab(
2129 tab_contents->GetContainerHWND());
2130 // This call is only valid on an externally hosted tab
2131 if (external_tab_container) {
2132 external_tab_container->SetAccelerators(accel_table,
2133 accel_entry_count);
2134 status = true;
2135 }
2136 }
2137 Send(new AutomationMsg_SetAcceleratorsForTabResponse(message.routing_id(),
2138 status));
2139}
2140
2141void AutomationProvider::ProcessUnhandledAccelerator(
2142 const IPC::Message& message, int handle, const MSG& msg) {
2143 if (tab_tracker_->ContainsHandle(handle)) {
2144 NavigationController* tab = tab_tracker_->GetResource(handle);
2145 TabContents* tab_contents = tab->GetTabContents(TAB_CONTENTS_WEB);
2146 ExternalTabContainer* external_tab_container =
2147 ExternalTabContainer::GetContainerForTab(
2148 tab_contents->GetContainerHWND());
2149 // This call is only valid on an externally hosted tab
2150 if (external_tab_container) {
2151 external_tab_container->ProcessUnhandledAccelerator(msg);
2152 }
2153 }
2154 // This message expects no response.
2155}
2156
2157void AutomationProvider::WaitForTabToBeRestored(
2158 const IPC::Message& message,
2159 int tab_handle) {
2160 if (tab_tracker_->ContainsHandle(tab_handle)) {
2161 NavigationController* tab = tab_tracker_->GetResource(tab_handle);
2162 restore_tracker_.reset(
2163 new NavigationControllerRestoredObserver(this, tab,
2164 message.routing_id()));
2165 }
2166}
2167
2168void AutomationProvider::GetSecurityState(const IPC::Message& message,
2169 int handle) {
2170 if (tab_tracker_->ContainsHandle(handle)) {
2171 NavigationController* tab = tab_tracker_->GetResource(handle);
2172 NavigationEntry* entry = tab->GetActiveEntry();
2173 Send(new AutomationMsg_GetSecurityStateResponse(message.routing_id(), true,
[email protected]eb34392b2008-08-19 15:42:202174 entry->ssl().security_style(), entry->ssl().cert_status(),
2175 entry->ssl().content_status()));
initial.commit09911bf2008-07-26 23:55:292176 } else {
2177 Send(new AutomationMsg_GetSecurityStateResponse(message.routing_id(), false,
2178 SECURITY_STYLE_UNKNOWN,
2179 0, 0));
2180 }
2181}
2182
2183void AutomationProvider::GetPageType(const IPC::Message& message, int handle) {
2184 if (tab_tracker_->ContainsHandle(handle)) {
2185 NavigationController* tab = tab_tracker_->GetResource(handle);
2186 NavigationEntry* entry = tab->GetActiveEntry();
[email protected]1e5645ff2008-08-27 18:09:072187 NavigationEntry::PageType page_type = entry->page_type();
initial.commit09911bf2008-07-26 23:55:292188 // In order to return the proper result when an interstitial is shown and
2189 // no navigation entry were created for it we need to ask the WebContents.
2190 if (page_type == NavigationEntry::NORMAL_PAGE &&
2191 tab->active_contents()->AsWebContents() &&
[email protected]b6e09ac2008-08-12 16:11:092192 tab->active_contents()->AsWebContents()->showing_interstitial_page())
initial.commit09911bf2008-07-26 23:55:292193 page_type = NavigationEntry::INTERSTITIAL_PAGE;
2194
2195 Send(new AutomationMsg_GetPageTypeResponse(message.routing_id(), true,
2196 page_type));
2197 } else {
2198 Send(new AutomationMsg_GetPageTypeResponse(message.routing_id(), false,
2199 NavigationEntry::NORMAL_PAGE));
2200 }
2201}
2202
2203void AutomationProvider::ActionOnSSLBlockingPage(const IPC::Message& message,
2204 int handle, bool proceed) {
2205 if (tab_tracker_->ContainsHandle(handle)) {
2206 NavigationController* tab = tab_tracker_->GetResource(handle);
2207 NavigationEntry* entry = tab->GetActiveEntry();
[email protected]1e5645ff2008-08-27 18:09:072208 if (entry->page_type() == NavigationEntry::INTERSTITIAL_PAGE) {
initial.commit09911bf2008-07-26 23:55:292209 TabContents* tab_contents = tab->GetTabContents(TAB_CONTENTS_WEB);
[email protected]cbab76d2008-10-13 22:42:472210 InterstitialPage* ssl_blocking_page =
2211 InterstitialPage::GetInterstitialPage(tab_contents);
initial.commit09911bf2008-07-26 23:55:292212 if (ssl_blocking_page) {
2213 if (proceed) {
2214 AddNavigationStatusListener(tab,
2215 new AutomationMsg_ActionOnSSLBlockingPageResponse(
2216 message.routing_id(), true),
2217 new AutomationMsg_ActionOnSSLBlockingPageResponse(
2218 message.routing_id(), true));
2219 ssl_blocking_page->Proceed();
2220 return;
2221 }
2222 ssl_blocking_page->DontProceed();
2223 Send(new AutomationMsg_ActionOnSSLBlockingPageResponse(
2224 message.routing_id(), true));
2225 return;
2226 }
2227 }
2228 }
2229 // We failed.
2230 Send(new AutomationMsg_ActionOnSSLBlockingPageResponse(message.routing_id(),
2231 false));
2232}
2233
2234void AutomationProvider::BringBrowserToFront(const IPC::Message& message,
2235 int browser_handle) {
2236 if (browser_tracker_->ContainsHandle(browser_handle)) {
2237 Browser* browser = browser_tracker_->GetResource(browser_handle);
[email protected]cd7ffc22008-11-12 00:26:062238 browser->window()->Activate();
initial.commit09911bf2008-07-26 23:55:292239 Send(new AutomationMsg_BringBrowserToFrontResponse(message.routing_id(),
2240 true));
2241 } else {
2242 Send(new AutomationMsg_BringBrowserToFrontResponse(message.routing_id(),
2243 false));
2244 }
2245}
2246
2247void AutomationProvider::IsPageMenuCommandEnabled(const IPC::Message& message,
2248 int browser_handle,
2249 int message_num) {
2250 if (browser_tracker_->ContainsHandle(browser_handle)) {
2251 Browser* browser = browser_tracker_->GetResource(browser_handle);
2252 bool menu_item_enabled =
2253 browser->controller()->IsCommandEnabled(message_num);
2254 Send(new AutomationMsg_IsPageMenuCommandEnabledResponse(
2255 message.routing_id(), menu_item_enabled));
2256 } else {
2257 Send(new AutomationMsg_IsPageMenuCommandEnabledResponse(
2258 message.routing_id(), false));
2259 }
2260}
2261
2262void AutomationProvider::PrintNow(const IPC::Message& message, int tab_handle) {
[email protected]20e93d12008-08-28 16:31:572263 NavigationController* tab = NULL;
2264 WebContents* web_contents = GetWebContentsForHandle(tab_handle, &tab);
2265 if (web_contents) {
initial.commit09911bf2008-07-26 23:55:292266 FindAndActivateTab(tab);
[email protected]20e93d12008-08-28 16:31:572267 notification_observer_list_.AddObserver(
2268 new DocumentPrintedNotificationObserver(this, message.routing_id()));
2269 if (web_contents->PrintNow())
2270 return;
initial.commit09911bf2008-07-26 23:55:292271 }
2272 Send(new AutomationMsg_PrintNowResponse(message.routing_id(), false));
2273}
2274
2275void AutomationProvider::SavePage(const IPC::Message& message,
2276 int tab_handle,
2277 const std::wstring& file_name,
2278 const std::wstring& dir_path,
2279 int type) {
2280 if (!tab_tracker_->ContainsHandle(tab_handle)) {
2281 Send(new AutomationMsg_SavePageResponse(message.routing_id(), false));
2282 return;
2283 }
2284
2285 NavigationController* nav = tab_tracker_->GetResource(tab_handle);
2286 Browser* browser = FindAndActivateTab(nav);
2287 DCHECK(browser);
2288 if (!browser->IsCommandEnabled(IDC_SAVEPAGE)) {
2289 Send(new AutomationMsg_SavePageResponse(message.routing_id(), false));
2290 return;
2291 }
2292
2293 TabContents* tab_contents = nav->active_contents();
2294 if (tab_contents->type() != TAB_CONTENTS_WEB) {
2295 Send(new AutomationMsg_SavePageResponse(message.routing_id(), false));
2296 return;
2297 }
2298
2299 SavePackage::SavePackageType save_type =
2300 static_cast<SavePackage::SavePackageType>(type);
2301 DCHECK(save_type >= SavePackage::SAVE_AS_ONLY_HTML &&
2302 save_type <= SavePackage::SAVE_AS_COMPLETE_HTML);
2303 tab_contents->AsWebContents()->SavePage(file_name, dir_path, save_type);
2304
2305 Send(new AutomationMsg_SavePageResponse(
2306 message.routing_id(), true));
2307}
2308
2309void AutomationProvider::GetAutocompleteEditText(const IPC::Message& message,
2310 int autocomplete_edit_handle) {
2311 bool success = false;
2312 std::wstring text;
2313 if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
[email protected]81c21222008-09-10 19:35:522314 text = autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle)->
2315 GetText();
initial.commit09911bf2008-07-26 23:55:292316 success = true;
2317 }
2318 Send(new AutomationMsg_AutocompleteEditGetTextResponse(message.routing_id(),
2319 success, text));
2320}
2321
2322void AutomationProvider::SetAutocompleteEditText(const IPC::Message& message,
2323 int autocomplete_edit_handle,
2324 const std::wstring& text) {
2325 bool success = false;
2326 if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
[email protected]81c21222008-09-10 19:35:522327 autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle)->
2328 SetUserText(text);
initial.commit09911bf2008-07-26 23:55:292329 success = true;
2330 }
2331 Send(new AutomationMsg_AutocompleteEditSetTextResponse(
2332 message.routing_id(), success));
2333}
2334
2335void AutomationProvider::AutocompleteEditGetMatches(
2336 const IPC::Message& message,
2337 int autocomplete_edit_handle) {
2338 bool success = false;
2339 std::vector<AutocompleteMatchData> matches;
2340 if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
[email protected]8deeb952008-10-09 18:21:272341 const AutocompleteResult& result = autocomplete_edit_tracker_->
2342 GetResource(autocomplete_edit_handle)->model()->result();
2343 for (AutocompleteResult::const_iterator i = result.begin();
2344 i != result.end(); ++i)
initial.commit09911bf2008-07-26 23:55:292345 matches.push_back(AutocompleteMatchData(*i));
2346 success = true;
2347 }
2348 Send(new AutomationMsg_AutocompleteEditGetMatchesResponse(
2349 message.routing_id(), success, matches));
2350}
2351
2352void AutomationProvider::AutocompleteEditIsQueryInProgress(
2353 const IPC::Message& message,
2354 int autocomplete_edit_handle) {
2355 bool success = false;
2356 bool query_in_progress = false;
2357 if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
[email protected]81c21222008-09-10 19:35:522358 query_in_progress = autocomplete_edit_tracker_->
2359 GetResource(autocomplete_edit_handle)->model()->query_in_progress();
initial.commit09911bf2008-07-26 23:55:292360 success = true;
2361 }
2362 Send(new AutomationMsg_AutocompleteEditIsQueryInProgressResponse(
2363 message.routing_id(), success, query_in_progress));
2364}
2365
[email protected]18cb2572008-08-21 20:34:452366void AutomationProvider::OnMessageFromExternalHost(
2367 int handle, const std::string& target, const std::string& message) {
[email protected]fa83e762008-08-15 21:41:392368 if (tab_tracker_->ContainsHandle(handle)) {
2369 NavigationController* tab = tab_tracker_->GetResource(handle);
2370 if (!tab) {
2371 NOTREACHED();
2372 return;
2373 }
2374 TabContents* tab_contents = tab->GetTabContents(TAB_CONTENTS_WEB);
2375 if (!tab_contents) {
2376 NOTREACHED();
2377 return;
2378 }
2379
2380 WebContents* web_contents = tab_contents->AsWebContents();
2381 if (!web_contents) {
2382 NOTREACHED();
2383 return;
2384 }
2385
2386 RenderViewHost* view_host = web_contents->render_view_host();
2387 if (!view_host) {
2388 return;
2389 }
2390
[email protected]18cb2572008-08-21 20:34:452391 view_host->ForwardMessageFromExternalHost(target, message);
[email protected]fa83e762008-08-15 21:41:392392 }
2393}
2394
[email protected]20e93d12008-08-28 16:31:572395WebContents* AutomationProvider::GetWebContentsForHandle(
2396 int handle, NavigationController** tab) {
2397 WebContents* web_contents = NULL;
2398 if (tab_tracker_->ContainsHandle(handle)) {
2399 NavigationController* nav_controller = tab_tracker_->GetResource(handle);
2400 TabContents* tab_contents = nav_controller->active_contents();
2401 if (tab_contents && tab_contents->type() == TAB_CONTENTS_WEB) {
2402 web_contents = tab_contents->AsWebContents();
2403 if (tab)
2404 *tab = nav_controller;
2405 }
2406 }
2407 return web_contents;
2408}
2409
initial.commit09911bf2008-07-26 23:55:292410TestingAutomationProvider::TestingAutomationProvider(Profile* profile)
2411 : AutomationProvider(profile) {
2412 BrowserList::AddObserver(this);
2413 NotificationService::current()->AddObserver(this, NOTIFY_SESSION_END,
2414 NotificationService::AllSources());
2415}
2416
2417TestingAutomationProvider::~TestingAutomationProvider() {
2418 NotificationService::current()->RemoveObserver(this, NOTIFY_SESSION_END,
2419 NotificationService::AllSources());
2420 BrowserList::RemoveObserver(this);
2421}
2422
2423void TestingAutomationProvider::OnChannelError() {
2424 BrowserList::CloseAllBrowsers(true);
2425 AutomationProvider::OnChannelError();
2426}
2427
2428void TestingAutomationProvider::OnBrowserRemoving(const Browser* browser) {
2429 // For backwards compatibility with the testing automation interface, we
2430 // want the automation provider (and hence the process) to go away when the
2431 // last browser goes away.
2432 if (BrowserList::size() == 1) {
2433 // If you change this, update Observer for NOTIFY_SESSION_END below.
[email protected]295039bd2008-08-15 04:32:572434 MessageLoop::current()->PostTask(FROM_HERE,
2435 NewRunnableMethod(this, &TestingAutomationProvider::OnRemoveProvider));
initial.commit09911bf2008-07-26 23:55:292436 }
2437}
2438
2439void TestingAutomationProvider::Observe(NotificationType type,
2440 const NotificationSource& source,
2441 const NotificationDetails& details) {
2442 DCHECK(type == NOTIFY_SESSION_END);
2443 // OnBrowserRemoving does a ReleaseLater. When session end is received we exit
2444 // before the task runs resulting in this object not being deleted. This
2445 // Release balance out the Release scheduled by OnBrowserRemoving.
2446 Release();
2447}
[email protected]295039bd2008-08-15 04:32:572448
2449void TestingAutomationProvider::OnRemoveProvider() {
2450 AutomationProviderList::GetInstance()->RemoveProvider(this);
2451}
[email protected]8a3422c92008-09-24 17:42:422452
2453void AutomationProvider::GetSSLInfoBarCount(const IPC::Message& message,
2454 int handle) {
2455 int count = -1; // -1 means error.
2456 if (tab_tracker_->ContainsHandle(handle)) {
2457 NavigationController* nav_controller = tab_tracker_->GetResource(handle);
2458 if (nav_controller) {
2459 count = static_cast<int>(nav_controller->ssl_manager()->
2460 visible_info_bars_.size());
2461 }
2462 }
2463 Send(new AutomationMsg_GetSSLInfoBarCountResponse(message.routing_id(),
2464 count));
2465}
2466
2467void AutomationProvider::ClickSSLInfoBarLink(const IPC::Message& message,
2468 int handle,
2469 int info_bar_index,
2470 bool wait_for_navigation) {
2471 bool success = false;
2472 if (tab_tracker_->ContainsHandle(handle)) {
2473 NavigationController* nav_controller = tab_tracker_->GetResource(handle);
2474 if (nav_controller) {
2475 int count = static_cast<int>(nav_controller->ssl_manager()->
2476 visible_info_bars_.size());
2477 if (info_bar_index >= 0 && info_bar_index < count) {
2478 if (wait_for_navigation) {
2479 AddNavigationStatusListener(nav_controller,
2480 new AutomationMsg_ClickSSLInfoBarLinkResponse(
2481 message.routing_id(), true),
2482 new AutomationMsg_ClickSSLInfoBarLinkResponse(
2483 message.routing_id(), true));
2484 }
2485 SSLManager::SSLInfoBar* info_bar =
2486 nav_controller->ssl_manager()->visible_info_bars_.
2487 GetElementAt(info_bar_index);
2488 info_bar->LinkActivated(NULL, 0); // Parameters are not used.
2489 success = true;
2490 }
2491 }
2492 }
2493 if (!wait_for_navigation || !success)
2494 Send(new AutomationMsg_ClickSSLInfoBarLinkResponse(message.routing_id(),
2495 success));
2496}
2497
2498void AutomationProvider::GetLastNavigationTime(const IPC::Message& message,
2499 int handle) {
2500 Time time = tab_tracker_->GetLastNavigationTime(handle);
2501 Send(new AutomationMsg_GetLastNavigationTimeResponse(message.routing_id(),
2502 time.ToInternalValue()));
2503}
2504
2505void AutomationProvider::WaitForNavigation(const IPC::Message& message,
2506 int handle,
2507 int64 last_navigation_time) {
2508 NavigationController* controller = NULL;
2509 if (tab_tracker_->ContainsHandle(handle))
2510 controller = tab_tracker_->GetResource(handle);
2511
2512 Time time = tab_tracker_->GetLastNavigationTime(handle);
2513 if (time.ToInternalValue() > last_navigation_time || !controller) {
2514 Send(new AutomationMsg_WaitForNavigationResponse(message.routing_id(),
2515 controller != NULL));
2516 return;
2517 }
2518
2519 AddNavigationStatusListener(controller,
2520 new AutomationMsg_WaitForNavigationResponse(message.routing_id(),
2521 true),
2522 new AutomationMsg_WaitForNavigationResponse(message.routing_id(),
2523 true));
2524}
2525
2526void AutomationProvider::SetIntPreference(const IPC::Message& message,
2527 int handle,
2528 std::wstring name,
2529 int value) {
2530 bool success = false;
2531 if (browser_tracker_->ContainsHandle(handle)) {
2532 Browser* browser = browser_tracker_->GetResource(handle);
2533 browser->profile()->GetPrefs()->SetInteger(name.c_str(), value);
2534 success = true;
2535 }
2536 Send(new AutomationMsg_SetIntPreferenceResponse(message.routing_id(),
2537 success));
2538}