Roll src/third_party/skia de7665a:76033be
[chromium-blink-merge.git] / components / dom_distiller / core / viewer.cc
blob00e05ca447e2a8665bdffd1376ef9a5a590d91c5
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
3 // found in the LICENSE file.
5 #include "components/dom_distiller/core/viewer.h"
7 #include <string>
8 #include <vector>
10 #include "base/json/json_writer.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/metrics/histogram.h"
13 #include "base/strings/string_util.h"
14 #include "components/dom_distiller/core/distilled_page_prefs.h"
15 #include "components/dom_distiller/core/dom_distiller_service.h"
16 #include "components/dom_distiller/core/proto/distilled_article.pb.h"
17 #include "components/dom_distiller/core/proto/distilled_page.pb.h"
18 #include "components/dom_distiller/core/task_tracker.h"
19 #include "components/dom_distiller/core/url_constants.h"
20 #include "components/dom_distiller/core/url_utils.h"
21 #include "grit/components_resources.h"
22 #include "grit/components_strings.h"
23 #include "net/base/escape.h"
24 #include "net/url_request/url_request.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "url/gurl.h"
29 namespace dom_distiller {
31 namespace {
33 // JS Themes. Must agree with useTheme() in dom_distiller_viewer.js.
34 const char kDarkJsTheme[] = "dark";
35 const char kLightJsTheme[] = "light";
36 const char kSepiaJsTheme[] = "sepia";
38 // CSS Theme classes. Must agree with classes in distilledpage.css.
39 const char kDarkCssClass[] = "dark";
40 const char kLightCssClass[] = "light";
41 const char kSepiaCssClass[] = "sepia";
43 // JS FontFamilies. Must agree with useFontFamily() in dom_distiller_viewer.js.
44 const char kSerifJsFontFamily[] = "serif";
45 const char kSansSerifJsFontFamily[] = "sans-serif";
46 const char kMonospaceJsFontFamily[] = "monospace";
48 // CSS FontFamily classes. Must agree with classes in distilledpage.css.
49 const char kSerifCssClass[] = "serif";
50 const char kSansSerifCssClass[] = "sans-serif";
51 const char kMonospaceCssClass[] = "monospace";
53 // Maps themes to JS themes.
54 const std::string GetJsTheme(DistilledPagePrefs::Theme theme) {
55 if (theme == DistilledPagePrefs::DARK) {
56 return kDarkJsTheme;
57 } else if (theme == DistilledPagePrefs::SEPIA) {
58 return kSepiaJsTheme;
60 return kLightJsTheme;
63 // Maps themes to CSS classes.
64 const std::string GetThemeCssClass(DistilledPagePrefs::Theme theme) {
65 if (theme == DistilledPagePrefs::DARK) {
66 return kDarkCssClass;
67 } else if (theme == DistilledPagePrefs::SEPIA) {
68 return kSepiaCssClass;
70 return kLightCssClass;
73 // Maps font families to JS font families.
74 const std::string GetJsFontFamily(DistilledPagePrefs::FontFamily font_family) {
75 if (font_family == DistilledPagePrefs::SERIF) {
76 return kSerifJsFontFamily;
77 } else if (font_family == DistilledPagePrefs::MONOSPACE) {
78 return kMonospaceJsFontFamily;
80 return kSansSerifJsFontFamily;
83 // Maps fontFamilies to CSS fontFamily classes.
84 const std::string GetFontCssClass(DistilledPagePrefs::FontFamily font_family) {
85 if (font_family == DistilledPagePrefs::SERIF) {
86 return kSerifCssClass;
87 } else if (font_family == DistilledPagePrefs::MONOSPACE) {
88 return kMonospaceCssClass;
90 return kSansSerifCssClass;
93 void EnsureNonEmptyTitleAndContent(std::string* title, std::string* content) {
94 if (title->empty())
95 *title = l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_NO_DATA_TITLE);
96 UMA_HISTOGRAM_BOOLEAN("DomDistiller.PageHasDistilledData", !content->empty());
97 if (content->empty()) {
98 *content = l10n_util::GetStringUTF8(
99 IDS_DOM_DISTILLER_VIEWER_NO_DATA_CONTENT);
103 std::string ReplaceHtmlTemplateValues(
104 const std::string& title,
105 const std::string& textDirection,
106 const std::string& content,
107 const std::string& loading_indicator_class,
108 const std::string& original_url,
109 const DistilledPagePrefs::Theme theme,
110 const DistilledPagePrefs::FontFamily font_family) {
111 base::StringPiece html_template =
112 ResourceBundle::GetSharedInstance().GetRawDataResource(
113 IDR_DOM_DISTILLER_VIEWER_HTML);
114 std::vector<std::string> substitutions;
115 substitutions.push_back(title); // $1
116 substitutions.push_back(kViewerCssPath); // $2
117 substitutions.push_back(kViewerJsPath); // $3
118 substitutions.push_back(GetThemeCssClass(theme) + " " +
119 GetFontCssClass(font_family)); // $4
120 substitutions.push_back(content); // $5
121 substitutions.push_back(loading_indicator_class); // $6
122 substitutions.push_back(original_url); // $7
123 substitutions.push_back(
124 l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_VIEW_ORIGINAL)); // $8
125 substitutions.push_back(textDirection); // $9
126 return ReplaceStringPlaceholders(html_template, substitutions, NULL);
129 } // namespace
131 namespace viewer {
133 const std::string GetUnsafeIncrementalDistilledPageJs(
134 const DistilledPageProto* page_proto,
135 const bool is_last_page) {
136 std::string output;
137 base::StringValue value(page_proto->html());
138 base::JSONWriter::Write(&value, &output);
139 std::string page_update("addToPage(");
140 page_update += output + ");";
141 return page_update + GetToggleLoadingIndicatorJs(
142 is_last_page);
146 const std::string GetToggleLoadingIndicatorJs(const bool is_last_page) {
147 if (is_last_page)
148 return "showLoadingIndicator(true);";
149 else
150 return "showLoadingIndicator(false);";
153 const std::string GetUnsafePartialArticleHtml(
154 const DistilledPageProto* page_proto,
155 const DistilledPagePrefs::Theme theme,
156 const DistilledPagePrefs::FontFamily font_family) {
157 DCHECK(page_proto);
158 std::string title = net::EscapeForHTML(page_proto->title());
159 std::ostringstream unsafe_output_stream;
160 unsafe_output_stream << page_proto->html();
161 std::string unsafe_article_html = unsafe_output_stream.str();
162 EnsureNonEmptyTitleAndContent(&title, &unsafe_article_html);
163 std::string original_url = page_proto->url();
164 return ReplaceHtmlTemplateValues(
165 title, page_proto->text_direction(), unsafe_article_html, "visible",
166 original_url, theme, font_family);
169 const std::string GetUnsafeArticleHtml(
170 const DistilledArticleProto* article_proto,
171 const DistilledPagePrefs::Theme theme,
172 const DistilledPagePrefs::FontFamily font_family) {
173 DCHECK(article_proto);
174 std::string title;
175 std::string unsafe_article_html;
176 std::string text_direction = "";
177 if (article_proto->has_title() && article_proto->pages_size() > 0 &&
178 article_proto->pages(0).has_html()) {
179 title = net::EscapeForHTML(article_proto->title());
180 std::ostringstream unsafe_output_stream;
181 for (int page_num = 0; page_num < article_proto->pages_size(); ++page_num) {
182 unsafe_output_stream << article_proto->pages(page_num).html();
184 unsafe_article_html = unsafe_output_stream.str();
185 text_direction = article_proto->pages(0).text_direction();
188 EnsureNonEmptyTitleAndContent(&title, &unsafe_article_html);
190 std::string original_url;
191 if (article_proto->pages_size() > 0 && article_proto->pages(0).has_url()) {
192 original_url = article_proto->pages(0).url();
195 return ReplaceHtmlTemplateValues(
196 title, text_direction, unsafe_article_html, "hidden", original_url,
197 theme, font_family);
200 const std::string GetErrorPageHtml(
201 const DistilledPagePrefs::Theme theme,
202 const DistilledPagePrefs::FontFamily font_family) {
203 std::string title = l10n_util::GetStringUTF8(
204 IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_TITLE);
205 std::string content = l10n_util::GetStringUTF8(
206 IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_CONTENT);
207 return ReplaceHtmlTemplateValues(
208 title, "", content, "hidden", "", theme, font_family);
211 const std::string GetCss() {
212 return ResourceBundle::GetSharedInstance().GetRawDataResource(
213 IDR_DISTILLER_CSS).as_string();
216 const std::string GetJavaScript() {
217 return ResourceBundle::GetSharedInstance()
218 .GetRawDataResource(IDR_DOM_DISTILLER_VIEWER_JS)
219 .as_string();
222 scoped_ptr<ViewerHandle> CreateViewRequest(
223 DomDistillerServiceInterface* dom_distiller_service,
224 const std::string& path,
225 ViewRequestDelegate* view_request_delegate,
226 const gfx::Size& render_view_size) {
227 std::string entry_id =
228 url_utils::GetValueForKeyInUrlPathQuery(path, kEntryIdKey);
229 bool has_valid_entry_id = !entry_id.empty();
230 entry_id = StringToUpperASCII(entry_id);
232 std::string requested_url_str =
233 url_utils::GetValueForKeyInUrlPathQuery(path, kUrlKey);
234 GURL requested_url(requested_url_str);
235 bool has_valid_url = url_utils::IsUrlDistillable(requested_url);
237 if (has_valid_entry_id && has_valid_url) {
238 // It is invalid to specify a query param for both |kEntryIdKey| and
239 // |kUrlKey|.
240 return scoped_ptr<ViewerHandle>();
243 if (has_valid_entry_id) {
244 return dom_distiller_service->ViewEntry(
245 view_request_delegate,
246 dom_distiller_service->CreateDefaultDistillerPage(render_view_size),
247 entry_id).Pass();
248 } else if (has_valid_url) {
249 return dom_distiller_service->ViewUrl(
250 view_request_delegate,
251 dom_distiller_service->CreateDefaultDistillerPage(render_view_size),
252 requested_url).Pass();
255 // It is invalid to not specify a query param for |kEntryIdKey| or |kUrlKey|.
256 return scoped_ptr<ViewerHandle>();
259 const std::string GetDistilledPageThemeJs(DistilledPagePrefs::Theme theme) {
260 return "useTheme('" + GetJsTheme(theme) + "');";
263 const std::string GetDistilledPageFontFamilyJs(
264 DistilledPagePrefs::FontFamily font_family) {
265 return "useFontFamily('" + GetJsFontFamily(font_family) + "');";
268 } // namespace viewer
270 } // namespace dom_distiller