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

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: address comments 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
« no previous file with comments | « components/dom_distiller.gypi ('k') | components/dom_distiller/core/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
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 {
42 public: 66 public:
43 explicit RequestViewerHandle( 67 RequestViewerHandle(content::WebContents* web_contents,
44 content::WebContents* web_contents, 68 const std::string& expected_scheme,
45 const std::string& expected_scheme, 69 const std::string& expected_request_path,
46 const std::string& expected_request_path, 70 scoped_ptr<ContentDataCallback> callback,
47 const content::URLDataSource::GotDataCallback& callback, 71 DistilledPagePrefs* distilled_page_prefs);
48 DistilledPagePrefs* distilled_page_prefs);
49 ~RequestViewerHandle() override; 72 ~RequestViewerHandle() override;
50 73
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: 74 // content::WebContentsObserver implementation:
62 void DidNavigateMainFrame( 75 void DidNavigateMainFrame(
63 const content::LoadCommittedDetails& details, 76 const content::LoadCommittedDetails& details,
64 const content::FrameNavigateParams& params) override; 77 const content::FrameNavigateParams& params) override;
65 void RenderProcessGone(base::TerminationStatus status) override; 78 void RenderProcessGone(base::TerminationStatus status) override;
66 void WebContentsDestroyed() override; 79 void WebContentsDestroyed() override;
67 void DidFinishLoad(content::RenderFrameHost* render_frame_host, 80 void DidFinishLoad(content::RenderFrameHost* render_frame_host,
68 const GURL& validated_url) override; 81 const GURL& validated_url) override;
69 82
70 private: 83 private:
71 // Sends JavaScript to the attached Viewer, buffering data if the viewer isn't 84 // Sends JavaScript to the attached Viewer, buffering data if the viewer isn't
72 // ready. 85 // ready.
73 void SendJavaScript(const std::string& buffer); 86 void SendJavaScript(const std::string& buffer) override;
74 87
75 // Cancels the current view request. Once called, no updates will be 88 // Cancels the current view request. Once called, no updates will be
76 // propagated to the view, and the request to DomDistillerService will be 89 // propagated to the view, and the request to DomDistillerService will be
77 // cancelled. 90 // cancelled.
78 void Cancel(); 91 void Cancel();
79 92
80 // DistilledPagePrefs::Observer implementation:
81 void OnChangeFontFamily(
82 DistilledPagePrefs::FontFamily new_font_family) override;
83 void OnChangeTheme(DistilledPagePrefs::Theme new_theme) override;
84
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; 93 // The scheme hosting the current view request;
90 std::string expected_scheme_; 94 std::string expected_scheme_;
91 95
92 // The query path for the current view request. 96 // The query path for the current view request.
93 std::string expected_request_path_; 97 std::string expected_request_path_;
94 98
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 99 // Whether the page is sufficiently initialized to handle updates from the
106 // distiller. 100 // distiller.
107 bool waiting_for_page_ready_; 101 bool waiting_for_page_ready_;
108 102
109 // Temporary store of pending JavaScript if the page isn't ready to receive 103 // Temporary store of pending JavaScript if the page isn't ready to receive
110 // data from distillation. 104 // data from distillation.
111 std::string buffer_; 105 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 }; 106 };
116 107
117 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle( 108 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle(
118 content::WebContents* web_contents, 109 content::WebContents* web_contents,
119 const std::string& expected_scheme, 110 const std::string& expected_scheme,
120 const std::string& expected_request_path, 111 const std::string& expected_request_path,
121 const content::URLDataSource::GotDataCallback& callback, 112 scoped_ptr<ContentDataCallback> callback,
122 DistilledPagePrefs* distilled_page_prefs) 113 DistilledPagePrefs* distilled_page_prefs)
123 : expected_scheme_(expected_scheme), 114 : DomDistillerRequestViewBase(callback.Pass(), distilled_page_prefs),
115 expected_scheme_(expected_scheme),
124 expected_request_path_(expected_request_path), 116 expected_request_path_(expected_request_path),
125 callback_(callback), 117 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); 118 content::WebContentsObserver::Observe(web_contents);
131 distilled_page_prefs_->AddObserver(this); 119 distilled_page_prefs_->AddObserver(this);
132 } 120 }
133 121
134 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() { 122 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() {
135 distilled_page_prefs_->RemoveObserver(this); 123 distilled_page_prefs_->RemoveObserver(this);
136 } 124 }
137 125
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( 126 void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript(
147 const std::string& buffer) { 127 const std::string& buffer) {
148 if (waiting_for_page_ready_) { 128 if (waiting_for_page_ready_) {
149 buffer_ += buffer; 129 buffer_ += buffer;
150 } else { 130 } else {
151 if (web_contents()) { 131 if (web_contents()) {
152 web_contents()->GetMainFrame()->ExecuteJavaScript( 132 web_contents()->GetMainFrame()->ExecuteJavaScript(
153 base::UTF8ToUTF16(buffer)); 133 base::UTF8ToUTF16(buffer));
154 } 134 }
155 } 135 }
(...skipping 27 matching lines...) Expand all
183 content::WebContentsObserver::Observe(NULL); 163 content::WebContentsObserver::Observe(NULL);
184 164
185 // Schedule the Viewer for deletion. Ensures distillation is cancelled, and 165 // Schedule the Viewer for deletion. Ensures distillation is cancelled, and
186 // any pending data stored in |buffer_| is released. 166 // any pending data stored in |buffer_| is released.
187 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 167 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
188 } 168 }
189 169
190 void DomDistillerViewerSource::RequestViewerHandle::DidFinishLoad( 170 void DomDistillerViewerSource::RequestViewerHandle::DidFinishLoad(
191 content::RenderFrameHost* render_frame_host, 171 content::RenderFrameHost* render_frame_host,
192 const GURL& validated_url) { 172 const GURL& validated_url) {
193 if (is_error_page_) { 173 if (IsErrorPage()) {
194 waiting_for_page_ready_ = false; 174 waiting_for_page_ready_ = false;
195 SendJavaScript(viewer::GetErrorPageJs()); 175 SendJavaScript(viewer::GetErrorPageJs());
196 SendJavaScript(viewer::GetShowFeedbackFormJs()); 176 SendJavaScript(viewer::GetShowFeedbackFormJs());
197 Cancel(); // This will cause the object to clean itself up. 177 Cancel(); // This will cause the object to clean itself up.
198 return; 178 return;
199 } 179 }
200 180
201 if (render_frame_host->GetParent()) { 181 if (render_frame_host->GetParent()) {
202 return; 182 return;
203 } 183 }
204 waiting_for_page_ready_ = false; 184 waiting_for_page_ready_ = false;
205 if (buffer_.empty()) { 185 if (buffer_.empty()) {
206 return; 186 return;
207 } 187 }
208 web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(buffer_)); 188 web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(buffer_));
209 buffer_.clear(); 189 buffer_.clear();
210 } 190 }
211 191
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(
273 DistilledPagePrefs::Theme new_theme) {
274 SendJavaScript(viewer::GetDistilledPageThemeJs(new_theme));
275 }
276
277 void DomDistillerViewerSource::RequestViewerHandle::OnChangeFontFamily(
278 DistilledPagePrefs::FontFamily new_font) {
279 SendJavaScript(viewer::GetDistilledPageFontFamilyJs(new_font));
280 }
281
282 DomDistillerViewerSource::DomDistillerViewerSource( 192 DomDistillerViewerSource::DomDistillerViewerSource(
283 DomDistillerServiceInterface* dom_distiller_service, 193 DomDistillerServiceInterface* dom_distiller_service,
284 const std::string& scheme, 194 const std::string& scheme,
285 scoped_ptr<ExternalFeedbackReporter> external_reporter) 195 scoped_ptr<ExternalFeedbackReporter> external_reporter)
286 : scheme_(scheme), 196 : scheme_(scheme),
287 dom_distiller_service_(dom_distiller_service), 197 dom_distiller_service_(dom_distiller_service),
288 external_feedback_reporter_(external_reporter.Pass()) { 198 external_feedback_reporter_(external_reporter.Pass()) {
289 } 199 }
290 200
291 DomDistillerViewerSource::~DomDistillerViewerSource() { 201 DomDistillerViewerSource::~DomDistillerViewerSource() {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 return; 241 return;
332 } else if (kFeedbackGood == path) { 242 } else if (kFeedbackGood == path) {
333 FeedbackReporter::ReportQuality(true); 243 FeedbackReporter::ReportQuality(true);
334 return; 244 return;
335 } 245 }
336 content::WebContents* web_contents = 246 content::WebContents* web_contents =
337 content::WebContents::FromRenderFrameHost(render_frame_host); 247 content::WebContents::FromRenderFrameHost(render_frame_host);
338 DCHECK(web_contents); 248 DCHECK(web_contents);
339 // An empty |path| is invalid, but guard against it. If not empty, assume 249 // An empty |path| is invalid, but guard against it. If not empty, assume
340 // |path| starts with '?', which is stripped away. 250 // |path| starts with '?', which is stripped away.
251 scoped_ptr<ContentDataCallback> data_callback(
252 new ContentDataCallback(callback));
341 const std::string path_after_query_separator = 253 const std::string path_after_query_separator =
342 path.size() > 0 ? path.substr(1) : ""; 254 path.size() > 0 ? path.substr(1) : "";
343 RequestViewerHandle* request_viewer_handle = new RequestViewerHandle( 255 RequestViewerHandle* request_viewer_handle = new RequestViewerHandle(
344 web_contents, scheme_, path_after_query_separator, callback, 256 web_contents, scheme_, path_after_query_separator, data_callback.Pass(),
345 dom_distiller_service_->GetDistilledPagePrefs()); 257 dom_distiller_service_->GetDistilledPagePrefs());
346 scoped_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest( 258 scoped_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest(
347 dom_distiller_service_, path, request_viewer_handle, 259 dom_distiller_service_, path, request_viewer_handle,
348 web_contents->GetContainerBounds().size()); 260 web_contents->GetContainerBounds().size());
349 261
350 if (viewer_handle) { 262 if (viewer_handle) {
351 // The service returned a |ViewerHandle| and guarantees it will call 263 // The service returned a |ViewerHandle| and guarantees it will call
352 // the |RequestViewerHandle|, so passing ownership to it, to ensure the 264 // the |RequestViewerHandle|, so passing ownership to it, to ensure the
353 // request is not cancelled. The |RequestViewerHandle| will delete itself 265 // request is not cancelled. The |RequestViewerHandle| will delete itself
354 // after receiving the callback. 266 // after receiving the callback.
355 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass()); 267 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass());
356 } else { 268 } else {
357 request_viewer_handle->flagAsErrorPage(); 269 request_viewer_handle->FlagAsErrorPage();
358 } 270 }
359 }; 271 };
360 272
361 std::string DomDistillerViewerSource::GetMimeType( 273 std::string DomDistillerViewerSource::GetMimeType(
362 const std::string& path) const { 274 const std::string& path) const {
363 if (kViewerCssPath == path) { 275 if (kViewerCssPath == path) {
364 return "text/css"; 276 return "text/css";
365 } 277 }
366 if (kViewerJsPath == path) { 278 if (kViewerJsPath == path) {
367 return "text/javascript"; 279 return "text/javascript";
(...skipping 15 matching lines...) Expand all
383 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc() 295 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc()
384 const { 296 const {
385 return "object-src 'none'; style-src 'self' https://fonts.googleapis.com;"; 297 return "object-src 'none'; style-src 'self' https://fonts.googleapis.com;";
386 } 298 }
387 299
388 std::string DomDistillerViewerSource::GetContentSecurityPolicyFrameSrc() const { 300 std::string DomDistillerViewerSource::GetContentSecurityPolicyFrameSrc() const {
389 return "frame-src *;"; 301 return "frame-src *;";
390 } 302 }
391 303
392 } // namespace dom_distiller 304 } // namespace dom_distiller
OLDNEW
« no previous file with comments | « components/dom_distiller.gypi ('k') | components/dom_distiller/core/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698