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

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

Issue 1015463004: Consistent content placement method for dom-distiller (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Template observer Created 5 years, 9 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/logging.h"
11 #include "base/memory/ref_counted_memory.h" 12 #include "base/memory/ref_counted_memory.h"
12 #include "base/memory/scoped_ptr.h" 13 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h" 14 #include "base/message_loop/message_loop.h"
14 #include "base/metrics/user_metrics.h" 15 #include "base/metrics/user_metrics.h"
15 #include "base/strings/utf_string_conversions.h" 16 #include "base/strings/utf_string_conversions.h"
16 #include "components/dom_distiller/core/distilled_page_prefs.h" 17 #include "components/dom_distiller/core/distilled_page_prefs.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/task_tracker.h" 19 #include "components/dom_distiller/core/task_tracker.h"
19 #include "components/dom_distiller/core/url_constants.h" 20 #include "components/dom_distiller/core/url_constants.h"
20 #include "components/dom_distiller/core/viewer.h" 21 #include "components/dom_distiller/core/viewer.h"
21 #include "content/public/browser/navigation_details.h" 22 #include "content/public/browser/navigation_details.h"
22 #include "content/public/browser/navigation_entry.h" 23 #include "content/public/browser/navigation_entry.h"
23 #include "content/public/browser/render_frame_host.h" 24 #include "content/public/browser/render_frame_host.h"
24 #include "content/public/browser/render_view_host.h" 25 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/user_metrics.h" 26 #include "content/public/browser/user_metrics.h"
26 #include "content/public/browser/web_contents.h" 27 #include "content/public/browser/web_contents.h"
27 #include "content/public/browser/web_contents_observer.h" 28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/browser/web_contents_user_data.h"
28 #include "net/base/url_util.h" 30 #include "net/base/url_util.h"
29 #include "net/url_request/url_request.h" 31 #include "net/url_request/url_request.h"
30 32
33 namespace {
34
35 // Handles sending conent to pages that are in an error state (i.e. the URL
36 // was bad or could not be loaded).
37 class WebContentsErrorObserver
38 : public content::WebContentsObserver,
39 public content::WebContentsUserData<WebContentsErrorObserver> {
40 public:
41 // Once the page has finished loading, send an error message.
42 void DocumentOnLoadCompletedInMainFrame() override {
43 web_contents()->GetMainFrame()->ExecuteJavaScript(
44 base::UTF8ToUTF16(dom_distiller::viewer::GetErrorPageJs()));
45 }
46
47 private:
48 friend class content::WebContentsUserData<WebContentsErrorObserver>;
49 explicit WebContentsErrorObserver(content::WebContents* web_contents)
50 : WebContentsObserver(web_contents) {}
51
52 ~WebContentsErrorObserver() override {
53 content::WebContentsObserver::Observe(NULL);
54 }
55
56 DISALLOW_COPY_AND_ASSIGN(WebContentsErrorObserver);
57 };
58
59 // Handles sending the first page of content after the template has been
60 // loaded successfully.
61 class WebContentsTemplateObserver
62 : public content::WebContentsObserver,
63 public content::WebContentsUserData<WebContentsTemplateObserver> {
64 public:
65 explicit WebContentsTemplateObserver(content::WebContents* web_contents) {
66 content::WebContentsObserver::Observe(web_contents);
67 }
68
69 // Once the page has finished loading, send the page(s).
70 void DocumentOnLoadCompletedInMainFrame() override {
71 web_contents()->GetMainFrame()->ExecuteJavaScript(
72 base::UTF8ToUTF16(js_page_content_));
73 // First page has been sent, no need to keep observing.
74 content::WebContentsObserver::Observe(NULL);
75 }
76
77 // Set the content that should be loaded immediately after the template.
78 void setInitialContent(const std::string &content) {
79 js_page_content_ = content;
80 }
81
82 private:
83 friend class content::WebContentsUserData<WebContentsErrorObserver>;
84
85 ~WebContentsTemplateObserver() override {
86 content::WebContentsObserver::Observe(NULL);
87 }
88
89 // The JavaScript that puts the initial content in the page template.
90 std::string js_page_content_;
91
92 DISALLOW_COPY_AND_ASSIGN(WebContentsTemplateObserver);
93 };
94
95
96 } // namespace
97
98 DEFINE_WEB_CONTENTS_USER_DATA_KEY(WebContentsErrorObserver);
99
31 namespace dom_distiller { 100 namespace dom_distiller {
32 101
33 // Handles receiving data asynchronously for a specific entry, and passing 102 // Handles receiving data asynchronously for a specific entry, and passing
34 // it along to the data callback for the data source. Lifetime matches that of 103 // it along to the data callback for the data source. Lifetime matches that of
35 // the current main frame's page in the Viewer instance. 104 // the current main frame's page in the Viewer instance.
36 class DomDistillerViewerSource::RequestViewerHandle 105 class DomDistillerViewerSource::RequestViewerHandle
37 : public ViewRequestDelegate, 106 : public ViewRequestDelegate,
38 public content::WebContentsObserver, 107 public content::WebContentsObserver,
39 public DistilledPagePrefs::Observer { 108 public DistilledPagePrefs::Observer {
40 public: 109 public:
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 // Interface for accessing preferences for distilled pages. 166 // Interface for accessing preferences for distilled pages.
98 DistilledPagePrefs* distilled_page_prefs_; 167 DistilledPagePrefs* distilled_page_prefs_;
99 168
100 // Whether the page is sufficiently initialized to handle updates from the 169 // Whether the page is sufficiently initialized to handle updates from the
101 // distiller. 170 // distiller.
102 bool waiting_for_page_ready_; 171 bool waiting_for_page_ready_;
103 172
104 // Temporary store of pending JavaScript if the page isn't ready to receive 173 // Temporary store of pending JavaScript if the page isn't ready to receive
105 // data from distillation. 174 // data from distillation.
106 std::string buffer_; 175 std::string buffer_;
176
177 // WebContentsObserver for detecting the load completion of the page template.
178 WebContentsTemplateObserver* template_observer_;
107 }; 179 };
108 180
109 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle( 181 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle(
110 content::WebContents* web_contents, 182 content::WebContents* web_contents,
111 const std::string& expected_scheme, 183 const std::string& expected_scheme,
112 const std::string& expected_request_path, 184 const std::string& expected_request_path,
113 const content::URLDataSource::GotDataCallback& callback, 185 const content::URLDataSource::GotDataCallback& callback,
114 DistilledPagePrefs* distilled_page_prefs) 186 DistilledPagePrefs* distilled_page_prefs)
115 : expected_scheme_(expected_scheme), 187 : expected_scheme_(expected_scheme),
116 expected_request_path_(expected_request_path), 188 expected_request_path_(expected_request_path),
117 callback_(callback), 189 callback_(callback),
118 page_count_(0), 190 page_count_(0),
119 distilled_page_prefs_(distilled_page_prefs), 191 distilled_page_prefs_(distilled_page_prefs),
120 waiting_for_page_ready_(true) { 192 waiting_for_page_ready_(true) {
121 content::WebContentsObserver::Observe(web_contents); 193 content::WebContentsObserver::Observe(web_contents);
122 distilled_page_prefs_->AddObserver(this); 194 distilled_page_prefs_->AddObserver(this);
195 template_observer_ = new WebContentsTemplateObserver(web_contents);
123 } 196 }
124 197
125 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() { 198 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() {
126 distilled_page_prefs_->RemoveObserver(this); 199 distilled_page_prefs_->RemoveObserver(this);
127 } 200 }
128 201
129 void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript( 202 void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript(
130 const std::string& buffer) { 203 const std::string& buffer) {
131 if (waiting_for_page_ready_) { 204 if (waiting_for_page_ready_) {
132 buffer_ += buffer; 205 buffer_ += buffer;
(...skipping 10 matching lines...) Expand all
143 const content::FrameNavigateParams& params) { 216 const content::FrameNavigateParams& params) {
144 const GURL& navigation = details.entry->GetURL(); 217 const GURL& navigation = details.entry->GetURL();
145 if (details.is_in_page || ( 218 if (details.is_in_page || (
146 navigation.SchemeIs(expected_scheme_.c_str()) && 219 navigation.SchemeIs(expected_scheme_.c_str()) &&
147 expected_request_path_ == navigation.query())) { 220 expected_request_path_ == navigation.query())) {
148 // In-page navigations, as well as the main view request can be ignored. 221 // In-page navigations, as well as the main view request can be ignored.
149 return; 222 return;
150 } 223 }
151 224
152 Cancel(); 225 Cancel();
153
154 } 226 }
155 227
156 void DomDistillerViewerSource::RequestViewerHandle::RenderProcessGone( 228 void DomDistillerViewerSource::RequestViewerHandle::RenderProcessGone(
157 base::TerminationStatus status) { 229 base::TerminationStatus status) {
158 Cancel(); 230 Cancel();
159 } 231 }
160 232
161 void DomDistillerViewerSource::RequestViewerHandle::WebContentsDestroyed() { 233 void DomDistillerViewerSource::RequestViewerHandle::WebContentsDestroyed() {
162 Cancel(); 234 Cancel();
163 } 235 }
(...skipping 17 matching lines...) Expand all
181 if (buffer_.empty()) { 253 if (buffer_.empty()) {
182 return; 254 return;
183 } 255 }
184 web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(buffer_)); 256 web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(buffer_));
185 buffer_.clear(); 257 buffer_.clear();
186 } 258 }
187 259
188 void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady( 260 void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady(
189 const DistilledArticleProto* article_proto) { 261 const DistilledArticleProto* article_proto) {
190 if (page_count_ == 0) { 262 if (page_count_ == 0) {
191 // This is a single-page article. 263 template_observer_->setInitialContent(
192 std::string unsafe_page_html = 264 viewer::GetUnsafeArticleContentJs(article_proto));
193 viewer::GetUnsafeArticleHtml( 265
194 article_proto, 266 std::string unsafe_page_html = viewer::GetUnsafeArticleTemplateHtml(
195 distilled_page_prefs_->GetTheme(), 267 &article_proto->pages(0),
196 distilled_page_prefs_->GetFontFamily()); 268 distilled_page_prefs_->GetTheme(),
269 distilled_page_prefs_->GetFontFamily());
197 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); 270 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html));
271
272 // Send the actual article content to the page.
198 } else if (page_count_ == article_proto->pages_size()) { 273 } else if (page_count_ == article_proto->pages_size()) {
199 // We may still be showing the "Loading" indicator. 274 // We may still be showing the "Loading" indicator.
200 SendJavaScript(viewer::GetToggleLoadingIndicatorJs(true)); 275 SendJavaScript(viewer::GetToggleLoadingIndicatorJs(true));
201 } else { 276 } else {
202 // It's possible that we didn't get some incremental updates from the 277 // It's possible that we didn't get some incremental updates from the
203 // distiller. Ensure all remaining pages are flushed to the viewer. 278 // distiller. Ensure all remaining pages are flushed to the viewer.
204 for (;page_count_ < article_proto->pages_size(); page_count_++) { 279 for (;page_count_ < article_proto->pages_size(); page_count_++) {
205 const DistilledPageProto& page = article_proto->pages(page_count_); 280 const DistilledPageProto& page = article_proto->pages(page_count_);
206 SendJavaScript( 281 SendJavaScript(
207 viewer::GetUnsafeIncrementalDistilledPageJs( 282 viewer::GetUnsafeIncrementalDistilledPageJs(
208 &page, 283 &page,
209 page_count_ == article_proto->pages_size())); 284 page_count_ == article_proto->pages_size()));
210 } 285 }
211 } 286 }
212 // No need to hold on to the ViewerHandle now that distillation is complete. 287 // No need to hold on to the ViewerHandle now that distillation is complete.
213 viewer_handle_.reset(); 288 viewer_handle_.reset();
214 } 289 }
215 290
216 void DomDistillerViewerSource::RequestViewerHandle::OnArticleUpdated( 291 void DomDistillerViewerSource::RequestViewerHandle::OnArticleUpdated(
217 ArticleDistillationUpdate article_update) { 292 ArticleDistillationUpdate article_update) {
218 for (;page_count_ < static_cast<int>(article_update.GetPagesSize()); 293 for (;page_count_ < static_cast<int>(article_update.GetPagesSize());
219 page_count_++) { 294 page_count_++) {
220 const DistilledPageProto& page = 295 const DistilledPageProto& page =
221 article_update.GetDistilledPage(page_count_); 296 article_update.GetDistilledPage(page_count_);
222 if (page_count_ == 0) { 297 if (page_count_ == 0) {
298 template_observer_->setInitialContent(
299 viewer::GetUnsafeIncrementalDistilledPageJs(&page, false));
300
223 // This is the first page, so send Viewer page scaffolding too. 301 // This is the first page, so send Viewer page scaffolding too.
224 std::string unsafe_page_html = viewer::GetUnsafePartialArticleHtml( 302 std::string unsafe_page_html = viewer::GetUnsafeArticleTemplateHtml(
225 &page, 303 &page,
226 distilled_page_prefs_->GetTheme(), 304 distilled_page_prefs_->GetTheme(),
227 distilled_page_prefs_->GetFontFamily()); 305 distilled_page_prefs_->GetFontFamily());
228 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); 306 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html));
229 } else { 307 } else {
230 SendJavaScript( 308 // Send the page content to the client.
231 viewer::GetUnsafeIncrementalDistilledPageJs(&page, false)); 309 SendJavaScript(viewer::GetUnsafeIncrementalDistilledPageJs(&page, false));
cjhopman 2015/03/24 01:45:36 Isn't it possible now that the second page has it'
mdjones 2015/03/24 18:42:52 Done/See general comment.
232 } 310 }
233 } 311 }
234 } 312 }
235 313
236 void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle( 314 void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle(
237 scoped_ptr<ViewerHandle> viewer_handle) { 315 scoped_ptr<ViewerHandle> viewer_handle) {
238 viewer_handle_ = viewer_handle.Pass(); 316 viewer_handle_ = viewer_handle.Pass();
239 } 317 }
240 318
241 void DomDistillerViewerSource::RequestViewerHandle::OnChangeTheme( 319 void DomDistillerViewerSource::RequestViewerHandle::OnChangeTheme(
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 // The service returned a |ViewerHandle| and guarantees it will call 385 // The service returned a |ViewerHandle| and guarantees it will call
308 // the |RequestViewerHandle|, so passing ownership to it, to ensure the 386 // the |RequestViewerHandle|, so passing ownership to it, to ensure the
309 // request is not cancelled. The |RequestViewerHandle| will delete itself 387 // request is not cancelled. The |RequestViewerHandle| will delete itself
310 // after receiving the callback. 388 // after receiving the callback.
311 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass()); 389 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass());
312 } else { 390 } else {
313 // The service did not return a |ViewerHandle|, which means the 391 // The service did not return a |ViewerHandle|, which means the
314 // |RequestViewerHandle| will never be called, so clean up now. 392 // |RequestViewerHandle| will never be called, so clean up now.
315 delete request_viewer_handle; 393 delete request_viewer_handle;
316 394
395 WebContentsErrorObserver::CreateForWebContents(web_contents);
396
317 std::string error_page_html = viewer::GetErrorPageHtml( 397 std::string error_page_html = viewer::GetErrorPageHtml(
318 dom_distiller_service_->GetDistilledPagePrefs()->GetTheme(), 398 dom_distiller_service_->GetDistilledPagePrefs()->GetTheme(),
319 dom_distiller_service_->GetDistilledPagePrefs()->GetFontFamily()); 399 dom_distiller_service_->GetDistilledPagePrefs()->GetFontFamily());
320 callback.Run(base::RefCountedString::TakeString(&error_page_html)); 400 callback.Run(base::RefCountedString::TakeString(&error_page_html));
321 } 401 }
322 }; 402 };
323 403
324 std::string DomDistillerViewerSource::GetMimeType( 404 std::string DomDistillerViewerSource::GetMimeType(
325 const std::string& path) const { 405 const std::string& path) const {
326 if (kViewerCssPath == path) { 406 if (kViewerCssPath == path) {
(...skipping 15 matching lines...) Expand all
342 const net::URLRequest* request, 422 const net::URLRequest* request,
343 std::string* path) const { 423 std::string* path) const {
344 } 424 }
345 425
346 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc() 426 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc()
347 const { 427 const {
348 return "object-src 'none'; style-src 'self' https://fonts.googleapis.com;"; 428 return "object-src 'none'; style-src 'self' https://fonts.googleapis.com;";
349 } 429 }
350 430
351 } // namespace dom_distiller 431 } // namespace dom_distiller
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698