| 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 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 public DistilledPagePrefs::Observer { | 39 public DistilledPagePrefs::Observer { |
| 40 public: | 40 public: |
| 41 explicit RequestViewerHandle( | 41 explicit RequestViewerHandle( |
| 42 content::WebContents* web_contents, | 42 content::WebContents* web_contents, |
| 43 const std::string& expected_scheme, | 43 const std::string& expected_scheme, |
| 44 const std::string& expected_request_path, | 44 const std::string& expected_request_path, |
| 45 const content::URLDataSource::GotDataCallback& callback, | 45 const content::URLDataSource::GotDataCallback& callback, |
| 46 DistilledPagePrefs* distilled_page_prefs); | 46 DistilledPagePrefs* distilled_page_prefs); |
| 47 ~RequestViewerHandle() override; | 47 ~RequestViewerHandle() override; |
| 48 | 48 |
| 49 // Flag this request as an error and send the error page template. |
| 50 void flagAsErrorPage(); |
| 51 |
| 49 // ViewRequestDelegate implementation: | 52 // ViewRequestDelegate implementation: |
| 50 void OnArticleReady(const DistilledArticleProto* article_proto) override; | 53 void OnArticleReady(const DistilledArticleProto* article_proto) override; |
| 51 | 54 |
| 52 void OnArticleUpdated(ArticleDistillationUpdate article_update) override; | 55 void OnArticleUpdated(ArticleDistillationUpdate article_update) override; |
| 53 | 56 |
| 54 void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle); | 57 void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle); |
| 55 | 58 |
| 56 // content::WebContentsObserver implementation: | 59 // content::WebContentsObserver implementation: |
| 57 void DidNavigateMainFrame( | 60 void DidNavigateMainFrame( |
| 58 const content::LoadCommittedDetails& details, | 61 const content::LoadCommittedDetails& details, |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 // Interface for accessing preferences for distilled pages. | 100 // Interface for accessing preferences for distilled pages. |
| 98 DistilledPagePrefs* distilled_page_prefs_; | 101 DistilledPagePrefs* distilled_page_prefs_; |
| 99 | 102 |
| 100 // Whether the page is sufficiently initialized to handle updates from the | 103 // Whether the page is sufficiently initialized to handle updates from the |
| 101 // distiller. | 104 // distiller. |
| 102 bool waiting_for_page_ready_; | 105 bool waiting_for_page_ready_; |
| 103 | 106 |
| 104 // Temporary store of pending JavaScript if the page isn't ready to receive | 107 // Temporary store of pending JavaScript if the page isn't ready to receive |
| 105 // data from distillation. | 108 // data from distillation. |
| 106 std::string buffer_; | 109 std::string buffer_; |
| 110 |
| 111 // Flag to tell this observer that the web contents are in an error state. |
| 112 bool is_error_page_; |
| 107 }; | 113 }; |
| 108 | 114 |
| 109 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle( | 115 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle( |
| 110 content::WebContents* web_contents, | 116 content::WebContents* web_contents, |
| 111 const std::string& expected_scheme, | 117 const std::string& expected_scheme, |
| 112 const std::string& expected_request_path, | 118 const std::string& expected_request_path, |
| 113 const content::URLDataSource::GotDataCallback& callback, | 119 const content::URLDataSource::GotDataCallback& callback, |
| 114 DistilledPagePrefs* distilled_page_prefs) | 120 DistilledPagePrefs* distilled_page_prefs) |
| 115 : expected_scheme_(expected_scheme), | 121 : expected_scheme_(expected_scheme), |
| 116 expected_request_path_(expected_request_path), | 122 expected_request_path_(expected_request_path), |
| 117 callback_(callback), | 123 callback_(callback), |
| 118 page_count_(0), | 124 page_count_(0), |
| 119 distilled_page_prefs_(distilled_page_prefs), | 125 distilled_page_prefs_(distilled_page_prefs), |
| 120 waiting_for_page_ready_(true) { | 126 waiting_for_page_ready_(true), |
| 127 is_error_page_(false) { |
| 121 content::WebContentsObserver::Observe(web_contents); | 128 content::WebContentsObserver::Observe(web_contents); |
| 122 distilled_page_prefs_->AddObserver(this); | 129 distilled_page_prefs_->AddObserver(this); |
| 123 } | 130 } |
| 124 | 131 |
| 125 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() { | 132 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() { |
| 126 distilled_page_prefs_->RemoveObserver(this); | 133 distilled_page_prefs_->RemoveObserver(this); |
| 127 } | 134 } |
| 128 | 135 |
| 136 void DomDistillerViewerSource::RequestViewerHandle::flagAsErrorPage() { |
| 137 is_error_page_ = true; |
| 138 std::string error_page_html = viewer::GetErrorPageHtml( |
| 139 distilled_page_prefs_->GetTheme(), |
| 140 distilled_page_prefs_->GetFontFamily()); |
| 141 callback_.Run(base::RefCountedString::TakeString(&error_page_html)); |
| 142 } |
| 143 |
| 129 void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript( | 144 void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript( |
| 130 const std::string& buffer) { | 145 const std::string& buffer) { |
| 131 if (waiting_for_page_ready_) { | 146 if (waiting_for_page_ready_) { |
| 132 buffer_ += buffer; | 147 buffer_ += buffer; |
| 133 } else { | 148 } else { |
| 134 if (web_contents()) { | 149 if (web_contents()) { |
| 135 web_contents()->GetMainFrame()->ExecuteJavaScript( | 150 web_contents()->GetMainFrame()->ExecuteJavaScript( |
| 136 base::UTF8ToUTF16(buffer)); | 151 base::UTF8ToUTF16(buffer)); |
| 137 } | 152 } |
| 138 } | 153 } |
| 139 } | 154 } |
| 140 | 155 |
| 141 void DomDistillerViewerSource::RequestViewerHandle::DidNavigateMainFrame( | 156 void DomDistillerViewerSource::RequestViewerHandle::DidNavigateMainFrame( |
| 142 const content::LoadCommittedDetails& details, | 157 const content::LoadCommittedDetails& details, |
| 143 const content::FrameNavigateParams& params) { | 158 const content::FrameNavigateParams& params) { |
| 144 const GURL& navigation = details.entry->GetURL(); | 159 const GURL& navigation = details.entry->GetURL(); |
| 145 if (details.is_in_page || ( | 160 if (details.is_in_page || ( |
| 146 navigation.SchemeIs(expected_scheme_.c_str()) && | 161 navigation.SchemeIs(expected_scheme_.c_str()) && |
| 147 expected_request_path_ == navigation.query())) { | 162 expected_request_path_ == navigation.query())) { |
| 148 // In-page navigations, as well as the main view request can be ignored. | 163 // In-page navigations, as well as the main view request can be ignored. |
| 149 return; | 164 return; |
| 150 } | 165 } |
| 151 | 166 |
| 152 Cancel(); | 167 Cancel(); |
| 153 | |
| 154 } | 168 } |
| 155 | 169 |
| 156 void DomDistillerViewerSource::RequestViewerHandle::RenderProcessGone( | 170 void DomDistillerViewerSource::RequestViewerHandle::RenderProcessGone( |
| 157 base::TerminationStatus status) { | 171 base::TerminationStatus status) { |
| 158 Cancel(); | 172 Cancel(); |
| 159 } | 173 } |
| 160 | 174 |
| 161 void DomDistillerViewerSource::RequestViewerHandle::WebContentsDestroyed() { | 175 void DomDistillerViewerSource::RequestViewerHandle::WebContentsDestroyed() { |
| 162 Cancel(); | 176 Cancel(); |
| 163 } | 177 } |
| 164 | 178 |
| 165 void DomDistillerViewerSource::RequestViewerHandle::Cancel() { | 179 void DomDistillerViewerSource::RequestViewerHandle::Cancel() { |
| 166 // No need to listen for notifications. | 180 // No need to listen for notifications. |
| 167 content::WebContentsObserver::Observe(NULL); | 181 content::WebContentsObserver::Observe(NULL); |
| 168 | 182 |
| 169 // Schedule the Viewer for deletion. Ensures distillation is cancelled, and | 183 // Schedule the Viewer for deletion. Ensures distillation is cancelled, and |
| 170 // any pending data stored in |buffer_| is released. | 184 // any pending data stored in |buffer_| is released. |
| 171 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | 185 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
| 172 } | 186 } |
| 173 | 187 |
| 174 void DomDistillerViewerSource::RequestViewerHandle::DidFinishLoad( | 188 void DomDistillerViewerSource::RequestViewerHandle::DidFinishLoad( |
| 175 content::RenderFrameHost* render_frame_host, | 189 content::RenderFrameHost* render_frame_host, |
| 176 const GURL& validated_url) { | 190 const GURL& validated_url) { |
| 191 if (is_error_page_) { |
| 192 waiting_for_page_ready_ = false; |
| 193 SendJavaScript(viewer::GetErrorPageJs()); |
| 194 Cancel(); // This will cause the object to clean itself up. |
| 195 return; |
| 196 } |
| 197 |
| 177 if (render_frame_host->GetParent()) { | 198 if (render_frame_host->GetParent()) { |
| 178 return; | 199 return; |
| 179 } | 200 } |
| 180 waiting_for_page_ready_ = false; | 201 waiting_for_page_ready_ = false; |
| 181 if (buffer_.empty()) { | 202 if (buffer_.empty()) { |
| 182 return; | 203 return; |
| 183 } | 204 } |
| 184 web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(buffer_)); | 205 web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(buffer_)); |
| 185 buffer_.clear(); | 206 buffer_.clear(); |
| 186 } | 207 } |
| 187 | 208 |
| 188 void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady( | 209 void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady( |
| 189 const DistilledArticleProto* article_proto) { | 210 const DistilledArticleProto* article_proto) { |
| 190 if (page_count_ == 0) { | 211 if (page_count_ == 0) { |
| 191 // This is a single-page article. | 212 std::string unsafe_page_html = viewer::GetUnsafeArticleTemplateHtml( |
| 192 std::string unsafe_page_html = | 213 &article_proto->pages(0), |
| 193 viewer::GetUnsafeArticleHtml( | 214 distilled_page_prefs_->GetTheme(), |
| 194 article_proto, | 215 distilled_page_prefs_->GetFontFamily()); |
| 195 distilled_page_prefs_->GetTheme(), | |
| 196 distilled_page_prefs_->GetFontFamily()); | |
| 197 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); | 216 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); |
| 217 // Send first page to client. |
| 218 SendJavaScript(viewer::GetUnsafeArticleContentJs(article_proto)); |
| 198 } else if (page_count_ == article_proto->pages_size()) { | 219 } else if (page_count_ == article_proto->pages_size()) { |
| 199 // We may still be showing the "Loading" indicator. | 220 // We may still be showing the "Loading" indicator. |
| 200 SendJavaScript(viewer::GetToggleLoadingIndicatorJs(true)); | 221 SendJavaScript(viewer::GetToggleLoadingIndicatorJs(true)); |
| 201 } else { | 222 } else { |
| 202 // It's possible that we didn't get some incremental updates from the | 223 // It's possible that we didn't get some incremental updates from the |
| 203 // distiller. Ensure all remaining pages are flushed to the viewer. | 224 // distiller. Ensure all remaining pages are flushed to the viewer. |
| 204 for (;page_count_ < article_proto->pages_size(); page_count_++) { | 225 for (;page_count_ < article_proto->pages_size(); page_count_++) { |
| 205 const DistilledPageProto& page = article_proto->pages(page_count_); | 226 const DistilledPageProto& page = article_proto->pages(page_count_); |
| 206 SendJavaScript( | 227 SendJavaScript( |
| 207 viewer::GetUnsafeIncrementalDistilledPageJs( | 228 viewer::GetUnsafeIncrementalDistilledPageJs( |
| 208 &page, | 229 &page, |
| 209 page_count_ == article_proto->pages_size())); | 230 page_count_ == article_proto->pages_size())); |
| 210 } | 231 } |
| 211 } | 232 } |
| 212 // No need to hold on to the ViewerHandle now that distillation is complete. | 233 // No need to hold on to the ViewerHandle now that distillation is complete. |
| 213 viewer_handle_.reset(); | 234 viewer_handle_.reset(); |
| 214 } | 235 } |
| 215 | 236 |
| 216 void DomDistillerViewerSource::RequestViewerHandle::OnArticleUpdated( | 237 void DomDistillerViewerSource::RequestViewerHandle::OnArticleUpdated( |
| 217 ArticleDistillationUpdate article_update) { | 238 ArticleDistillationUpdate article_update) { |
| 218 for (;page_count_ < static_cast<int>(article_update.GetPagesSize()); | 239 for (;page_count_ < static_cast<int>(article_update.GetPagesSize()); |
| 219 page_count_++) { | 240 page_count_++) { |
| 220 const DistilledPageProto& page = | 241 const DistilledPageProto& page = |
| 221 article_update.GetDistilledPage(page_count_); | 242 article_update.GetDistilledPage(page_count_); |
| 222 if (page_count_ == 0) { | 243 if (page_count_ == 0) { |
| 223 // This is the first page, so send Viewer page scaffolding too. | 244 // This is the first page, so send Viewer page scaffolding too. |
| 224 std::string unsafe_page_html = viewer::GetUnsafePartialArticleHtml( | 245 std::string unsafe_page_html = viewer::GetUnsafeArticleTemplateHtml( |
| 225 &page, | 246 &page, |
| 226 distilled_page_prefs_->GetTheme(), | 247 distilled_page_prefs_->GetTheme(), |
| 227 distilled_page_prefs_->GetFontFamily()); | 248 distilled_page_prefs_->GetFontFamily()); |
| 228 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); | 249 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); |
| 229 } else { | |
| 230 SendJavaScript( | |
| 231 viewer::GetUnsafeIncrementalDistilledPageJs(&page, false)); | |
| 232 } | 250 } |
| 251 // Send the page content to the client. |
| 252 SendJavaScript(viewer::GetUnsafeIncrementalDistilledPageJs(&page, false)); |
| 233 } | 253 } |
| 234 } | 254 } |
| 235 | 255 |
| 236 void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle( | 256 void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle( |
| 237 scoped_ptr<ViewerHandle> viewer_handle) { | 257 scoped_ptr<ViewerHandle> viewer_handle) { |
| 238 viewer_handle_ = viewer_handle.Pass(); | 258 viewer_handle_ = viewer_handle.Pass(); |
| 239 } | 259 } |
| 240 | 260 |
| 241 void DomDistillerViewerSource::RequestViewerHandle::OnChangeTheme( | 261 void DomDistillerViewerSource::RequestViewerHandle::OnChangeTheme( |
| 242 DistilledPagePrefs::Theme new_theme) { | 262 DistilledPagePrefs::Theme new_theme) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 dom_distiller_service_, path, request_viewer_handle, | 323 dom_distiller_service_, path, request_viewer_handle, |
| 304 web_contents->GetContainerBounds().size()); | 324 web_contents->GetContainerBounds().size()); |
| 305 | 325 |
| 306 if (viewer_handle) { | 326 if (viewer_handle) { |
| 307 // The service returned a |ViewerHandle| and guarantees it will call | 327 // The service returned a |ViewerHandle| and guarantees it will call |
| 308 // the |RequestViewerHandle|, so passing ownership to it, to ensure the | 328 // the |RequestViewerHandle|, so passing ownership to it, to ensure the |
| 309 // request is not cancelled. The |RequestViewerHandle| will delete itself | 329 // request is not cancelled. The |RequestViewerHandle| will delete itself |
| 310 // after receiving the callback. | 330 // after receiving the callback. |
| 311 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass()); | 331 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass()); |
| 312 } else { | 332 } else { |
| 313 // The service did not return a |ViewerHandle|, which means the | 333 request_viewer_handle->flagAsErrorPage(); |
| 314 // |RequestViewerHandle| will never be called, so clean up now. | |
| 315 delete request_viewer_handle; | |
| 316 | |
| 317 std::string error_page_html = viewer::GetErrorPageHtml( | |
| 318 dom_distiller_service_->GetDistilledPagePrefs()->GetTheme(), | |
| 319 dom_distiller_service_->GetDistilledPagePrefs()->GetFontFamily()); | |
| 320 callback.Run(base::RefCountedString::TakeString(&error_page_html)); | |
| 321 } | 334 } |
| 322 }; | 335 }; |
| 323 | 336 |
| 324 std::string DomDistillerViewerSource::GetMimeType( | 337 std::string DomDistillerViewerSource::GetMimeType( |
| 325 const std::string& path) const { | 338 const std::string& path) const { |
| 326 if (kViewerCssPath == path) { | 339 if (kViewerCssPath == path) { |
| 327 return "text/css"; | 340 return "text/css"; |
| 328 } | 341 } |
| 329 if (kViewerJsPath == path) { | 342 if (kViewerJsPath == path) { |
| 330 return "text/javascript"; | 343 return "text/javascript"; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 342 const net::URLRequest* request, | 355 const net::URLRequest* request, |
| 343 std::string* path) const { | 356 std::string* path) const { |
| 344 } | 357 } |
| 345 | 358 |
| 346 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc() | 359 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc() |
| 347 const { | 360 const { |
| 348 return "object-src 'none'; style-src 'self' https://fonts.googleapis.com;"; | 361 return "object-src 'none'; style-src 'self' https://fonts.googleapis.com;"; |
| 349 } | 362 } |
| 350 | 363 |
| 351 } // namespace dom_distiller | 364 } // namespace dom_distiller |
| OLD | NEW |