15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/dom_distiller/content/dom_distiller_viewer_source.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <sstream>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string>
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <vector>
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/ref_counted_memory.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/message_loop/message_loop.h"
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/metrics/user_metrics.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/dom_distiller/core/distilled_page_prefs.h"
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/dom_distiller/core/dom_distiller_service.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/dom_distiller/core/task_tracker.h"
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/dom_distiller/core/url_constants.h"
20a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "components/dom_distiller/core/viewer.h"
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/navigation_details.h"
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/navigation_entry.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/render_frame_host.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/user_metrics.h"
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/web_contents.h"
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/web_contents_observer.h"
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/base/url_util.h"
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/url_request/url_request.h"
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace dom_distiller {
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Handles receiving data asynchronously for a specific entry, and passing
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// it along to the data callback for the data source. Lifetime matches that of
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// the current main frame's page in the Viewer instance.
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class DomDistillerViewerSource::RequestViewerHandle
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : public ViewRequestDelegate,
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      public content::WebContentsObserver,
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      public DistilledPagePrefs::Observer {
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  explicit RequestViewerHandle(
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      content::WebContents* web_contents,
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const std::string& expected_scheme,
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const std::string& expected_request_path,
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      const content::URLDataSource::GotDataCallback& callback,
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      DistilledPagePrefs* distilled_page_prefs);
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~RequestViewerHandle();
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // ViewRequestDelegate implementation:
50a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  virtual void OnArticleReady(
51a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      const DistilledArticleProto* article_proto) OVERRIDE;
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
53a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  virtual void OnArticleUpdated(
54a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      ArticleDistillationUpdate article_update) OVERRIDE;
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle);
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // content::WebContentsObserver implementation:
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void DidNavigateMainFrame(
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const content::LoadCommittedDetails& details,
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const content::FrameNavigateParams& params) OVERRIDE;
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void WebContentsDestroyed() OVERRIDE;
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void DidFinishLoad(content::RenderFrameHost* render_frame_host,
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             const GURL& validated_url) OVERRIDE;
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Sends JavaScript to the attached Viewer, buffering data if the viewer isn't
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // ready.
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SendJavaScript(const std::string& buffer);
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Cancels the current view request. Once called, no updates will be
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // propagated to the view, and the request to DomDistillerService will be
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // cancelled.
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void Cancel();
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // DistilledPagePrefs::Observer implementation:
786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  virtual void OnChangeFontFamily(
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      DistilledPagePrefs::FontFamily new_font_family) OVERRIDE;
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void OnChangeTheme(DistilledPagePrefs::Theme new_theme) OVERRIDE;
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The handle to the view request towards the DomDistillerService. It
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // needs to be kept around to ensure the distillation request finishes.
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ViewerHandle> viewer_handle_;
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // The scheme hosting the current view request;
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string expected_scheme_;
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // The query path for the current view request.
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string expected_request_path_;
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Holds the callback to where the data retrieved is sent back.
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::URLDataSource::GotDataCallback callback_;
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Number of pages of the distilled article content that have been rendered by
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // the viewer.
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int page_count_;
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Interface for accessing preferences for distilled pages.
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DistilledPagePrefs* distilled_page_prefs_;
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Whether the page is sufficiently initialized to handle updates from the
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // distiller.
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool waiting_for_page_ready_;
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Temporary store of pending JavaScript if the page isn't ready to receive
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // data from distillation.
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string buffer_;
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle(
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    content::WebContents* web_contents,
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& expected_scheme,
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& expected_request_path,
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const content::URLDataSource::GotDataCallback& callback,
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DistilledPagePrefs* distilled_page_prefs)
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : expected_scheme_(expected_scheme),
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      expected_request_path_(expected_request_path),
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      callback_(callback),
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      page_count_(0),
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      distilled_page_prefs_(distilled_page_prefs),
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      waiting_for_page_ready_(true) {
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  content::WebContentsObserver::Observe(web_contents);
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  distilled_page_prefs_->AddObserver(this);
125a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
127a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochDomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() {
128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  distilled_page_prefs_->RemoveObserver(this);
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript(
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& buffer) {
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (waiting_for_page_ready_) {
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    buffer_ += buffer;
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (web_contents()) {
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      web_contents()->GetMainFrame()->ExecuteJavaScript(
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          base::UTF8ToUTF16(buffer));
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::DidNavigateMainFrame(
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const content::LoadCommittedDetails& details,
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const content::FrameNavigateParams& params) {
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const GURL& navigation = details.entry->GetURL();
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (details.is_in_page || (
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      navigation.SchemeIs(expected_scheme_.c_str()) &&
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      expected_request_path_ == navigation.query())) {
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // In-page navigations, as well as the main view request can be ignored.
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Cancel();
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::RenderProcessGone(
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::TerminationStatus status) {
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Cancel();
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::WebContentsDestroyed() {
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Cancel();
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::Cancel() {
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // No need to listen for notifications.
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  content::WebContentsObserver::Observe(NULL);
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Schedule the Viewer for deletion. Ensures distillation is cancelled, and
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // any pending data stored in |buffer_| is released.
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::DidFinishLoad(
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    content::RenderFrameHost* render_frame_host,
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const GURL& validated_url) {
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (render_frame_host->GetParent()) {
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  waiting_for_page_ready_ = false;
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (buffer_.empty()) {
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(buffer_));
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  buffer_.clear();
188a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady(
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const DistilledArticleProto* article_proto) {
192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (page_count_ == 0) {
193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // This is a single-page article.
1946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    std::string unsafe_page_html =
1956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        viewer::GetUnsafeArticleHtml(
1966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            article_proto,
1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            distilled_page_prefs_->GetTheme(),
1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            distilled_page_prefs_->GetFontFamily());
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html));
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else if (page_count_ == article_proto->pages_size()) {
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // We may still be showing the "Loading" indicator.
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    SendJavaScript(viewer::GetToggleLoadingIndicatorJs(true));
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // It's possible that we didn't get some incremental updates from the
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // distiller. Ensure all remaining pages are flushed to the viewer.
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for (;page_count_ < article_proto->pages_size(); page_count_++) {
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const DistilledPageProto& page = article_proto->pages(page_count_);
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      SendJavaScript(
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          viewer::GetUnsafeIncrementalDistilledPageJs(
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              &page,
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              page_count_ == article_proto->pages_size()));
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // No need to hold on to the ViewerHandle now that distillation is complete.
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  viewer_handle_.reset();
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::OnArticleUpdated(
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ArticleDistillationUpdate article_update) {
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (;page_count_ < static_cast<int>(article_update.GetPagesSize());
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       page_count_++) {
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const DistilledPageProto& page =
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        article_update.GetDistilledPage(page_count_);
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (page_count_ == 0) {
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // This is the first page, so send Viewer page scaffolding too.
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      std::string unsafe_page_html = viewer::GetUnsafePartialArticleHtml(
2276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          &page,
2286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          distilled_page_prefs_->GetTheme(),
2296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          distilled_page_prefs_->GetFontFamily());
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html));
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else {
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      SendJavaScript(
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          viewer::GetUnsafeIncrementalDistilledPageJs(&page, false));
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle(
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<ViewerHandle> viewer_handle) {
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  viewer_handle_ = viewer_handle.Pass();
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
243116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid DomDistillerViewerSource::RequestViewerHandle::OnChangeTheme(
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DistilledPagePrefs::Theme new_theme) {
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SendJavaScript(viewer::GetDistilledPageThemeJs(new_theme));
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::OnChangeFontFamily(
2496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DistilledPagePrefs::FontFamily new_font) {
2506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  SendJavaScript(viewer::GetDistilledPageFontFamilyJs(new_font));
2516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
2526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DomDistillerViewerSource::DomDistillerViewerSource(
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DomDistillerServiceInterface* dom_distiller_service,
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& scheme)
256a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    : scheme_(scheme), dom_distiller_service_(dom_distiller_service) {
257a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
259a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochDomDistillerViewerSource::~DomDistillerViewerSource() {
260a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string DomDistillerViewerSource::GetSource() const {
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return scheme_ + "://";
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DomDistillerViewerSource::StartDataRequest(
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& path,
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int render_process_id,
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int render_frame_id,
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const content::URLDataSource::GotDataCallback& callback) {
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::RenderFrameHost* render_frame_host =
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      content::RenderFrameHost::FromID(render_process_id, render_frame_id);
2735b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  if (!render_frame_host) return;
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::RenderViewHost* render_view_host =
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      render_frame_host->GetRenderViewHost();
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(render_view_host);
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK_EQ(0, render_view_host->GetEnabledBindings());
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (kViewerCssPath == path) {
280a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::string css = viewer::GetCss();
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(base::RefCountedString::TakeString(&css));
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (kViewerJsPath == path) {
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    std::string js = viewer::GetJavaScript();
286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    callback.Run(base::RefCountedString::TakeString(&js));
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (kViewerViewOriginalPath == path) {
2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content::RecordAction(base::UserMetricsAction("DomDistiller_ViewOriginal"));
2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(NULL);
2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  content::WebContents* web_contents =
2955b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      content::WebContents::FromRenderFrameHost(render_frame_host);
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(web_contents);
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // An empty |path| is invalid, but guard against it. If not empty, assume
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |path| starts with '?', which is stripped away.
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const std::string path_after_query_separator =
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      path.size() > 0 ? path.substr(1) : "";
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  RequestViewerHandle* request_viewer_handle = new RequestViewerHandle(
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      web_contents, scheme_, path_after_query_separator, callback,
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      dom_distiller_service_->GetDistilledPagePrefs());
304a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  scoped_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest(
3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      dom_distiller_service_, path, request_viewer_handle,
3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      web_contents->GetContainerBounds().size());
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (viewer_handle) {
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // The service returned a |ViewerHandle| and guarantees it will call
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // the |RequestViewerHandle|, so passing ownership to it, to ensure the
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // request is not cancelled. The |RequestViewerHandle| will delete itself
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // after receiving the callback.
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    request_viewer_handle->TakeViewerHandle(viewer_handle.Pass());
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // The service did not return a |ViewerHandle|, which means the
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // |RequestViewerHandle| will never be called, so clean up now.
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    delete request_viewer_handle;
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    std::string error_page_html = viewer::GetErrorPageHtml(
3206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        dom_distiller_service_->GetDistilledPagePrefs()->GetTheme(),
3216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        dom_distiller_service_->GetDistilledPagePrefs()->GetFontFamily());
322a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    callback.Run(base::RefCountedString::TakeString(&error_page_html));
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string DomDistillerViewerSource::GetMimeType(
327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& path) const {
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (kViewerCssPath == path) {
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return "text/css";
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (kViewerJsPath == path) {
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return "text/javascript";
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return "text/html";
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DomDistillerViewerSource::ShouldServiceRequest(
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const net::URLRequest* request) const {
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return request->url().SchemeIs(scheme_.c_str());
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
342a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// TODO(nyquist): Start tracking requests using this method.
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DomDistillerViewerSource::WillServiceRequest(
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const net::URLRequest* request,
345a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    std::string* path) const {
346a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc()
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const {
3506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return "object-src 'none'; style-src 'self' https://fonts.googleapis.com;";
351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace dom_distiller
354