Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(505)

Side by Side Diff: components/dom_distiller/content/dom_distiller_viewer_source.cc

Issue 1101993003: Move common distiller code to superclass (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move IOS to different CL Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/dom_distiller/content/dom_distiller_viewer_source.h" 5 #include "components/dom_distiller/content/dom_distiller_viewer_source.h"
6 6
7 #include <sstream> 7 #include <sstream>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/memory/ref_counted_memory.h" 11 #include "base/memory/ref_counted_memory.h"
12 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h" 13 #include "base/message_loop/message_loop.h"
14 #include "base/metrics/user_metrics.h" 14 #include "base/metrics/user_metrics.h"
15 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
16 #include "components/dom_distiller/core/distilled_page_prefs.h" 16 #include "components/dom_distiller/core/distilled_page_prefs.h"
17 #include "components/dom_distiller/core/dom_distiller_request_view_base.h"
17 #include "components/dom_distiller/core/dom_distiller_service.h" 18 #include "components/dom_distiller/core/dom_distiller_service.h"
18 #include "components/dom_distiller/core/external_feedback_reporter.h" 19 #include "components/dom_distiller/core/external_feedback_reporter.h"
19 #include "components/dom_distiller/core/feedback_reporter.h" 20 #include "components/dom_distiller/core/feedback_reporter.h"
20 #include "components/dom_distiller/core/task_tracker.h" 21 #include "components/dom_distiller/core/task_tracker.h"
21 #include "components/dom_distiller/core/url_constants.h" 22 #include "components/dom_distiller/core/url_constants.h"
22 #include "components/dom_distiller/core/viewer.h" 23 #include "components/dom_distiller/core/viewer.h"
23 #include "content/public/browser/navigation_details.h" 24 #include "content/public/browser/navigation_details.h"
24 #include "content/public/browser/navigation_entry.h" 25 #include "content/public/browser/navigation_entry.h"
25 #include "content/public/browser/render_frame_host.h" 26 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/render_view_host.h" 27 #include "content/public/browser/render_view_host.h"
27 #include "content/public/browser/user_metrics.h" 28 #include "content/public/browser/user_metrics.h"
28 #include "content/public/browser/web_contents.h" 29 #include "content/public/browser/web_contents.h"
29 #include "content/public/browser/web_contents_observer.h" 30 #include "content/public/browser/web_contents_observer.h"
30 #include "net/base/url_util.h" 31 #include "net/base/url_util.h"
31 #include "net/url_request/url_request.h" 32 #include "net/url_request/url_request.h"
32 33
33 namespace dom_distiller { 34 namespace dom_distiller {
34 35
36 namespace {
37
38 class ContentDataCallback : public DistillerDataCallback {
39 public:
40 ContentDataCallback(const content::URLDataSource::GotDataCallback& callback);
41 // Runs the callback.
42 void runCallback(std::string& data) override;
nyquist 2015/04/24 22:13:09 RunCallback
mdjones 2015/04/25 00:55:03 Done.
43
44 private:
45 // The callback that actually gets run.
46 content::URLDataSource::GotDataCallback callback_;
47 };
48
49 ContentDataCallback::ContentDataCallback(
50 const content::URLDataSource::GotDataCallback& callback) {
51 callback_ = callback;
52 }
53
54 void ContentDataCallback::runCallback(std::string& data) {
55 callback_.Run(base::RefCountedString::TakeString(&data));
56 }
57
58 } // namespace
59
35 // Handles receiving data asynchronously for a specific entry, and passing 60 // Handles receiving data asynchronously for a specific entry, and passing
36 // it along to the data callback for the data source. Lifetime matches that of 61 // it along to the data callback for the data source. Lifetime matches that of
37 // the current main frame's page in the Viewer instance. 62 // the current main frame's page in the Viewer instance.
38 class DomDistillerViewerSource::RequestViewerHandle 63 class DomDistillerViewerSource::RequestViewerHandle
39 : public ViewRequestDelegate, 64 : public DomDistillerRequestViewBase,
40 public content::WebContentsObserver, 65 public content::WebContentsObserver,
41 public DistilledPagePrefs::Observer { 66 public DistilledPagePrefs::Observer {
42 public: 67 public:
43 explicit RequestViewerHandle( 68 explicit RequestViewerHandle(content::WebContents* web_contents,
nyquist 2015/04/24 22:13:08 Does this need to be explicit?
mdjones 2015/04/25 00:55:03 Not as far as I can tell.
44 content::WebContents* web_contents, 69 const std::string& expected_scheme,
45 const std::string& expected_scheme, 70 const std::string& expected_request_path,
46 const std::string& expected_request_path, 71 scoped_ptr<ContentDataCallback> callback,
47 const content::URLDataSource::GotDataCallback& callback, 72 DistilledPagePrefs* distilled_page_prefs);
48 DistilledPagePrefs* distilled_page_prefs);
49 ~RequestViewerHandle() override; 73 ~RequestViewerHandle() override;
50 74
51 // Flag this request as an error and send the error page template.
52 void flagAsErrorPage();
53
54 // ViewRequestDelegate implementation:
55 void OnArticleReady(const DistilledArticleProto* article_proto) override;
56
57 void OnArticleUpdated(ArticleDistillationUpdate article_update) override;
58
59 void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle);
60
61 // content::WebContentsObserver implementation: 75 // content::WebContentsObserver implementation:
62 void DidNavigateMainFrame( 76 void DidNavigateMainFrame(
63 const content::LoadCommittedDetails& details, 77 const content::LoadCommittedDetails& details,
64 const content::FrameNavigateParams& params) override; 78 const content::FrameNavigateParams& params) override;
65 void RenderProcessGone(base::TerminationStatus status) override; 79 void RenderProcessGone(base::TerminationStatus status) override;
66 void WebContentsDestroyed() override; 80 void WebContentsDestroyed() override;
67 void DidFinishLoad(content::RenderFrameHost* render_frame_host, 81 void DidFinishLoad(content::RenderFrameHost* render_frame_host,
68 const GURL& validated_url) override; 82 const GURL& validated_url) override;
69 83
70 private: 84 private:
71 // Sends JavaScript to the attached Viewer, buffering data if the viewer isn't 85 // Sends JavaScript to the attached Viewer, buffering data if the viewer isn't
72 // ready. 86 // ready.
73 void SendJavaScript(const std::string& buffer); 87 void SendJavaScript(const std::string& buffer) override;
74 88
75 // Cancels the current view request. Once called, no updates will be 89 // Cancels the current view request. Once called, no updates will be
76 // propagated to the view, and the request to DomDistillerService will be 90 // propagated to the view, and the request to DomDistillerService will be
77 // cancelled. 91 // cancelled.
78 void Cancel(); 92 void Cancel();
79 93
80 // DistilledPagePrefs::Observer implementation: 94 // DistilledPagePrefs::Observer implementation:
81 void OnChangeFontFamily( 95 void OnChangeFontFamily(
nyquist 2015/04/24 22:13:09 Could these observer methods also move up to the b
mdjones 2015/04/25 00:55:03 They can. Originally I left them out because iOS d
82 DistilledPagePrefs::FontFamily new_font_family) override; 96 DistilledPagePrefs::FontFamily new_font_family) override;
83 void OnChangeTheme(DistilledPagePrefs::Theme new_theme) override; 97 void OnChangeTheme(DistilledPagePrefs::Theme new_theme) override;
84 98
85 // The handle to the view request towards the DomDistillerService. It
86 // needs to be kept around to ensure the distillation request finishes.
87 scoped_ptr<ViewerHandle> viewer_handle_;
88
89 // The scheme hosting the current view request; 99 // The scheme hosting the current view request;
90 std::string expected_scheme_; 100 std::string expected_scheme_;
91 101
92 // The query path for the current view request. 102 // The query path for the current view request.
93 std::string expected_request_path_; 103 std::string expected_request_path_;
94 104
95 // Holds the callback to where the data retrieved is sent back.
96 content::URLDataSource::GotDataCallback callback_;
97
98 // Number of pages of the distilled article content that have been rendered by
99 // the viewer.
100 int page_count_;
101
102 // Interface for accessing preferences for distilled pages.
103 DistilledPagePrefs* distilled_page_prefs_;
104
105 // Whether the page is sufficiently initialized to handle updates from the 105 // Whether the page is sufficiently initialized to handle updates from the
106 // distiller. 106 // distiller.
107 bool waiting_for_page_ready_; 107 bool waiting_for_page_ready_;
108 108
109 // Temporary store of pending JavaScript if the page isn't ready to receive 109 // Temporary store of pending JavaScript if the page isn't ready to receive
110 // data from distillation. 110 // data from distillation.
111 std::string buffer_; 111 std::string buffer_;
112
113 // Flag to tell this observer that the web contents are in an error state.
114 bool is_error_page_;
115 }; 112 };
116 113
117 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle( 114 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle(
118 content::WebContents* web_contents, 115 content::WebContents* web_contents,
119 const std::string& expected_scheme, 116 const std::string& expected_scheme,
120 const std::string& expected_request_path, 117 const std::string& expected_request_path,
121 const content::URLDataSource::GotDataCallback& callback, 118 scoped_ptr<ContentDataCallback> callback,
122 DistilledPagePrefs* distilled_page_prefs) 119 DistilledPagePrefs* distilled_page_prefs)
123 : expected_scheme_(expected_scheme), 120 : DomDistillerRequestViewBase(callback.Pass(), distilled_page_prefs),
121 expected_scheme_(expected_scheme),
124 expected_request_path_(expected_request_path), 122 expected_request_path_(expected_request_path),
125 callback_(callback), 123 waiting_for_page_ready_(true) {
126 page_count_(0),
127 distilled_page_prefs_(distilled_page_prefs),
128 waiting_for_page_ready_(true),
129 is_error_page_(false) {
130 content::WebContentsObserver::Observe(web_contents); 124 content::WebContentsObserver::Observe(web_contents);
131 distilled_page_prefs_->AddObserver(this); 125 distilled_page_prefs_->AddObserver(this);
132 } 126 }
133 127
134 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() { 128 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() {
135 distilled_page_prefs_->RemoveObserver(this); 129 distilled_page_prefs_->RemoveObserver(this);
136 } 130 }
137 131
138 void DomDistillerViewerSource::RequestViewerHandle::flagAsErrorPage() {
139 is_error_page_ = true;
140 std::string error_page_html = viewer::GetErrorPageHtml(
141 distilled_page_prefs_->GetTheme(),
142 distilled_page_prefs_->GetFontFamily());
143 callback_.Run(base::RefCountedString::TakeString(&error_page_html));
144 }
145
146 void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript( 132 void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript(
147 const std::string& buffer) { 133 const std::string& buffer) {
148 if (waiting_for_page_ready_) { 134 if (waiting_for_page_ready_) {
149 buffer_ += buffer; 135 buffer_ += buffer;
150 } else { 136 } else {
151 if (web_contents()) { 137 if (web_contents()) {
152 web_contents()->GetMainFrame()->ExecuteJavaScript( 138 web_contents()->GetMainFrame()->ExecuteJavaScript(
153 base::UTF8ToUTF16(buffer)); 139 base::UTF8ToUTF16(buffer));
154 } 140 }
155 } 141 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 return; 188 return;
203 } 189 }
204 waiting_for_page_ready_ = false; 190 waiting_for_page_ready_ = false;
205 if (buffer_.empty()) { 191 if (buffer_.empty()) {
206 return; 192 return;
207 } 193 }
208 web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(buffer_)); 194 web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(buffer_));
209 buffer_.clear(); 195 buffer_.clear();
210 } 196 }
211 197
212 void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady(
213 const DistilledArticleProto* article_proto) {
214 // TODO(mdjones): Move this logic to super class so it can be used in both
215 // android and IOS. http://crbug.com/472797
216 if (page_count_ == 0) {
217 std::string unsafe_page_html = viewer::GetUnsafeArticleTemplateHtml(
218 &article_proto->pages(0),
219 distilled_page_prefs_->GetTheme(),
220 distilled_page_prefs_->GetFontFamily());
221 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html));
222 // Send first page to client.
223 SendJavaScript(viewer::GetUnsafeArticleContentJs(article_proto));
224 // If any content was loaded, show the feedback form.
225 SendJavaScript(viewer::GetShowFeedbackFormJs());
226 } else if (page_count_ == article_proto->pages_size()) {
227 // We may still be showing the "Loading" indicator.
228 SendJavaScript(viewer::GetToggleLoadingIndicatorJs(true));
229 } else {
230 // It's possible that we didn't get some incremental updates from the
231 // distiller. Ensure all remaining pages are flushed to the viewer.
232 for (;page_count_ < article_proto->pages_size(); page_count_++) {
233 const DistilledPageProto& page = article_proto->pages(page_count_);
234 SendJavaScript(
235 viewer::GetUnsafeIncrementalDistilledPageJs(
236 &page,
237 page_count_ == article_proto->pages_size()));
238 }
239 }
240 // No need to hold on to the ViewerHandle now that distillation is complete.
241 viewer_handle_.reset();
242 }
243
244 void DomDistillerViewerSource::RequestViewerHandle::OnArticleUpdated(
245 ArticleDistillationUpdate article_update) {
246 for (;page_count_ < static_cast<int>(article_update.GetPagesSize());
247 page_count_++) {
248 const DistilledPageProto& page =
249 article_update.GetDistilledPage(page_count_);
250 // Send the page content to the client. This will execute after the page is
251 // ready.
252 SendJavaScript(viewer::GetUnsafeIncrementalDistilledPageJs(&page, false));
253
254 if (page_count_ == 0) {
255 // This is the first page, so send Viewer page scaffolding too.
256 std::string unsafe_page_html = viewer::GetUnsafeArticleTemplateHtml(
257 &page,
258 distilled_page_prefs_->GetTheme(),
259 distilled_page_prefs_->GetFontFamily());
260 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html));
261 // If any content was loaded, show the feedback form.
262 SendJavaScript(viewer::GetShowFeedbackFormJs());
263 }
264 }
265 }
266
267 void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle(
268 scoped_ptr<ViewerHandle> viewer_handle) {
269 viewer_handle_ = viewer_handle.Pass();
270 }
271
272 void DomDistillerViewerSource::RequestViewerHandle::OnChangeTheme( 198 void DomDistillerViewerSource::RequestViewerHandle::OnChangeTheme(
273 DistilledPagePrefs::Theme new_theme) { 199 DistilledPagePrefs::Theme new_theme) {
274 SendJavaScript(viewer::GetDistilledPageThemeJs(new_theme)); 200 SendJavaScript(viewer::GetDistilledPageThemeJs(new_theme));
275 } 201 }
276 202
277 void DomDistillerViewerSource::RequestViewerHandle::OnChangeFontFamily( 203 void DomDistillerViewerSource::RequestViewerHandle::OnChangeFontFamily(
278 DistilledPagePrefs::FontFamily new_font) { 204 DistilledPagePrefs::FontFamily new_font) {
279 SendJavaScript(viewer::GetDistilledPageFontFamilyJs(new_font)); 205 SendJavaScript(viewer::GetDistilledPageFontFamilyJs(new_font));
280 } 206 }
281 207
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 return; 257 return;
332 } else if (kFeedbackGood == path) { 258 } else if (kFeedbackGood == path) {
333 FeedbackReporter::ReportQuality(true); 259 FeedbackReporter::ReportQuality(true);
334 return; 260 return;
335 } 261 }
336 content::WebContents* web_contents = 262 content::WebContents* web_contents =
337 content::WebContents::FromRenderFrameHost(render_frame_host); 263 content::WebContents::FromRenderFrameHost(render_frame_host);
338 DCHECK(web_contents); 264 DCHECK(web_contents);
339 // An empty |path| is invalid, but guard against it. If not empty, assume 265 // An empty |path| is invalid, but guard against it. If not empty, assume
340 // |path| starts with '?', which is stripped away. 266 // |path| starts with '?', which is stripped away.
267 scoped_ptr<ContentDataCallback> data_callback(
268 new ContentDataCallback(callback));
341 const std::string path_after_query_separator = 269 const std::string path_after_query_separator =
342 path.size() > 0 ? path.substr(1) : ""; 270 path.size() > 0 ? path.substr(1) : "";
343 RequestViewerHandle* request_viewer_handle = new RequestViewerHandle( 271 RequestViewerHandle* request_viewer_handle = new RequestViewerHandle(
344 web_contents, scheme_, path_after_query_separator, callback, 272 web_contents, scheme_, path_after_query_separator, data_callback.Pass(),
345 dom_distiller_service_->GetDistilledPagePrefs()); 273 dom_distiller_service_->GetDistilledPagePrefs());
346 scoped_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest( 274 scoped_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest(
347 dom_distiller_service_, path, request_viewer_handle, 275 dom_distiller_service_, path, request_viewer_handle,
348 web_contents->GetContainerBounds().size()); 276 web_contents->GetContainerBounds().size());
349 277
350 if (viewer_handle) { 278 if (viewer_handle) {
351 // The service returned a |ViewerHandle| and guarantees it will call 279 // The service returned a |ViewerHandle| and guarantees it will call
352 // the |RequestViewerHandle|, so passing ownership to it, to ensure the 280 // the |RequestViewerHandle|, so passing ownership to it, to ensure the
353 // request is not cancelled. The |RequestViewerHandle| will delete itself 281 // request is not cancelled. The |RequestViewerHandle| will delete itself
354 // after receiving the callback. 282 // after receiving the callback.
(...skipping 28 matching lines...) Expand all
383 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc() 311 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc()
384 const { 312 const {
385 return "object-src 'none'; style-src 'self' https://fonts.googleapis.com;"; 313 return "object-src 'none'; style-src 'self' https://fonts.googleapis.com;";
386 } 314 }
387 315
388 std::string DomDistillerViewerSource::GetContentSecurityPolicyFrameSrc() const { 316 std::string DomDistillerViewerSource::GetContentSecurityPolicyFrameSrc() const {
389 return "frame-src *;"; 317 return "frame-src *;";
390 } 318 }
391 319
392 } // namespace dom_distiller 320 } // namespace dom_distiller
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698