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