• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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.
4 
5 #include "chrome/browser/automation/automation_tab_helper.h"
6 
7 #include <algorithm>
8 
9 #include "content/browser/tab_contents/navigation_controller.h"
10 #include "content/browser/tab_contents/tab_contents.h"
11 #include "chrome/common/automation_messages.h"
12 #include "ipc/ipc_message.h"
13 #include "ipc/ipc_message_macros.h"
14 
TabEventObserver()15 TabEventObserver::TabEventObserver() { }
16 
~TabEventObserver()17 TabEventObserver::~TabEventObserver() {
18   for (size_t i = 0; i < event_sources_.size(); ++i) {
19     if (event_sources_[i])
20       event_sources_[i]->RemoveObserver(this);
21   }
22 }
23 
StartObserving(AutomationTabHelper * tab_helper)24 void TabEventObserver::StartObserving(AutomationTabHelper* tab_helper) {
25   tab_helper->AddObserver(this);
26   event_sources_.push_back(tab_helper->AsWeakPtr());
27 }
28 
StopObserving(AutomationTabHelper * tab_helper)29 void TabEventObserver::StopObserving(AutomationTabHelper* tab_helper) {
30   tab_helper->RemoveObserver(this);
31   EventSourceVector::iterator iter =
32       std::find(event_sources_.begin(), event_sources_.end(), tab_helper);
33   if (iter != event_sources_.end())
34     event_sources_.erase(iter);
35 }
36 
AutomationTabHelper(TabContents * tab_contents)37 AutomationTabHelper::AutomationTabHelper(TabContents* tab_contents)
38     : TabContentsObserver(tab_contents),
39       is_loading_(false) {
40 }
41 
~AutomationTabHelper()42 AutomationTabHelper::~AutomationTabHelper() { }
43 
AddObserver(TabEventObserver * observer)44 void AutomationTabHelper::AddObserver(TabEventObserver* observer) {
45   observers_.AddObserver(observer);
46 }
47 
RemoveObserver(TabEventObserver * observer)48 void AutomationTabHelper::RemoveObserver(TabEventObserver* observer) {
49   observers_.RemoveObserver(observer);
50 }
51 
has_pending_loads() const52 bool AutomationTabHelper::has_pending_loads() const {
53   return is_loading_ || !pending_client_redirects_.empty();
54 }
55 
DidStartLoading()56 void AutomationTabHelper::DidStartLoading() {
57   if (is_loading_) {
58     // DidStartLoading is often called twice. Once when the renderer sends a
59     // load start message, and once when the browser calls it directly as a
60     // result of some user-initiated navigation.
61     VLOG(1) << "Received DidStartLoading while loading already started.";
62     return;
63   }
64   bool had_pending_loads = has_pending_loads();
65   is_loading_ = true;
66   if (!had_pending_loads) {
67     FOR_EACH_OBSERVER(TabEventObserver, observers_,
68                       OnFirstPendingLoad(tab_contents()));
69   }
70 }
71 
DidStopLoading()72 void AutomationTabHelper::DidStopLoading() {
73   if (!is_loading_) {
74     LOG(WARNING) << "Received DidStopLoading while loading already stopped.";
75     return;
76   }
77   is_loading_ = false;
78   if (!has_pending_loads()) {
79     FOR_EACH_OBSERVER(TabEventObserver, observers_,
80                       OnNoMorePendingLoads(tab_contents()));
81   }
82 }
83 
RenderViewGone()84 void AutomationTabHelper::RenderViewGone() {
85   OnTabOrRenderViewDestroyed(tab_contents());
86 }
87 
TabContentsDestroyed(TabContents * tab_contents)88 void AutomationTabHelper::TabContentsDestroyed(TabContents* tab_contents) {
89   OnTabOrRenderViewDestroyed(tab_contents);
90 }
91 
OnTabOrRenderViewDestroyed(TabContents * tab_contents)92 void AutomationTabHelper::OnTabOrRenderViewDestroyed(
93     TabContents* tab_contents) {
94   if (has_pending_loads()) {
95     is_loading_ = false;
96     pending_client_redirects_.clear();
97     FOR_EACH_OBSERVER(TabEventObserver, observers_,
98                       OnNoMorePendingLoads(tab_contents));
99   }
100 }
101 
OnMessageReceived(const IPC::Message & message)102 bool AutomationTabHelper::OnMessageReceived(const IPC::Message& message) {
103   bool handled = true;
104   bool msg_is_good = true;
105   IPC_BEGIN_MESSAGE_MAP_EX(AutomationTabHelper, message, msg_is_good)
106     IPC_MESSAGE_HANDLER(AutomationMsg_WillPerformClientRedirect,
107                         OnWillPerformClientRedirect)
108     IPC_MESSAGE_HANDLER(AutomationMsg_DidCompleteOrCancelClientRedirect,
109                         OnDidCompleteOrCancelClientRedirect)
110     IPC_MESSAGE_UNHANDLED(handled = false)
111   IPC_END_MESSAGE_MAP_EX()
112   if (!msg_is_good) {
113     LOG(ERROR) << "Failed to deserialize an IPC message";
114   }
115   return handled;
116 }
117 
OnWillPerformClientRedirect(int64 frame_id,double delay_seconds)118 void AutomationTabHelper::OnWillPerformClientRedirect(
119     int64 frame_id, double delay_seconds) {
120   // Ignore all non-zero delays.
121   // TODO(kkania): Handle timed redirects.
122   if (delay_seconds > 0) {
123     LOG(WARNING) << "Ignoring timed redirect scheduled for " << delay_seconds
124                  << " seconds later. Will not wait for the redirect to occur";
125     return;
126   }
127 
128   bool first_pending_load = !has_pending_loads();
129   pending_client_redirects_.insert(frame_id);
130   if (first_pending_load) {
131     FOR_EACH_OBSERVER(TabEventObserver, observers_,
132                       OnFirstPendingLoad(tab_contents()));
133   }
134 }
135 
OnDidCompleteOrCancelClientRedirect(int64 frame_id)136 void AutomationTabHelper::OnDidCompleteOrCancelClientRedirect(int64 frame_id) {
137   std::set<int64>::iterator iter =
138       pending_client_redirects_.find(frame_id);
139   // It is possible that we did not track the redirect becasue it had a non-zero
140   // delay. See the comment in |OnWillPerformClientRedirect|.
141   if (iter != pending_client_redirects_.end()) {
142     pending_client_redirects_.erase(iter);
143     if (!has_pending_loads()) {
144       FOR_EACH_OBSERVER(TabEventObserver, observers_,
145                         OnNoMorePendingLoads(tab_contents()));
146     }
147   }
148 }
149