OLD | NEW |
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/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
| 15 #include "components/dom_distiller/core/distilled_page_prefs.h" |
| 16 #include "components/dom_distiller/core/dom_distiller_service.h" |
15 #include "components/dom_distiller/core/task_tracker.h" | 17 #include "components/dom_distiller/core/task_tracker.h" |
16 #include "components/dom_distiller/core/url_constants.h" | 18 #include "components/dom_distiller/core/url_constants.h" |
17 #include "components/dom_distiller/core/viewer.h" | 19 #include "components/dom_distiller/core/viewer.h" |
18 #include "content/public/browser/navigation_details.h" | 20 #include "content/public/browser/navigation_details.h" |
19 #include "content/public/browser/navigation_entry.h" | 21 #include "content/public/browser/navigation_entry.h" |
20 #include "content/public/browser/render_frame_host.h" | 22 #include "content/public/browser/render_frame_host.h" |
21 #include "content/public/browser/render_view_host.h" | 23 #include "content/public/browser/render_view_host.h" |
22 #include "content/public/browser/web_contents.h" | 24 #include "content/public/browser/web_contents.h" |
23 #include "content/public/browser/web_contents_observer.h" | 25 #include "content/public/browser/web_contents_observer.h" |
24 #include "net/base/url_util.h" | 26 #include "net/base/url_util.h" |
25 #include "net/url_request/url_request.h" | 27 #include "net/url_request/url_request.h" |
26 | 28 |
27 namespace dom_distiller { | 29 namespace dom_distiller { |
28 | 30 |
29 // Handles receiving data asynchronously for a specific entry, and passing | 31 // Handles receiving data asynchronously for a specific entry, and passing |
30 // it along to the data callback for the data source. Lifetime matches that of | 32 // it along to the data callback for the data source. Lifetime matches that of |
31 // the current main frame's page in the Viewer instance. | 33 // the current main frame's page in the Viewer instance. |
32 class DomDistillerViewerSource::RequestViewerHandle | 34 class DomDistillerViewerSource::RequestViewerHandle |
33 : public ViewRequestDelegate, | 35 : public ViewRequestDelegate, |
34 public content::WebContentsObserver { | 36 public content::WebContentsObserver, |
| 37 public DistilledPagePrefs::Observer { |
35 public: | 38 public: |
36 explicit RequestViewerHandle( | 39 explicit RequestViewerHandle( |
37 content::WebContents* web_contents, | 40 content::WebContents* web_contents, |
38 const std::string& expected_scheme, | 41 const std::string& expected_scheme, |
39 const std::string& expected_request_path, | 42 const std::string& expected_request_path, |
40 const content::URLDataSource::GotDataCallback& callback); | 43 const content::URLDataSource::GotDataCallback& callback, |
| 44 DistilledPagePrefs* distilled_page_prefs); |
41 virtual ~RequestViewerHandle(); | 45 virtual ~RequestViewerHandle(); |
42 | 46 |
43 // ViewRequestDelegate implementation. | 47 // ViewRequestDelegate implementation: |
44 virtual void OnArticleReady( | 48 virtual void OnArticleReady( |
45 const DistilledArticleProto* article_proto) OVERRIDE; | 49 const DistilledArticleProto* article_proto) OVERRIDE; |
46 | 50 |
47 virtual void OnArticleUpdated( | 51 virtual void OnArticleUpdated( |
48 ArticleDistillationUpdate article_update) OVERRIDE; | 52 ArticleDistillationUpdate article_update) OVERRIDE; |
49 | 53 |
50 void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle); | 54 void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle); |
51 | 55 |
52 // WebContentsObserver: | 56 // content::WebContentsObserver implementation: |
53 virtual void DidNavigateMainFrame( | 57 virtual void DidNavigateMainFrame( |
54 const content::LoadCommittedDetails& details, | 58 const content::LoadCommittedDetails& details, |
55 const content::FrameNavigateParams& params) OVERRIDE; | 59 const content::FrameNavigateParams& params) OVERRIDE; |
56 virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE; | 60 virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE; |
57 virtual void WebContentsDestroyed() OVERRIDE; | 61 virtual void WebContentsDestroyed() OVERRIDE; |
58 virtual void DidFinishLoad(content::RenderFrameHost* render_frame_host, | 62 virtual void DidFinishLoad(content::RenderFrameHost* render_frame_host, |
59 const GURL& validated_url) OVERRIDE; | 63 const GURL& validated_url) OVERRIDE; |
60 | 64 |
61 private: | 65 private: |
62 // Sends JavaScript to the attached Viewer, buffering data if the viewer isn't | 66 // Sends JavaScript to the attached Viewer, buffering data if the viewer isn't |
63 // ready. | 67 // ready. |
64 void SendJavaScript(const std::string& buffer); | 68 void SendJavaScript(const std::string& buffer); |
65 | 69 |
66 // Cancels the current view request. Once called, no updates will be | 70 // Cancels the current view request. Once called, no updates will be |
67 // propagated to the view, and the request to DomDistillerService will be | 71 // propagated to the view, and the request to DomDistillerService will be |
68 // cancelled. | 72 // cancelled. |
69 void Cancel(); | 73 void Cancel(); |
70 | 74 |
| 75 // DistilledPagePrefs::Observer implementation: |
| 76 virtual void OnChangeTheme(DistilledPagePrefs::Theme new_theme) OVERRIDE; |
| 77 |
71 // The handle to the view request towards the DomDistillerService. It | 78 // The handle to the view request towards the DomDistillerService. It |
72 // needs to be kept around to ensure the distillation request finishes. | 79 // needs to be kept around to ensure the distillation request finishes. |
73 scoped_ptr<ViewerHandle> viewer_handle_; | 80 scoped_ptr<ViewerHandle> viewer_handle_; |
74 | 81 |
75 // The scheme hosting the current view request; | 82 // The scheme hosting the current view request; |
76 std::string expected_scheme_; | 83 std::string expected_scheme_; |
77 | 84 |
78 // The query path for the current view request. | 85 // The query path for the current view request. |
79 std::string expected_request_path_; | 86 std::string expected_request_path_; |
80 | 87 |
81 // Holds the callback to where the data retrieved is sent back. | 88 // Holds the callback to where the data retrieved is sent back. |
82 content::URLDataSource::GotDataCallback callback_; | 89 content::URLDataSource::GotDataCallback callback_; |
83 | 90 |
84 // Number of pages of the distilled article content that have been rendered by | 91 // Number of pages of the distilled article content that have been rendered by |
85 // the viewer. | 92 // the viewer. |
86 int page_count_; | 93 int page_count_; |
87 | 94 |
| 95 // Interface for accessing preferences for distilled pages. |
| 96 DistilledPagePrefs* distilled_page_prefs_; |
| 97 |
88 // Whether the page is sufficiently initialized to handle updates from the | 98 // Whether the page is sufficiently initialized to handle updates from the |
89 // distiller. | 99 // distiller. |
90 bool waiting_for_page_ready_; | 100 bool waiting_for_page_ready_; |
91 | 101 |
92 // Temporary store of pending JavaScript if the page isn't ready to receive | 102 // Temporary store of pending JavaScript if the page isn't ready to receive |
93 // data from distillation. | 103 // data from distillation. |
94 std::string buffer_; | 104 std::string buffer_; |
95 }; | 105 }; |
96 | 106 |
97 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle( | 107 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle( |
98 content::WebContents* web_contents, | 108 content::WebContents* web_contents, |
99 const std::string& expected_scheme, | 109 const std::string& expected_scheme, |
100 const std::string& expected_request_path, | 110 const std::string& expected_request_path, |
101 const content::URLDataSource::GotDataCallback& callback) | 111 const content::URLDataSource::GotDataCallback& callback, |
| 112 DistilledPagePrefs* distilled_page_prefs) |
102 : expected_scheme_(expected_scheme), | 113 : expected_scheme_(expected_scheme), |
103 expected_request_path_(expected_request_path), | 114 expected_request_path_(expected_request_path), |
104 callback_(callback), | 115 callback_(callback), |
105 page_count_(0), | 116 page_count_(0), |
| 117 distilled_page_prefs_(distilled_page_prefs), |
106 waiting_for_page_ready_(true) { | 118 waiting_for_page_ready_(true) { |
107 content::WebContentsObserver::Observe(web_contents); | 119 content::WebContentsObserver::Observe(web_contents); |
| 120 distilled_page_prefs_->AddObserver(this); |
108 } | 121 } |
109 | 122 |
110 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() { | 123 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() { |
| 124 distilled_page_prefs_->RemoveObserver(this); |
111 } | 125 } |
112 | 126 |
113 void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript( | 127 void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript( |
114 const std::string& buffer) { | 128 const std::string& buffer) { |
115 if (waiting_for_page_ready_) { | 129 if (waiting_for_page_ready_) { |
116 buffer_ += buffer; | 130 buffer_ += buffer; |
117 } else { | 131 } else { |
118 if (web_contents()) { | 132 if (web_contents()) { |
119 web_contents()->GetMainFrame()->ExecuteJavaScript( | 133 web_contents()->GetMainFrame()->ExecuteJavaScript( |
120 base::UTF8ToUTF16(buffer)); | 134 base::UTF8ToUTF16(buffer)); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 return; | 180 return; |
167 } | 181 } |
168 web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(buffer_)); | 182 web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(buffer_)); |
169 buffer_.clear(); | 183 buffer_.clear(); |
170 } | 184 } |
171 | 185 |
172 void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady( | 186 void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady( |
173 const DistilledArticleProto* article_proto) { | 187 const DistilledArticleProto* article_proto) { |
174 if (page_count_ == 0) { | 188 if (page_count_ == 0) { |
175 // This is a single-page article. | 189 // This is a single-page article. |
176 std::string unsafe_page_html = viewer::GetUnsafeArticleHtml(article_proto); | 190 std::string unsafe_page_html = viewer::GetUnsafeArticleHtml( |
| 191 article_proto, distilled_page_prefs_->GetTheme()); |
177 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); | 192 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); |
178 } else if (page_count_ == article_proto->pages_size()) { | 193 } else if (page_count_ == article_proto->pages_size()) { |
179 // We may still be showing the "Loading" indicator. | 194 // We may still be showing the "Loading" indicator. |
180 SendJavaScript(viewer::GetToggleLoadingIndicatorJs(true)); | 195 SendJavaScript(viewer::GetToggleLoadingIndicatorJs(true)); |
181 } else { | 196 } else { |
182 // It's possible that we didn't get some incremental updates from the | 197 // It's possible that we didn't get some incremental updates from the |
183 // distiller. Ensure all remaining pages are flushed to the viewer. | 198 // distiller. Ensure all remaining pages are flushed to the viewer. |
184 for (;page_count_ < article_proto->pages_size(); page_count_++) { | 199 for (;page_count_ < article_proto->pages_size(); page_count_++) { |
185 const DistilledPageProto& page = article_proto->pages(page_count_); | 200 const DistilledPageProto& page = article_proto->pages(page_count_); |
186 SendJavaScript( | 201 SendJavaScript( |
187 viewer::GetUnsafeIncrementalDistilledPageJs( | 202 viewer::GetUnsafeIncrementalDistilledPageJs( |
188 &page, | 203 &page, |
189 page_count_ == article_proto->pages_size())); | 204 page_count_ == article_proto->pages_size())); |
190 } | 205 } |
191 } | 206 } |
192 // No need to hold on to the ViewerHandle now that distillation is complete. | 207 // No need to hold on to the ViewerHandle now that distillation is complete. |
193 viewer_handle_.reset(); | 208 viewer_handle_.reset(); |
194 } | 209 } |
195 | 210 |
196 void DomDistillerViewerSource::RequestViewerHandle::OnArticleUpdated( | 211 void DomDistillerViewerSource::RequestViewerHandle::OnArticleUpdated( |
197 ArticleDistillationUpdate article_update) { | 212 ArticleDistillationUpdate article_update) { |
198 for (;page_count_ < static_cast<int>(article_update.GetPagesSize()); | 213 for (;page_count_ < static_cast<int>(article_update.GetPagesSize()); |
199 page_count_++) { | 214 page_count_++) { |
200 const DistilledPageProto& page = | 215 const DistilledPageProto& page = |
201 article_update.GetDistilledPage(page_count_); | 216 article_update.GetDistilledPage(page_count_); |
202 if (page_count_ == 0) { | 217 if (page_count_ == 0) { |
203 // This is the first page, so send Viewer page scaffolding too. | 218 // This is the first page, so send Viewer page scaffolding too. |
204 std::string unsafe_page_html = viewer::GetUnsafePartialArticleHtml(&page); | 219 std::string unsafe_page_html = viewer::GetUnsafePartialArticleHtml( |
| 220 &page, distilled_page_prefs_->GetTheme()); |
205 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); | 221 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); |
206 } else { | 222 } else { |
207 SendJavaScript( | 223 SendJavaScript( |
208 viewer::GetUnsafeIncrementalDistilledPageJs(&page, false)); | 224 viewer::GetUnsafeIncrementalDistilledPageJs(&page, false)); |
209 } | 225 } |
210 } | 226 } |
211 } | 227 } |
212 | 228 |
213 void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle( | 229 void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle( |
214 scoped_ptr<ViewerHandle> viewer_handle) { | 230 scoped_ptr<ViewerHandle> viewer_handle) { |
215 viewer_handle_ = viewer_handle.Pass(); | 231 viewer_handle_ = viewer_handle.Pass(); |
216 } | 232 } |
217 | 233 |
| 234 void DomDistillerViewerSource::RequestViewerHandle::OnChangeTheme( |
| 235 DistilledPagePrefs::Theme new_theme) { |
| 236 SendJavaScript(viewer::GetDistilledPageThemeJs(new_theme)); |
| 237 } |
| 238 |
218 DomDistillerViewerSource::DomDistillerViewerSource( | 239 DomDistillerViewerSource::DomDistillerViewerSource( |
219 DomDistillerServiceInterface* dom_distiller_service, | 240 DomDistillerServiceInterface* dom_distiller_service, |
220 const std::string& scheme) | 241 const std::string& scheme) |
221 : scheme_(scheme), dom_distiller_service_(dom_distiller_service) { | 242 : scheme_(scheme), dom_distiller_service_(dom_distiller_service) { |
222 } | 243 } |
223 | 244 |
224 DomDistillerViewerSource::~DomDistillerViewerSource() { | 245 DomDistillerViewerSource::~DomDistillerViewerSource() { |
225 } | 246 } |
226 | 247 |
227 std::string DomDistillerViewerSource::GetSource() const { | 248 std::string DomDistillerViewerSource::GetSource() const { |
(...skipping 26 matching lines...) Expand all Loading... |
254 content::WebContents* web_contents = | 275 content::WebContents* web_contents = |
255 content::WebContents::FromRenderFrameHost( | 276 content::WebContents::FromRenderFrameHost( |
256 content::RenderFrameHost::FromID(render_process_id, | 277 content::RenderFrameHost::FromID(render_process_id, |
257 render_frame_id)); | 278 render_frame_id)); |
258 DCHECK(web_contents); | 279 DCHECK(web_contents); |
259 // An empty |path| is invalid, but guard against it. If not empty, assume | 280 // An empty |path| is invalid, but guard against it. If not empty, assume |
260 // |path| starts with '?', which is stripped away. | 281 // |path| starts with '?', which is stripped away. |
261 const std::string path_after_query_separator = | 282 const std::string path_after_query_separator = |
262 path.size() > 0 ? path.substr(1) : ""; | 283 path.size() > 0 ? path.substr(1) : ""; |
263 RequestViewerHandle* request_viewer_handle = new RequestViewerHandle( | 284 RequestViewerHandle* request_viewer_handle = new RequestViewerHandle( |
264 web_contents, scheme_, path_after_query_separator, callback); | 285 web_contents, scheme_, path_after_query_separator, callback, |
| 286 dom_distiller_service_->GetDistilledPagePrefs()); |
265 scoped_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest( | 287 scoped_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest( |
266 dom_distiller_service_, path, request_viewer_handle); | 288 dom_distiller_service_, path, request_viewer_handle); |
267 | 289 |
268 if (viewer_handle) { | 290 if (viewer_handle) { |
269 // The service returned a |ViewerHandle| and guarantees it will call | 291 // The service returned a |ViewerHandle| and guarantees it will call |
270 // the |RequestViewerHandle|, so passing ownership to it, to ensure the | 292 // the |RequestViewerHandle|, so passing ownership to it, to ensure the |
271 // request is not cancelled. The |RequestViewerHandle| will delete itself | 293 // request is not cancelled. The |RequestViewerHandle| will delete itself |
272 // after receiving the callback. | 294 // after receiving the callback. |
273 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass()); | 295 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass()); |
274 } else { | 296 } else { |
275 // The service did not return a |ViewerHandle|, which means the | 297 // The service did not return a |ViewerHandle|, which means the |
276 // |RequestViewerHandle| will never be called, so clean up now. | 298 // |RequestViewerHandle| will never be called, so clean up now. |
277 delete request_viewer_handle; | 299 delete request_viewer_handle; |
278 | 300 |
279 std::string error_page_html = viewer::GetErrorPageHtml(); | 301 std::string error_page_html = viewer::GetErrorPageHtml( |
| 302 dom_distiller_service_->GetDistilledPagePrefs()->GetTheme()); |
280 callback.Run(base::RefCountedString::TakeString(&error_page_html)); | 303 callback.Run(base::RefCountedString::TakeString(&error_page_html)); |
281 } | 304 } |
282 }; | 305 }; |
283 | 306 |
284 std::string DomDistillerViewerSource::GetMimeType( | 307 std::string DomDistillerViewerSource::GetMimeType( |
285 const std::string& path) const { | 308 const std::string& path) const { |
286 if (kViewerCssPath == path) { | 309 if (kViewerCssPath == path) { |
287 return "text/css"; | 310 return "text/css"; |
288 } | 311 } |
289 if (kViewerJsPath == path) { | 312 if (kViewerJsPath == path) { |
(...skipping 12 matching lines...) Expand all Loading... |
302 const net::URLRequest* request, | 325 const net::URLRequest* request, |
303 std::string* path) const { | 326 std::string* path) const { |
304 } | 327 } |
305 | 328 |
306 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc() | 329 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc() |
307 const { | 330 const { |
308 return "object-src 'none'; style-src 'self';"; | 331 return "object-src 'none'; style-src 'self';"; |
309 } | 332 } |
310 | 333 |
311 } // namespace dom_distiller | 334 } // namespace dom_distiller |
OLD | NEW |