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

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

Issue 260073009: [dom_distiller] Add support for incremental viewer. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix ios Created 6 years, 7 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 | Annotate | Revision Log
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/strings/utf_string_conversions.h"
14 #include "components/dom_distiller/core/task_tracker.h" 15 #include "components/dom_distiller/core/task_tracker.h"
15 #include "components/dom_distiller/core/url_constants.h" 16 #include "components/dom_distiller/core/url_constants.h"
16 #include "components/dom_distiller/core/viewer.h" 17 #include "components/dom_distiller/core/viewer.h"
17 #include "content/public/browser/render_frame_host.h" 18 #include "content/public/browser/render_frame_host.h"
18 #include "content/public/browser/render_view_host.h" 19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/browser/web_contents_observer.h"
19 #include "net/url_request/url_request.h" 22 #include "net/url_request/url_request.h"
20 23
21 namespace dom_distiller { 24 namespace dom_distiller {
22 25
23 // Handles receiving data asynchronously for a specific entry, and passing 26 // Handles receiving data asynchronously for a specific entry, and passing
24 // it along to the data callback for the data source. 27 // it along to the data callback for the data source. Lifetime matches that of
28 // the RenderFrameHost for the Viewer instance.
Charlie Reis 2014/05/09 21:32:46 What are your expectations in the case that the We
Yaron 2014/05/12 18:48:17 It should go away. My intention was to have this b
Charlie Reis 2014/05/12 20:04:01 Oh, I misunderstand. That sounds good; one commen
25 class DomDistillerViewerSource::RequestViewerHandle 29 class DomDistillerViewerSource::RequestViewerHandle
26 : public ViewRequestDelegate { 30 : public ViewRequestDelegate,
31 public content::WebContentsObserver {
27 public: 32 public:
28 explicit RequestViewerHandle( 33 explicit RequestViewerHandle(
34 int render_process_id,
35 int render_frame_id,
29 const content::URLDataSource::GotDataCallback& callback); 36 const content::URLDataSource::GotDataCallback& callback);
30 virtual ~RequestViewerHandle(); 37 virtual ~RequestViewerHandle();
31 38
32 // ViewRequestDelegate implementation. 39 // ViewRequestDelegate implementation.
33 virtual void OnArticleReady( 40 virtual void OnArticleReady(
34 const DistilledArticleProto* article_proto) OVERRIDE; 41 const DistilledArticleProto* article_proto) OVERRIDE;
35 42
36 virtual void OnArticleUpdated( 43 virtual void OnArticleUpdated(
37 ArticleDistillationUpdate article_update) OVERRIDE; 44 ArticleDistillationUpdate article_update) OVERRIDE;
38 45
39 void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle); 46 void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle);
40 47
48 // WebContentsObserver:
49 virtual void AboutToNavigateRenderView(
50 content::RenderViewHost* render_view_host) OVERRIDE;
51 virtual void WebContentsDestroyed(content::WebContents* web_contents)
52 OVERRIDE;
53 virtual void DidFinishLoad(
54 int64 frame_id,
55 const GURL& validated_url,
56 bool is_main_frame,
57 content::RenderViewHost* render_view_host) OVERRIDE;
58
41 private: 59 private:
60 // Sends JavaScript to the attached Viewer, buffering data if the viewer isn't
61 // ready.
62 void SendJavaScript(const std::string& buffer);
63
64 // Cancel's the current view request. Once called, no updates will be
Charlie Reis 2014/05/09 21:32:46 nit: Cancels
Yaron 2014/05/12 18:48:17 Done.
Yaron 2014/05/12 18:48:17 Done.
65 // propagated to the view, and the request to DomDistillerService will be
66 // cancelled.
67 void Cancel();
68
42 // The handle to the view request towards the DomDistillerService. It 69 // The handle to the view request towards the DomDistillerService. It
43 // needs to be kept around to ensure the distillation request finishes. 70 // needs to be kept around to ensure the distillation request finishes.
44 scoped_ptr<ViewerHandle> viewer_handle_; 71 scoped_ptr<ViewerHandle> viewer_handle_;
45 72
46 // This holds the callback to where the data retrieved is sent back. 73 // WebContents associated with the Viewer's render process.
74 content::WebContents* web_contents_;
75
76 // Holds the callback to where the data retrieved is sent back.
47 content::URLDataSource::GotDataCallback callback_; 77 content::URLDataSource::GotDataCallback callback_;
78
79 // Number of pages that have been rendered by the viewer.
Charlie Reis 2014/05/09 21:32:46 I'm not sure what this comment is referring to. A
Yaron 2014/05/12 18:48:17 Conceptual pages of the article. Expanded the comm
80 int page_count_;
81
82 // Whether the page is sufficiently initialized to handle updates from the
83 // distiller.
84 bool waiting_for_page_ready_;
85
86 // Temporary store of pending JavaScript if the page isn't ready to receive
87 // data from distillation.
88 std::string buffer_;
48 }; 89 };
49 90
50 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle( 91 DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle(
92 int render_process_id,
93 int render_frame_id,
51 const content::URLDataSource::GotDataCallback& callback) 94 const content::URLDataSource::GotDataCallback& callback)
52 : callback_(callback) { 95 : web_contents_(content::WebContents::FromRenderFrameHost(
96 content::RenderFrameHost::FromID(render_process_id,
97 render_frame_id))),
98 callback_(callback),
99 page_count_(0),
100 waiting_for_page_ready_(true) {
101 content::WebContentsObserver::Observe(web_contents_);
53 } 102 }
54 103
55 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() { 104 DomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() {
105 // Balanced with constructor although can be a no-op if frame navigated away.
106 content::WebContentsObserver::Observe(NULL);
107 }
108
109 void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript(
110 const std::string& buffer) {
111 if (waiting_for_page_ready_) {
112 buffer_ += buffer;
113 } else {
114 if (web_contents_) {
115 web_contents_->GetMainFrame()->ExecuteJavaScript(
116 base::UTF8ToUTF16(buffer));
117 }
118 }
119 }
120
121 void DomDistillerViewerSource::RequestViewerHandle::WebContentsDestroyed(
122 content::WebContents* web_contents) {
123 Cancel();
124 }
125
126 void DomDistillerViewerSource::RequestViewerHandle::AboutToNavigateRenderView(
127 content::RenderViewHost* render_view_host) {
Charlie Reis 2014/05/09 21:32:46 nit: Wrong indent.
Yaron 2014/05/12 18:48:17 Done.
128 Cancel();
129 }
130
131 void DomDistillerViewerSource::RequestViewerHandle::Cancel() {
132 // Ensure we don't send any incremental updates to the Viewer.
133 web_contents_ = NULL;
134
135 // No need to listen for notifications.
136 content::WebContentsObserver::Observe(NULL);
137
138 // Schedule the Viewer for deletion. Ensures distillation is cancelled, and
139 // any pending data stored in |buffer_| is released.
140 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
141 }
142
143 void DomDistillerViewerSource::RequestViewerHandle::DidFinishLoad(
144 int64 frame_id,
145 const GURL& validated_url,
146 bool is_main_frame,
147 content::RenderViewHost* render_view_host) {
148 if (!is_main_frame || web_contents_ == NULL) {
149 return;
150 }
151 waiting_for_page_ready_ = false;
152 if (buffer_.empty()) return;
Charlie Reis 2014/05/09 21:32:46 nit: Return should be on its own line.
Yaron 2014/05/12 18:48:17 Done.
153
154 if (web_contents_) {
155 web_contents_->GetMainFrame()->ExecuteJavaScript(
156 base::UTF8ToUTF16(buffer_));
157 }
158 buffer_.clear();
56 } 159 }
57 160
58 void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady( 161 void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady(
59 const DistilledArticleProto* article_proto) { 162 const DistilledArticleProto* article_proto) {
60 std::string unsafe_page_html = viewer::GetUnsafeHtml(article_proto); 163 if (page_count_ == 0) {
61 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); 164 // This is a single-page article.
62 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 165 std::string unsafe_page_html = viewer::GetUnsafeArticleHtml(article_proto);
166 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html));
167 } else if (page_count_ == article_proto->pages_size()) {
168 // We may still be showing the "Loading" indicator.
169 SendJavaScript(viewer::GetToggleLoadingIndicatorJs(true));
170 } else {
171 // It's possible that we didn't get some incremental updates from the
172 // distiller. Ensure all remaining pages are flushed to the viewer.
173 for (;page_count_ < article_proto->pages_size();
174 page_count_++) {
Charlie Reis 2014/05/09 21:32:46 nit: Won't this fit on the previous line?
Yaron 2014/05/12 18:48:17 Done.
175 const DistilledPageProto& page = article_proto->pages(page_count_);
176 SendJavaScript(
177 viewer::GetUnsafeIncrementalDistilledPageJs(
178 &page,
179 page_count_ == article_proto->pages_size()));
180 }
181 }
182 // No need to hold on to the ViewerHandle now that distillation is complete.
183 viewer_handle_.reset();
63 } 184 }
64 185
65 void DomDistillerViewerSource::RequestViewerHandle::OnArticleUpdated( 186 void DomDistillerViewerSource::RequestViewerHandle::OnArticleUpdated(
66 ArticleDistillationUpdate article_update) { 187 ArticleDistillationUpdate article_update) {
67 // TODO(nyquist): Add support for displaying pages incrementally. 188 for (;page_count_ < static_cast<int>(article_update.GetPagesSize());
189 page_count_++) {
190 const DistilledPageProto& page =
191 article_update.GetDistilledPage(page_count_);
192 if (page_count_ == 0) {
193 std::string unsafe_page_html = viewer::GetUnsafePartialArticleHtml(&page);
194 callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html));
195 } else {
196 SendJavaScript(
197 viewer::GetUnsafeIncrementalDistilledPageJs(&page, false));
Charlie Reis 2014/05/09 21:32:46 nit: Wrong indent.
Yaron 2014/05/12 18:48:17 Done.
198 }
199 }
68 } 200 }
69 201
70 void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle( 202 void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle(
71 scoped_ptr<ViewerHandle> viewer_handle) { 203 scoped_ptr<ViewerHandle> viewer_handle) {
72 viewer_handle_ = viewer_handle.Pass(); 204 viewer_handle_ = viewer_handle.Pass();
73 } 205 }
74 206
75 DomDistillerViewerSource::DomDistillerViewerSource( 207 DomDistillerViewerSource::DomDistillerViewerSource(
76 DomDistillerServiceInterface* dom_distiller_service, 208 DomDistillerServiceInterface* dom_distiller_service,
77 const std::string& scheme) 209 const std::string& scheme)
(...skipping 13 matching lines...) Expand all
91 int render_frame_id, 223 int render_frame_id,
92 const content::URLDataSource::GotDataCallback& callback) { 224 const content::URLDataSource::GotDataCallback& callback) {
93 content::RenderFrameHost* render_frame_host = 225 content::RenderFrameHost* render_frame_host =
94 content::RenderFrameHost::FromID(render_process_id, render_frame_id); 226 content::RenderFrameHost::FromID(render_process_id, render_frame_id);
95 DCHECK(render_frame_host); 227 DCHECK(render_frame_host);
96 content::RenderViewHost* render_view_host = 228 content::RenderViewHost* render_view_host =
97 render_frame_host->GetRenderViewHost(); 229 render_frame_host->GetRenderViewHost();
98 DCHECK(render_view_host); 230 DCHECK(render_view_host);
99 CHECK_EQ(0, render_view_host->GetEnabledBindings()); 231 CHECK_EQ(0, render_view_host->GetEnabledBindings());
100 232
101 if (kCssPath == path) { 233 if (kViewerCssPath == path) {
102 std::string css = viewer::GetCss(); 234 std::string css = viewer::GetCss();
103 callback.Run(base::RefCountedString::TakeString(&css)); 235 callback.Run(base::RefCountedString::TakeString(&css));
104 return; 236 return;
237 } else if (kViewerJsPath == path) {
Charlie Reis 2014/05/09 21:32:46 nit: No need for an else if the previous block ret
Yaron 2014/05/12 18:48:17 Done.
238 std::string js = viewer::GetJavaScript();
239 callback.Run(base::RefCountedString::TakeString(&js));
240 return;
105 } 241 }
106
107 RequestViewerHandle* request_viewer_handle = 242 RequestViewerHandle* request_viewer_handle =
108 new RequestViewerHandle(callback); 243 new RequestViewerHandle(render_process_id, render_frame_id, callback);
Charlie Reis 2014/05/09 21:32:46 Maybe it's easier to just pass content::WebContent
Yaron 2014/05/12 18:48:17 Done.
109 scoped_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest( 244 scoped_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest(
110 dom_distiller_service_, path, request_viewer_handle); 245 dom_distiller_service_, path, request_viewer_handle);
111 246
112 if (viewer_handle) { 247 if (viewer_handle) {
113 // The service returned a |ViewerHandle| and guarantees it will call 248 // The service returned a |ViewerHandle| and guarantees it will call
114 // the |RequestViewerHandle|, so passing ownership to it, to ensure the 249 // the |RequestViewerHandle|, so passing ownership to it, to ensure the
115 // request is not cancelled. The |RequestViewerHandle| will delete itself 250 // request is not cancelled. The |RequestViewerHandle| will delete itself
116 // after receiving the callback. 251 // after receiving the callback.
117 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass()); 252 request_viewer_handle->TakeViewerHandle(viewer_handle.Pass());
118 } else { 253 } else {
119 // The service did not return a |ViewerHandle|, which means the 254 // The service did not return a |ViewerHandle|, which means the
120 // |RequestViewerHandle| will never be called, so clean up now. 255 // |RequestViewerHandle| will never be called, so clean up now.
121 delete request_viewer_handle; 256 delete request_viewer_handle;
122 257
123 std::string error_page_html = viewer::GetErrorPageHtml(); 258 std::string error_page_html = viewer::GetErrorPageHtml();
124 callback.Run(base::RefCountedString::TakeString(&error_page_html)); 259 callback.Run(base::RefCountedString::TakeString(&error_page_html));
125 } 260 }
126 }; 261 };
127 262
128 std::string DomDistillerViewerSource::GetMimeType( 263 std::string DomDistillerViewerSource::GetMimeType(
129 const std::string& path) const { 264 const std::string& path) const {
130 if (path == kCssPath) 265 if (kViewerCssPath == path)
131 return "text/css"; 266 return "text/css";
267 else if (kViewerJsPath == path)
268 return "text/javascript";
132 return "text/html"; 269 return "text/html";
133 } 270 }
134 271
135 bool DomDistillerViewerSource::ShouldServiceRequest( 272 bool DomDistillerViewerSource::ShouldServiceRequest(
136 const net::URLRequest* request) const { 273 const net::URLRequest* request) const {
137 return request->url().SchemeIs(scheme_.c_str()); 274 return request->url().SchemeIs(scheme_.c_str());
138 } 275 }
139 276
140 // TODO(nyquist): Start tracking requests using this method. 277 // TODO(nyquist): Start tracking requests using this method.
141 void DomDistillerViewerSource::WillServiceRequest( 278 void DomDistillerViewerSource::WillServiceRequest(
142 const net::URLRequest* request, 279 const net::URLRequest* request,
143 std::string* path) const { 280 std::string* path) const {
144 } 281 }
145 282
146 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc() 283 std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc()
147 const { 284 const {
148 return "object-src 'none'; style-src 'self';"; 285 return "object-src 'none'; style-src 'self';";
149 } 286 }
150 287
151 } // namespace dom_distiller 288 } // namespace dom_distiller
OLDNEW
« no previous file with comments | « components/dom_distiller/DEPS ('k') | components/dom_distiller/content/dom_distiller_viewer_source_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698