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.
5 #include "components/dom_distiller/content/distiller_page_web_contents.h"
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"
21 namespace dom_distiller
{
23 SourcePageHandleWebContents::SourcePageHandleWebContents(
24 scoped_ptr
<content::WebContents
> web_contents
)
25 : web_contents_(web_contents
.Pass()) {
26 DCHECK(web_contents_
);
29 SourcePageHandleWebContents::~SourcePageHandleWebContents() {
32 scoped_ptr
<content::WebContents
> SourcePageHandleWebContents::GetWebContents() {
33 return web_contents_
.Pass();
36 scoped_ptr
<DistillerPage
> DistillerPageWebContentsFactory::CreateDistillerPage()
38 DCHECK(browser_context_
);
39 return scoped_ptr
<DistillerPage
>(new DistillerPageWebContents(
40 browser_context_
, scoped_ptr
<SourcePageHandleWebContents
>()));
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()));
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();
63 DistillerPageWebContents::~DistillerPageWebContents() {
66 void DistillerPageWebContents::DistillPageImpl(const GURL
& url
,
67 const std::string
& script
) {
68 DCHECK(browser_context_
);
69 DCHECK(state_
== IDLE
);
70 state_
= LOADING_PAGE
;
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.
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());
88 // The WebContentsMainFrameObserver has not been correctly initialized,
89 // so fall back to creating a new WebContents.
90 CreateNewWebContents(url
);
93 CreateNewWebContents(url
);
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());
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
);
110 void DistillerPageWebContents::DocumentLoadedInFrame(
112 RenderViewHost
* render_view_host
) {
113 if (frame_id
== web_contents_
->GetMainFrame()->GetRoutingID()) {
118 void DistillerPageWebContents::DidFailLoad(
120 const GURL
& validated_url
,
123 const base::string16
& error_description
,
124 RenderViewHost
* render_view_host
) {
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());
134 void DistillerPageWebContents::ExecuteJavaScript() {
135 content::RenderFrameHost
* frame
= web_contents_
->GetMainFrame();
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()));
149 void DistillerPageWebContents::OnWebContentsDistillationDone(
150 const GURL
& page_url
,
151 const base::Value
* value
) {
152 DCHECK(state_
== PAGELOAD_FAILED
|| state_
== EXECUTING_JAVASCRIPT
);
154 DistillerPage::OnDistillationDone(page_url
, value
);
157 } // namespace dom_distiller