distiller_page_web_contents.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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    content::RenderFrameHost* render_frame_host) {
112  if (render_frame_host == web_contents_->GetMainFrame()) {
113    ExecuteJavaScript();
114  }
115}
116
117void DistillerPageWebContents::DidFailLoad(
118    content::RenderFrameHost* render_frame_host,
119    const GURL& validated_url,
120    int error_code,
121    const base::string16& error_description) {
122  if (!render_frame_host->GetParent()) {
123    content::WebContentsObserver::Observe(NULL);
124    DCHECK(state_ == LOADING_PAGE || state_ == EXECUTING_JAVASCRIPT);
125    state_ = PAGELOAD_FAILED;
126    scoped_ptr<base::Value> empty(base::Value::CreateNullValue());
127    OnWebContentsDistillationDone(GURL(), empty.get());
128  }
129}
130
131void DistillerPageWebContents::ExecuteJavaScript() {
132  content::RenderFrameHost* frame = web_contents_->GetMainFrame();
133  DCHECK(frame);
134  DCHECK_EQ(LOADING_PAGE, state_);
135  state_ = EXECUTING_JAVASCRIPT;
136  content::WebContentsObserver::Observe(NULL);
137  web_contents_->Stop();
138  DVLOG(1) << "Beginning distillation";
139  frame->ExecuteJavaScript(
140      base::UTF8ToUTF16(script_),
141      base::Bind(&DistillerPageWebContents::OnWebContentsDistillationDone,
142                 base::Unretained(this),
143                 web_contents_->GetLastCommittedURL()));
144}
145
146void DistillerPageWebContents::OnWebContentsDistillationDone(
147    const GURL& page_url,
148    const base::Value* value) {
149  DCHECK(state_ == PAGELOAD_FAILED || state_ == EXECUTING_JAVASCRIPT);
150  state_ = IDLE;
151  DistillerPage::OnDistillationDone(page_url, value);
152}
153
154}  // namespace dom_distiller
155