Home | History | Annotate | Download | only in capture
      1 // Copyright (c) 2013 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 "content/browser/media/capture/web_contents_tracker.h"
      6 
      7 #include "base/message_loop/message_loop_proxy.h"
      8 #include "content/browser/frame_host/render_frame_host_impl.h"
      9 #include "content/browser/renderer_host/render_widget_host_impl.h"
     10 #include "content/public/browser/browser_thread.h"
     11 #include "content/public/browser/render_process_host.h"
     12 #include "content/public/browser/render_widget_host_view.h"
     13 #include "content/public/browser/web_contents.h"
     14 
     15 namespace content {
     16 
     17 WebContentsTracker::WebContentsTracker(bool track_fullscreen_rwh)
     18     : track_fullscreen_rwh_(track_fullscreen_rwh),
     19       last_target_(NULL) {}
     20 
     21 WebContentsTracker::~WebContentsTracker() {
     22   DCHECK(!web_contents()) << "BUG: Still observering!";
     23 }
     24 
     25 void WebContentsTracker::Start(int render_process_id, int main_render_frame_id,
     26                                const ChangeCallback& callback) {
     27   DCHECK(!message_loop_.get() || message_loop_->BelongsToCurrentThread());
     28 
     29   message_loop_ = base::MessageLoopProxy::current();
     30   DCHECK(message_loop_.get());
     31   callback_ = callback;
     32 
     33   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     34     StartObservingWebContents(render_process_id, main_render_frame_id);
     35   } else {
     36     BrowserThread::PostTask(
     37         BrowserThread::UI, FROM_HERE,
     38         base::Bind(&WebContentsTracker::StartObservingWebContents, this,
     39                    render_process_id, main_render_frame_id));
     40   }
     41 }
     42 
     43 void WebContentsTracker::Stop() {
     44   DCHECK(message_loop_->BelongsToCurrentThread());
     45 
     46   callback_.Reset();
     47 
     48   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     49     WebContentsObserver::Observe(NULL);
     50   } else {
     51     BrowserThread::PostTask(
     52         BrowserThread::UI, FROM_HERE,
     53         base::Bind(&WebContentsTracker::Observe, this,
     54                    static_cast<WebContents*>(NULL)));
     55   }
     56 }
     57 
     58 RenderWidgetHost* WebContentsTracker::GetTargetRenderWidgetHost() const {
     59   DCHECK_CURRENTLY_ON(BrowserThread::UI);
     60 
     61   WebContents* const wc = web_contents();
     62   if (!wc)
     63     return NULL;
     64 
     65   RenderWidgetHost* rwh = NULL;
     66   if (track_fullscreen_rwh_) {
     67     RenderWidgetHostView* const view = wc->GetFullscreenRenderWidgetHostView();
     68     if (view)
     69       rwh = view->GetRenderWidgetHost();
     70   }
     71   if (!rwh) {
     72     RenderFrameHostImpl* const rfh =
     73         static_cast<RenderFrameHostImpl*>(wc->GetMainFrame());
     74     if (rfh)
     75       rwh = rfh->GetRenderWidgetHost();
     76   }
     77 
     78   return rwh;
     79 }
     80 
     81 void WebContentsTracker::OnPossibleTargetChange(bool force_callback_run) {
     82   DCHECK_CURRENTLY_ON(BrowserThread::UI);
     83 
     84   RenderWidgetHost* const rwh = GetTargetRenderWidgetHost();
     85   if (rwh == last_target_ && !force_callback_run)
     86     return;
     87   DVLOG(1) << "Will report target change from RenderWidgetHost@" << last_target_
     88            << " to RenderWidgetHost@" << rwh;
     89   last_target_ = rwh;
     90 
     91   if (message_loop_->BelongsToCurrentThread()) {
     92     MaybeDoCallback(rwh);
     93   } else {
     94     message_loop_->PostTask(
     95         FROM_HERE,
     96         base::Bind(&WebContentsTracker::MaybeDoCallback, this, rwh));
     97   }
     98 }
     99 
    100 void WebContentsTracker::MaybeDoCallback(RenderWidgetHost* rwh) {
    101   DCHECK(message_loop_->BelongsToCurrentThread());
    102 
    103   if (!callback_.is_null())
    104     callback_.Run(rwh);
    105 }
    106 
    107 void WebContentsTracker::StartObservingWebContents(int render_process_id,
    108                                                    int main_render_frame_id) {
    109   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    110 
    111   Observe(WebContents::FromRenderFrameHost(RenderFrameHost::FromID(
    112       render_process_id, main_render_frame_id)));
    113   DVLOG_IF(1, !web_contents())
    114       << "Could not find WebContents associated with main RenderFrameHost "
    115       << "referenced by render_process_id=" << render_process_id
    116       << ", routing_id=" << main_render_frame_id;
    117 
    118   OnPossibleTargetChange(true);
    119 }
    120 
    121 void WebContentsTracker::RenderFrameDeleted(
    122     RenderFrameHost* render_frame_host) {
    123   OnPossibleTargetChange(false);
    124 }
    125 
    126 void WebContentsTracker::RenderFrameHostChanged(RenderFrameHost* old_host,
    127                                                 RenderFrameHost* new_host) {
    128   OnPossibleTargetChange(false);
    129 }
    130 
    131 void WebContentsTracker::WebContentsDestroyed() {
    132   Observe(NULL);
    133   OnPossibleTargetChange(false);
    134 }
    135 
    136 void WebContentsTracker::DidShowFullscreenWidget(int routing_id) {
    137   OnPossibleTargetChange(false);
    138 }
    139 
    140 void WebContentsTracker::DidDestroyFullscreenWidget(int routing_id) {
    141   OnPossibleTargetChange(false);
    142 }
    143 
    144 }  // namespace content
    145