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 "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 Loading... | |
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 |
OLD | NEW |