summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authornyquist@chromium.org <nyquist@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-28 01:24:12 +0000
committernyquist@chromium.org <nyquist@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-28 01:24:12 +0000
commitd289bd7f55ca3d3f647a0a2c6049115e0125b5df (patch)
tree87d1b6c64b2d775a5bf07fed9cb2e1fed94a76b1 /components
parentd2b20dd909486a7c78a76ddf0d0d13410c969ffe (diff)
downloadchromium_src-d289bd7f55ca3d3f647a0a2c6049115e0125b5df.zip
chromium_src-d289bd7f55ca3d3f647a0a2c6049115e0125b5df.tar.gz
chromium_src-d289bd7f55ca3d3f647a0a2c6049115e0125b5df.tar.bz2
Add support for distilling current WebContents
This CL adds the utilities needed for using the current WebContents when distilling web pages. BUG=361939 Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=272611 Review URL: https://codereview.chromium.org/266073003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@273101 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
-rw-r--r--components/dom_distiller.gypi2
-rw-r--r--components/dom_distiller/content/distiller_page_web_contents.cc71
-rw-r--r--components/dom_distiller/content/distiller_page_web_contents.h25
-rw-r--r--components/dom_distiller/content/distiller_page_web_contents_browsertest.cc201
-rw-r--r--components/dom_distiller/content/web_contents_main_frame_observer.cc61
-rw-r--r--components/dom_distiller/content/web_contents_main_frame_observer.h63
-rw-r--r--components/dom_distiller/core/distiller_page.h11
-rw-r--r--components/dom_distiller/core/dom_distiller_service.cc10
-rw-r--r--components/dom_distiller/core/dom_distiller_service.h4
-rw-r--r--components/dom_distiller/core/fake_distiller_page.h4
-rw-r--r--components/dom_distiller/core/viewer_unittest.cc4
11 files changed, 435 insertions, 21 deletions
diff --git a/components/dom_distiller.gypi b/components/dom_distiller.gypi
index 092a26a..cc7bae5 100644
--- a/components/dom_distiller.gypi
+++ b/components/dom_distiller.gypi
@@ -156,6 +156,8 @@
'dom_distiller/content/distiller_page_web_contents.h',
'dom_distiller/content/dom_distiller_viewer_source.cc',
'dom_distiller/content/dom_distiller_viewer_source.h',
+ 'dom_distiller/content/web_contents_main_frame_observer.cc',
+ 'dom_distiller/content/web_contents_main_frame_observer.h',
],
},
],
diff --git a/components/dom_distiller/content/distiller_page_web_contents.cc b/components/dom_distiller/content/distiller_page_web_contents.cc
index baa9977..527c0eb 100644
--- a/components/dom_distiller/content/distiller_page_web_contents.cc
+++ b/components/dom_distiller/content/distiller_page_web_contents.cc
@@ -7,7 +7,9 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/dom_distiller/content/web_contents_main_frame_observer.h"
#include "components/dom_distiller/core/distiller_page.h"
+#include "components/dom_distiller/core/dom_distiller_service.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/render_frame_host.h"
@@ -18,18 +20,48 @@
namespace dom_distiller {
+SourcePageHandleWebContents::SourcePageHandleWebContents(
+ scoped_ptr<content::WebContents> web_contents)
+ : web_contents_(web_contents.Pass()) {
+ DCHECK(web_contents_);
+}
+
+SourcePageHandleWebContents::~SourcePageHandleWebContents() {
+}
+
+scoped_ptr<content::WebContents> SourcePageHandleWebContents::GetWebContents() {
+ return web_contents_.Pass();
+}
+
scoped_ptr<DistillerPage> DistillerPageWebContentsFactory::CreateDistillerPage()
const {
DCHECK(browser_context_);
- return scoped_ptr<DistillerPage>(
- new DistillerPageWebContents(browser_context_));
+ return scoped_ptr<DistillerPage>(new DistillerPageWebContents(
+ browser_context_, scoped_ptr<SourcePageHandleWebContents>()));
+}
+
+scoped_ptr<DistillerPage>
+DistillerPageWebContentsFactory::CreateDistillerPageWithHandle(
+ scoped_ptr<SourcePageHandle> handle) const {
+ DCHECK(browser_context_);
+ scoped_ptr<SourcePageHandleWebContents> web_contents_handle =
+ scoped_ptr<SourcePageHandleWebContents>(
+ static_cast<SourcePageHandleWebContents*>(handle.release()));
+ return scoped_ptr<DistillerPage>(new DistillerPageWebContents(
+ browser_context_, web_contents_handle.Pass()));
}
DistillerPageWebContents::DistillerPageWebContents(
- content::BrowserContext* browser_context)
- : state_(IDLE), browser_context_(browser_context) {}
+ content::BrowserContext* browser_context,
+ scoped_ptr<SourcePageHandleWebContents> optional_web_contents_handle)
+ : state_(IDLE), browser_context_(browser_context) {
+ if (optional_web_contents_handle) {
+ web_contents_ = optional_web_contents_handle->GetWebContents().Pass();
+ }
+}
-DistillerPageWebContents::~DistillerPageWebContents() {}
+DistillerPageWebContents::~DistillerPageWebContents() {
+}
void DistillerPageWebContents::DistillPageImpl(const GURL& url,
const std::string& script) {
@@ -38,6 +70,31 @@ void DistillerPageWebContents::DistillPageImpl(const GURL& url,
state_ = LOADING_PAGE;
script_ = script;
+ if (web_contents_ && web_contents_->GetLastCommittedURL() == url) {
+ WebContentsMainFrameObserver* main_frame_observer =
+ WebContentsMainFrameObserver::FromWebContents(web_contents_.get());
+ if (main_frame_observer && main_frame_observer->is_initialized()) {
+ if (main_frame_observer->is_document_loaded_in_main_frame()) {
+ // Main frame has already loaded for the current WebContents, so execute
+ // JavaScript immediately.
+ ExecuteJavaScript();
+ } else {
+ // Main frame document has not loaded yet, so wait until it has before
+ // executing JavaScript. It will trigger after DocumentLoadedInFrame is
+ // called for the main frame.
+ content::WebContentsObserver::Observe(web_contents_.get());
+ }
+ } else {
+ // The WebContentsMainFrameObserver has not been correctly initialized,
+ // so fall back to creating a new WebContents.
+ CreateNewWebContents(url);
+ }
+ } else {
+ CreateNewWebContents(url);
+ }
+}
+
+void DistillerPageWebContents::CreateNewWebContents(const GURL& url) {
// Create new WebContents to use for distilling the content.
content::WebContents::CreateParams create_params(browser_context_);
create_params.initially_hidden = true;
@@ -54,8 +111,6 @@ void DistillerPageWebContents::DocumentLoadedInFrame(
int64 frame_id,
RenderViewHost* render_view_host) {
if (frame_id == web_contents_->GetMainFrame()->GetRoutingID()) {
- content::WebContentsObserver::Observe(NULL);
- web_contents_->Stop();
ExecuteJavaScript();
}
}
@@ -81,6 +136,8 @@ void DistillerPageWebContents::ExecuteJavaScript() {
DCHECK(frame);
DCHECK_EQ(LOADING_PAGE, state_);
state_ = EXECUTING_JAVASCRIPT;
+ content::WebContentsObserver::Observe(NULL);
+ web_contents_->Stop();
DVLOG(1) << "Beginning distillation";
frame->ExecuteJavaScript(
base::UTF8ToUTF16(script_),
diff --git a/components/dom_distiller/content/distiller_page_web_contents.h b/components/dom_distiller/content/distiller_page_web_contents.h
index 52509f5..aed9789 100644
--- a/components/dom_distiller/content/distiller_page_web_contents.h
+++ b/components/dom_distiller/content/distiller_page_web_contents.h
@@ -21,7 +21,18 @@ using content::RenderViewHost;
namespace dom_distiller {
-class DistillerContext;
+class SourcePageHandleWebContents : public SourcePageHandle {
+ public:
+ explicit SourcePageHandleWebContents(
+ scoped_ptr<content::WebContents> web_contents);
+ virtual ~SourcePageHandleWebContents();
+
+ scoped_ptr<content::WebContents> GetWebContents();
+
+ private:
+ // The WebContents this class owns.
+ scoped_ptr<content::WebContents> web_contents_;
+};
class DistillerPageWebContentsFactory : public DistillerPageFactory {
public:
@@ -31,6 +42,8 @@ class DistillerPageWebContentsFactory : public DistillerPageFactory {
virtual ~DistillerPageWebContentsFactory() {}
virtual scoped_ptr<DistillerPage> CreateDistillerPage() const OVERRIDE;
+ virtual scoped_ptr<DistillerPage> CreateDistillerPageWithHandle(
+ scoped_ptr<SourcePageHandle> handle) const OVERRIDE;
private:
content::BrowserContext* browser_context_;
@@ -39,7 +52,9 @@ class DistillerPageWebContentsFactory : public DistillerPageFactory {
class DistillerPageWebContents : public DistillerPage,
public content::WebContentsObserver {
public:
- DistillerPageWebContents(content::BrowserContext* browser_context);
+ DistillerPageWebContents(
+ content::BrowserContext* browser_context,
+ scoped_ptr<SourcePageHandleWebContents> optional_web_contents_handle);
virtual ~DistillerPageWebContents();
// content::WebContentsObserver implementation.
@@ -58,6 +73,8 @@ class DistillerPageWebContents : public DistillerPage,
const std::string& script) OVERRIDE;
private:
+ friend class TestDistillerPageWebContents;
+
enum State {
// The page distiller is idle.
IDLE,
@@ -70,6 +87,10 @@ class DistillerPageWebContents : public DistillerPage,
EXECUTING_JAVASCRIPT
};
+ // Creates a new WebContents, adds |this| as an observer, and loads the
+ // |url|.
+ virtual void CreateNewWebContents(const GURL& url);
+
// Injects and executes JavaScript in the context of a loaded page. This
// must only be called after the page has successfully loaded.
void ExecuteJavaScript();
diff --git a/components/dom_distiller/content/distiller_page_web_contents_browsertest.cc b/components/dom_distiller/content/distiller_page_web_contents_browsertest.cc
index 5d1cd2a..e319097 100644
--- a/components/dom_distiller/content/distiller_page_web_contents_browsertest.cc
+++ b/components/dom_distiller/content/distiller_page_web_contents_browsertest.cc
@@ -7,8 +7,12 @@
#include "base/run_loop.h"
#include "base/values.h"
#include "components/dom_distiller/content/distiller_page_web_contents.h"
+#include "components/dom_distiller/content/web_contents_main_frame_observer.h"
#include "components/dom_distiller/core/distiller_page.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/content_browser_test.h"
#include "content/shell/browser/shell.h"
#include "grit/component_resources.h"
@@ -23,6 +27,8 @@ using testing::Not;
namespace dom_distiller {
+const char* kSimpleArticlePath = "/simple_article.html";
+
class DistillerPageWebContentsTest : public ContentBrowserTest {
public:
// ContentBrowserTest:
@@ -66,18 +72,108 @@ class DistillerPageWebContentsTest : public ContentBrowserTest {
}
protected:
+ void RunUseCurrentWebContentsTest(const std::string& url,
+ bool expect_new_web_contents,
+ bool setup_main_frame_observer,
+ bool wait_for_document_loaded);
+
DistillerPageWebContents* distiller_page_;
base::Closure quit_closure_;
scoped_ptr<DistilledPageInfo> page_info_;
};
+// Use this class to be able to leak the WebContents, which is needed for when
+// the current WebContents is used for distillation.
+class TestDistillerPageWebContents : public DistillerPageWebContents {
+ public:
+ TestDistillerPageWebContents(
+ content::BrowserContext* browser_context,
+ scoped_ptr<SourcePageHandleWebContents> optional_web_contents_handle,
+ bool expect_new_web_contents)
+ : DistillerPageWebContents(browser_context,
+ optional_web_contents_handle.Pass()),
+ expect_new_web_contents_(expect_new_web_contents),
+ new_web_contents_created_(false) {}
+
+ virtual void CreateNewWebContents(const GURL& url) OVERRIDE {
+ ASSERT_EQ(true, expect_new_web_contents_);
+ new_web_contents_created_ = true;
+ // DistillerPageWebContents::CreateNewWebContents resets the scoped_ptr to
+ // the WebContents, so intentionally leak WebContents here, since it is
+ // owned by the shell.
+ content::WebContents* web_contents = web_contents_.release();
+ web_contents->GetLastCommittedURL();
+ DistillerPageWebContents::CreateNewWebContents(url);
+ }
+
+ virtual ~TestDistillerPageWebContents() {
+ if (!expect_new_web_contents_) {
+ // Intentionally leaking WebContents, since it is owned by the shell.
+ content::WebContents* web_contents = web_contents_.release();
+ web_contents->GetLastCommittedURL();
+ }
+ }
+
+ bool new_web_contents_created() { return new_web_contents_created_; }
+
+ private:
+ bool expect_new_web_contents_;
+ bool new_web_contents_created_;
+};
+
+// Helper class to know how far in the loading process the current WebContents
+// has come. It will call the callback either after
+// DidCommitProvisionalLoadForFrame or DocumentLoadedInFrame is called for the
+// main frame, based on the value of |wait_for_document_loaded|.
+class WebContentsMainFrameHelper : public content::WebContentsObserver {
+ public:
+ WebContentsMainFrameHelper(content::WebContents* web_contents,
+ const base::Closure& callback,
+ bool wait_for_document_loaded)
+ : web_contents_(web_contents),
+ callback_(callback),
+ wait_for_document_loaded_(wait_for_document_loaded) {
+ content::WebContentsObserver::Observe(web_contents);
+ }
+
+ virtual void DidCommitProvisionalLoadForFrame(
+ int64 frame_id,
+ const base::string16& frame_unique_name,
+ bool is_main_frame,
+ const GURL& url,
+ content::PageTransition transition_type,
+ content::RenderViewHost* render_view_host) OVERRIDE {
+ if (wait_for_document_loaded_)
+ return;
+ if (is_main_frame)
+ callback_.Run();
+ }
+
+ virtual void DocumentLoadedInFrame(
+ int64 frame_id,
+ content::RenderViewHost* render_view_host) OVERRIDE {
+ if (wait_for_document_loaded_) {
+ if (web_contents_ &&
+ frame_id == web_contents_->GetMainFrame()->GetRoutingID()) {
+ callback_.Run();
+ }
+ }
+ }
+
+ private:
+ content::WebContents* web_contents_;
+ base::Closure callback_;
+ bool wait_for_document_loaded_;
+};
+
IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, BasicDistillationWorks) {
DistillerPageWebContents distiller_page(
- shell()->web_contents()->GetBrowserContext());
+ shell()->web_contents()->GetBrowserContext(),
+ scoped_ptr<SourcePageHandleWebContents>());
distiller_page_ = &distiller_page;
base::RunLoop run_loop;
- DistillPage(run_loop.QuitClosure(), "/simple_article.html");
+ DistillPage(run_loop.QuitClosure(), kSimpleArticlePath);
run_loop.Run();
EXPECT_EQ("Test Page Title", page_info_.get()->title);
@@ -89,11 +185,12 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, BasicDistillationWorks) {
IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, HandlesRelativeLinks) {
DistillerPageWebContents distiller_page(
- shell()->web_contents()->GetBrowserContext());
+ shell()->web_contents()->GetBrowserContext(),
+ scoped_ptr<SourcePageHandleWebContents>());
distiller_page_ = &distiller_page;
base::RunLoop run_loop;
- DistillPage(run_loop.QuitClosure(), "/simple_article.html");
+ DistillPage(run_loop.QuitClosure(), kSimpleArticlePath);
run_loop.Run();
// A relative link should've been updated.
@@ -105,11 +202,12 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, HandlesRelativeLinks) {
IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, HandlesRelativeImages) {
DistillerPageWebContents distiller_page(
- shell()->web_contents()->GetBrowserContext());
+ shell()->web_contents()->GetBrowserContext(),
+ scoped_ptr<SourcePageHandleWebContents>());
distiller_page_ = &distiller_page;
base::RunLoop run_loop;
- DistillPage(run_loop.QuitClosure(), "/simple_article.html");
+ DistillPage(run_loop.QuitClosure(), kSimpleArticlePath);
run_loop.Run();
// A relative link should've been updated.
@@ -121,7 +219,8 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, HandlesRelativeImages) {
IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, VisibilityDetection) {
DistillerPageWebContents distiller_page(
- shell()->web_contents()->GetBrowserContext());
+ shell()->web_contents()->GetBrowserContext(),
+ scoped_ptr<SourcePageHandleWebContents>());
distiller_page_ = &distiller_page;
// visble_style.html and invisible_style.html only differ by the visibility
@@ -142,4 +241,92 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, VisibilityDetection) {
}
}
+IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
+ UsingCurrentWebContentsWrongUrl) {
+ std::string url("/bogus");
+ bool expect_new_web_contents = true;
+ bool setup_main_frame_observer = true;
+ bool wait_for_document_loaded = true;
+ RunUseCurrentWebContentsTest(url,
+ expect_new_web_contents,
+ setup_main_frame_observer,
+ wait_for_document_loaded);
+}
+
+IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
+ UsingCurrentWebContentsNoMainFrameObserver) {
+ std::string url(kSimpleArticlePath);
+ bool expect_new_web_contents = true;
+ bool setup_main_frame_observer = false;
+ bool wait_for_document_loaded = true;
+ RunUseCurrentWebContentsTest(url,
+ expect_new_web_contents,
+ setup_main_frame_observer,
+ wait_for_document_loaded);
+}
+
+IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
+ UsingCurrentWebContentsNotFinishedLoadingYet) {
+ std::string url(kSimpleArticlePath);
+ bool expect_new_web_contents = false;
+ bool setup_main_frame_observer = true;
+ bool wait_for_document_loaded = false;
+ RunUseCurrentWebContentsTest(url,
+ expect_new_web_contents,
+ setup_main_frame_observer,
+ wait_for_document_loaded);
+}
+
+IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
+ UsingCurrentWebContentsReadyForDistillation) {
+ std::string url(kSimpleArticlePath);
+ bool expect_new_web_contents = false;
+ bool setup_main_frame_observer = true;
+ bool wait_for_document_loaded = true;
+ RunUseCurrentWebContentsTest(url,
+ expect_new_web_contents,
+ setup_main_frame_observer,
+ wait_for_document_loaded);
+}
+
+void DistillerPageWebContentsTest::RunUseCurrentWebContentsTest(
+ const std::string& url,
+ bool expect_new_web_contents,
+ bool setup_main_frame_observer,
+ bool wait_for_document_loaded) {
+ content::WebContents* current_web_contents = shell()->web_contents();
+ if (setup_main_frame_observer) {
+ dom_distiller::WebContentsMainFrameObserver::CreateForWebContents(
+ current_web_contents);
+ }
+ base::RunLoop url_loaded_runner;
+ WebContentsMainFrameHelper main_frame_loaded(current_web_contents,
+ url_loaded_runner.QuitClosure(),
+ wait_for_document_loaded);
+ current_web_contents->GetController().LoadURL(
+ embedded_test_server()->GetURL(url),
+ content::Referrer(),
+ content::PAGE_TRANSITION_TYPED,
+ std::string());
+ url_loaded_runner.Run();
+
+ scoped_ptr<content::WebContents> old_web_contents_sptr(current_web_contents);
+ scoped_ptr<SourcePageHandleWebContents> source_page_handle(
+ new SourcePageHandleWebContents(old_web_contents_sptr.Pass()));
+
+ TestDistillerPageWebContents distiller_page(
+ shell()->web_contents()->GetBrowserContext(),
+ source_page_handle.Pass(),
+ expect_new_web_contents);
+ distiller_page_ = &distiller_page;
+
+ base::RunLoop run_loop;
+ DistillPage(run_loop.QuitClosure(), kSimpleArticlePath);
+ run_loop.Run();
+
+ // Sanity check of distillation process.
+ EXPECT_EQ(expect_new_web_contents, distiller_page.new_web_contents_created());
+ EXPECT_EQ("Test Page Title", page_info_.get()->title);
+}
+
} // namespace dom_distiller
diff --git a/components/dom_distiller/content/web_contents_main_frame_observer.cc b/components/dom_distiller/content/web_contents_main_frame_observer.cc
new file mode 100644
index 0000000..ed1bbab
--- /dev/null
+++ b/components/dom_distiller/content/web_contents_main_frame_observer.cc
@@ -0,0 +1,61 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/dom_distiller/content/web_contents_main_frame_observer.h"
+
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(dom_distiller::WebContentsMainFrameObserver);
+
+namespace dom_distiller {
+
+WebContentsMainFrameObserver::WebContentsMainFrameObserver(
+ content::WebContents* web_contents)
+ : is_document_loaded_in_main_frame_(false),
+ is_initialized_(false),
+ web_contents_(web_contents) {
+ content::WebContentsObserver::Observe(web_contents);
+}
+
+WebContentsMainFrameObserver::~WebContentsMainFrameObserver() {
+ CleanUp();
+}
+
+void WebContentsMainFrameObserver::DocumentLoadedInFrame(
+ int64 frame_id,
+ content::RenderViewHost* render_view_host) {
+ if (web_contents_ &&
+ frame_id == web_contents_->GetMainFrame()->GetRoutingID()) {
+ is_document_loaded_in_main_frame_ = true;
+ }
+}
+
+void WebContentsMainFrameObserver::DidNavigateMainFrame(
+ const content::LoadCommittedDetails& details,
+ const content::FrameNavigateParams& params) {
+ if (details.is_main_frame) {
+ is_document_loaded_in_main_frame_ = false;
+ is_initialized_ = true;
+ }
+}
+
+void WebContentsMainFrameObserver::RenderProcessGone(
+ base::TerminationStatus status) {
+ CleanUp();
+}
+
+void WebContentsMainFrameObserver::WebContentsDestroyed() {
+ CleanUp();
+}
+
+void WebContentsMainFrameObserver::CleanUp() {
+ content::WebContentsObserver::Observe(NULL);
+ web_contents_ = NULL;
+}
+
+} // namespace dom_distiller
diff --git a/components/dom_distiller/content/web_contents_main_frame_observer.h b/components/dom_distiller/content/web_contents_main_frame_observer.h
new file mode 100644
index 0000000..7343dba
--- /dev/null
+++ b/components/dom_distiller/content/web_contents_main_frame_observer.h
@@ -0,0 +1,63 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DOM_DISTILLER_CONTENT_WEB_CONTENTS_MAIN_FRAME_OBSERVER_H_
+#define COMPONENTS_DOM_DISTILLER_CONTENT_WEB_CONTENTS_MAIN_FRAME_OBSERVER_H_
+
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace dom_distiller {
+
+// Tracks whether DocumentLoadedInFrame has been called for the main frame for
+// the current main frame for the given WebContents. It removes itself as an
+// observer if the WebContents is destroyed or the render process is gone.
+class WebContentsMainFrameObserver
+ : public content::WebContentsObserver,
+ public content::WebContentsUserData<WebContentsMainFrameObserver> {
+ public:
+ virtual ~WebContentsMainFrameObserver();
+
+ bool is_document_loaded_in_main_frame() {
+ return is_document_loaded_in_main_frame_;
+ }
+
+ bool is_initialized() { return is_initialized_; }
+
+ // content::WebContentsObserver implementation.
+ virtual void DocumentLoadedInFrame(
+ int64 frame_id,
+ content::RenderViewHost* render_view_host) OVERRIDE;
+ virtual void DidNavigateMainFrame(
+ const content::LoadCommittedDetails& details,
+ const content::FrameNavigateParams& params) OVERRIDE;
+ virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
+ virtual void WebContentsDestroyed() OVERRIDE;
+
+ private:
+ explicit WebContentsMainFrameObserver(content::WebContents* web_contents);
+ friend class content::WebContentsUserData<WebContentsMainFrameObserver>;
+
+ // Removes the observer and clears the WebContents member.
+ void CleanUp();
+
+ // Whether DocumentLoadedInFrame has been called for the tracked WebContents
+ // for the current main frame. This is cleared when the main frame navigates,
+ // and set again when DocumentLoadedInFrame is called for the main frame.
+ bool is_document_loaded_in_main_frame_;
+
+ // Whether this object has been correctly initialized. This is set as soon as
+ // at least one call to DidNavigateMainFrame has happened.
+ bool is_initialized_;
+
+ // The WebContents this class is tracking.
+ content::WebContents* web_contents_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebContentsMainFrameObserver);
+};
+
+} // namespace dom_distiller
+
+#endif // COMPONENTS_DOM_DISTILLER_CONTENT_WEB_CONTENTS_MAIN_FRAME_OBSERVER_H_
diff --git a/components/dom_distiller/core/distiller_page.h b/components/dom_distiller/core/distiller_page.h
index 429a676..b950df7 100644
--- a/components/dom_distiller/core/distiller_page.h
+++ b/components/dom_distiller/core/distiller_page.h
@@ -29,6 +29,11 @@ struct DistilledPageInfo {
DISALLOW_COPY_AND_ASSIGN(DistilledPageInfo);
};
+class SourcePageHandle {
+ public:
+ virtual ~SourcePageHandle() {}
+};
+
// Injects JavaScript into a page, and uses it to extract and return long-form
// content. The class can be reused to load and distill multiple pages,
// following the state transitions described along with the class's states.
@@ -62,10 +67,6 @@ class DistillerPage {
// should be the same regardless of the DistillerPage implementation.
virtual void DistillPageImpl(const GURL& url, const std::string& script) = 0;
- // Called by |ExecuteJavaScript| to carry out platform-specific instructions
- // to inject and execute JavaScript within the context of the loaded page.
- //virtual void ExecuteJavaScriptImpl() = 0;
-
private:
bool ready_;
DistillerPageCallback distiller_page_callback_;
@@ -81,6 +82,8 @@ class DistillerPageFactory {
// should be very cheap, since the pages can be thrown away without being
// used.
virtual scoped_ptr<DistillerPage> CreateDistillerPage() const = 0;
+ virtual scoped_ptr<DistillerPage> CreateDistillerPageWithHandle(
+ scoped_ptr<SourcePageHandle> handle) const = 0;
};
} // namespace dom_distiller
diff --git a/components/dom_distiller/core/dom_distiller_service.cc b/components/dom_distiller/core/dom_distiller_service.cc
index 848adaa..a3cbbda 100644
--- a/components/dom_distiller/core/dom_distiller_service.cc
+++ b/components/dom_distiller/core/dom_distiller_service.cc
@@ -46,7 +46,8 @@ DomDistillerService::DomDistillerService(
distiller_page_factory_(distiller_page_factory.Pass()) {
}
-DomDistillerService::~DomDistillerService() {}
+DomDistillerService::~DomDistillerService() {
+}
syncer::SyncableService* DomDistillerService::GetSyncableService() const {
return store_->GetSyncableService();
@@ -56,6 +57,13 @@ scoped_ptr<DistillerPage> DomDistillerService::CreateDefaultDistillerPage() {
return distiller_page_factory_->CreateDistillerPage().Pass();
}
+scoped_ptr<DistillerPage>
+DomDistillerService::CreateDefaultDistillerPageWithHandle(
+ scoped_ptr<SourcePageHandle> handle) {
+ return distiller_page_factory_->CreateDistillerPageWithHandle(handle.Pass())
+ .Pass();
+}
+
const std::string DomDistillerService::AddToList(
const GURL& url,
scoped_ptr<DistillerPage> distiller_page,
diff --git a/components/dom_distiller/core/dom_distiller_service.h b/components/dom_distiller/core/dom_distiller_service.h
index b2698b9e..cd59950 100644
--- a/components/dom_distiller/core/dom_distiller_service.h
+++ b/components/dom_distiller/core/dom_distiller_service.h
@@ -84,6 +84,8 @@ class DomDistillerServiceInterface {
// Creates a default DistillerPage.
virtual scoped_ptr<DistillerPage> CreateDefaultDistillerPage() = 0;
+ virtual scoped_ptr<DistillerPage> CreateDefaultDistillerPageWithHandle(
+ scoped_ptr<SourcePageHandle> handle) = 0;
virtual void AddObserver(DomDistillerObserver* observer) = 0;
virtual void RemoveObserver(DomDistillerObserver* observer) = 0;
@@ -121,6 +123,8 @@ class DomDistillerService : public DomDistillerServiceInterface {
scoped_ptr<DistillerPage> distiller_page,
const GURL& url) OVERRIDE;
virtual scoped_ptr<DistillerPage> CreateDefaultDistillerPage() OVERRIDE;
+ virtual scoped_ptr<DistillerPage> CreateDefaultDistillerPageWithHandle(
+ scoped_ptr<SourcePageHandle> handle) OVERRIDE;
virtual void AddObserver(DomDistillerObserver* observer) OVERRIDE;
virtual void RemoveObserver(DomDistillerObserver* observer) OVERRIDE;
diff --git a/components/dom_distiller/core/fake_distiller_page.h b/components/dom_distiller/core/fake_distiller_page.h
index 245d23e..2e88389 100644
--- a/components/dom_distiller/core/fake_distiller_page.h
+++ b/components/dom_distiller/core/fake_distiller_page.h
@@ -19,6 +19,10 @@ class MockDistillerPageFactory : public DistillerPageFactory {
virtual scoped_ptr<DistillerPage> CreateDistillerPage() const OVERRIDE {
return scoped_ptr<DistillerPage>(CreateDistillerPageImpl());
}
+ virtual scoped_ptr<DistillerPage> CreateDistillerPageWithHandle(
+ scoped_ptr<SourcePageHandle> handle) const OVERRIDE {
+ return scoped_ptr<DistillerPage>(CreateDistillerPageImpl());
+ }
};
class MockDistillerPage : public DistillerPage {
diff --git a/components/dom_distiller/core/viewer_unittest.cc b/components/dom_distiller/core/viewer_unittest.cc
index b0cea2a..7c1b075 100644
--- a/components/dom_distiller/core/viewer_unittest.cc
+++ b/components/dom_distiller/core/viewer_unittest.cc
@@ -62,6 +62,10 @@ class TestDomDistillerService : public DomDistillerServiceInterface {
virtual scoped_ptr<DistillerPage> CreateDefaultDistillerPage() {
return scoped_ptr<DistillerPage>();
}
+ virtual scoped_ptr<DistillerPage> CreateDefaultDistillerPageWithHandle(
+ scoped_ptr<SourcePageHandle> handle) {
+ return scoped_ptr<DistillerPage>();
+ }
};
class DomDistillerViewerTest : public testing::Test {