Home | History | Annotate | Download | only in content
      1 // Copyright 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 "components/dom_distiller/content/distiller_page_web_contents.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "components/dom_distiller/content/web_contents_main_frame_observer.h"
     11 #include "components/dom_distiller/core/distiller_page.h"
     12 #include "components/dom_distiller/core/dom_distiller_service.h"
     13 #include "content/public/browser/browser_context.h"
     14 #include "content/public/browser/navigation_controller.h"
     15 #include "content/public/browser/render_frame_host.h"
     16 #include "content/public/browser/render_view_host.h"
     17 #include "content/public/browser/web_contents.h"
     18 #include "content/public/browser/web_contents_observer.h"
     19 #include "url/gurl.h"
     20 
     21 namespace dom_distiller {
     22 
     23 SourcePageHandleWebContents::SourcePageHandleWebContents(
     24     scoped_ptr<content::WebContents> web_contents)
     25     : web_contents_(web_contents.Pass()) {
     26   DCHECK(web_contents_);
     27 }
     28 
     29 SourcePageHandleWebContents::~SourcePageHandleWebContents() {
     30 }
     31 
     32 scoped_ptr<content::WebContents> SourcePageHandleWebContents::GetWebContents() {
     33   return web_contents_.Pass();
     34 }
     35 
     36 scoped_ptr<DistillerPage> DistillerPageWebContentsFactory::CreateDistillerPage()
     37     const {
     38   DCHECK(browser_context_);
     39   return scoped_ptr<DistillerPage>(new DistillerPageWebContents(
     40       browser_context_, scoped_ptr<SourcePageHandleWebContents>()));
     41 }
     42 
     43 scoped_ptr<DistillerPage>
     44 DistillerPageWebContentsFactory::CreateDistillerPageWithHandle(
     45     scoped_ptr<SourcePageHandle> handle) const {
     46   DCHECK(browser_context_);
     47   scoped_ptr<SourcePageHandleWebContents> web_contents_handle =
     48       scoped_ptr<SourcePageHandleWebContents>(
     49           static_cast<SourcePageHandleWebContents*>(handle.release()));
     50   return scoped_ptr<DistillerPage>(new DistillerPageWebContents(
     51       browser_context_, web_contents_handle.Pass()));
     52 }
     53 
     54 DistillerPageWebContents::DistillerPageWebContents(
     55     content::BrowserContext* browser_context,
     56     scoped_ptr<SourcePageHandleWebContents> optional_web_contents_handle)
     57     : state_(IDLE), browser_context_(browser_context) {
     58   if (optional_web_contents_handle) {
     59     web_contents_ = optional_web_contents_handle->GetWebContents().Pass();
     60   }
     61 }
     62 
     63 DistillerPageWebContents::~DistillerPageWebContents() {
     64 }
     65 
     66 void DistillerPageWebContents::DistillPageImpl(const GURL& url,
     67                                                const std::string& script) {
     68   DCHECK(browser_context_);
     69   DCHECK(state_ == IDLE);
     70   state_ = LOADING_PAGE;
     71   script_ = script;
     72 
     73   if (web_contents_ && web_contents_->GetLastCommittedURL() == url) {
     74     WebContentsMainFrameObserver* main_frame_observer =
     75         WebContentsMainFrameObserver::FromWebContents(web_contents_.get());
     76     if (main_frame_observer && main_frame_observer->is_initialized()) {
     77       if (main_frame_observer->is_document_loaded_in_main_frame()) {
     78         // Main frame has already loaded for the current WebContents, so execute
     79         // JavaScript immediately.
     80         ExecuteJavaScript();
     81       } else {
     82         // Main frame document has not loaded yet, so wait until it has before
     83         // executing JavaScript. It will trigger after DocumentLoadedInFrame is
     84         // called for the main frame.
     85         content::WebContentsObserver::Observe(web_contents_.get());
     86       }
     87     } else {
     88       // The WebContentsMainFrameObserver has not been correctly initialized,
     89       // so fall back to creating a new WebContents.
     90       CreateNewWebContents(url);
     91     }
     92   } else {
     93     CreateNewWebContents(url);
     94   }
     95 }
     96 
     97 void DistillerPageWebContents::CreateNewWebContents(const GURL& url) {
     98   // Create new WebContents to use for distilling the content.
     99   content::WebContents::CreateParams create_params(browser_context_);
    100   create_params.initially_hidden = true;
    101   web_contents_.reset(content::WebContents::Create(create_params));
    102   DCHECK(web_contents_.get());
    103 
    104   // Start observing WebContents and load the requested URL.
    105   content::WebContentsObserver::Observe(web_contents_.get());
    106   content::NavigationController::LoadURLParams params(url);
    107   web_contents_->GetController().LoadURLWithParams(params);
    108 }
    109 
    110 void DistillerPageWebContents::DocumentLoadedInFrame(
    111     int64 frame_id,
    112     RenderViewHost* render_view_host) {
    113   if (frame_id == web_contents_->GetMainFrame()->GetRoutingID()) {
    114     ExecuteJavaScript();
    115   }
    116 }
    117 
    118 void DistillerPageWebContents::DidFailLoad(
    119     int64 frame_id,
    120     const GURL& validated_url,
    121     bool is_main_frame,
    122     int error_code,
    123     const base::string16& error_description,
    124     RenderViewHost* render_view_host) {
    125   if (is_main_frame) {
    126     content::WebContentsObserver::Observe(NULL);
    127     DCHECK(state_ == LOADING_PAGE || state_ == EXECUTING_JAVASCRIPT);
    128     state_ = PAGELOAD_FAILED;
    129     scoped_ptr<base::Value> empty(base::Value::CreateNullValue());
    130     OnWebContentsDistillationDone(GURL(), empty.get());
    131   }
    132 }
    133 
    134 void DistillerPageWebContents::ExecuteJavaScript() {
    135   content::RenderFrameHost* frame = web_contents_->GetMainFrame();
    136   DCHECK(frame);
    137   DCHECK_EQ(LOADING_PAGE, state_);
    138   state_ = EXECUTING_JAVASCRIPT;
    139   content::WebContentsObserver::Observe(NULL);
    140   web_contents_->Stop();
    141   DVLOG(1) << "Beginning distillation";
    142   frame->ExecuteJavaScript(
    143       base::UTF8ToUTF16(script_),
    144       base::Bind(&DistillerPageWebContents::OnWebContentsDistillationDone,
    145                  base::Unretained(this),
    146                  web_contents_->GetLastCommittedURL()));
    147 }
    148 
    149 void DistillerPageWebContents::OnWebContentsDistillationDone(
    150     const GURL& page_url,
    151     const base::Value* value) {
    152   DCHECK(state_ == PAGELOAD_FAILED || state_ == EXECUTING_JAVASCRIPT);
    153   state_ = IDLE;
    154   DistillerPage::OnDistillationDone(page_url, value);
    155 }
    156 
    157 }  // namespace dom_distiller
    158