Home | History | Annotate | Download | only in automation
      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 
     15 TabEventObserver::TabEventObserver() { }
     16 
     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 
     24 void TabEventObserver::StartObserving(AutomationTabHelper* tab_helper) {
     25   tab_helper->AddObserver(this);
     26   event_sources_.push_back(tab_helper->AsWeakPtr());
     27 }
     28 
     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 
     37 AutomationTabHelper::AutomationTabHelper(TabContents* tab_contents)
     38     : TabContentsObserver(tab_contents),
     39       is_loading_(false) {
     40 }
     41 
     42 AutomationTabHelper::~AutomationTabHelper() { }
     43 
     44 void AutomationTabHelper::AddObserver(TabEventObserver* observer) {
     45   observers_.AddObserver(observer);
     46 }
     47 
     48 void AutomationTabHelper::RemoveObserver(TabEventObserver* observer) {
     49   observers_.RemoveObserver(observer);
     50 }
     51 
     52 bool AutomationTabHelper::has_pending_loads() const {
     53   return is_loading_ || !pending_client_redirects_.empty();
     54 }
     55 
     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 
     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 
     84 void AutomationTabHelper::RenderViewGone() {
     85   OnTabOrRenderViewDestroyed(tab_contents());
     86 }
     87 
     88 void AutomationTabHelper::TabContentsDestroyed(TabContents* tab_contents) {
     89   OnTabOrRenderViewDestroyed(tab_contents);
     90 }
     91 
     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 
    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 
    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 
    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