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 21namespace dom_distiller { 22 23SourcePageHandleWebContents::SourcePageHandleWebContents( 24 scoped_ptr<content::WebContents> web_contents) 25 : web_contents_(web_contents.Pass()) { 26 DCHECK(web_contents_); 27} 28 29SourcePageHandleWebContents::~SourcePageHandleWebContents() { 30} 31 32scoped_ptr<content::WebContents> SourcePageHandleWebContents::GetWebContents() { 33 return web_contents_.Pass(); 34} 35 36scoped_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 43scoped_ptr<DistillerPage> 44DistillerPageWebContentsFactory::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 54DistillerPageWebContents::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 63DistillerPageWebContents::~DistillerPageWebContents() { 64} 65 66void 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 97void 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 110void DistillerPageWebContents::DocumentLoadedInFrame( 111 int64 frame_id, 112 RenderViewHost* render_view_host) { 113 if (frame_id == web_contents_->GetMainFrame()->GetRoutingID()) { 114 ExecuteJavaScript(); 115 } 116} 117 118void 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 134void 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 149void 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