Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / components / dom_distiller / core / viewer.cc
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.
4
5 #include "components/dom_distiller/core/viewer.h"
6
7 #include <string>
8 #include <vector>
9
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"
28
29 namespace dom_distiller {
30
31 namespace {
32
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";
37
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";
42
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";
47
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";
52
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;
59   }
60   return kLightJsTheme;
61 }
62
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;
69   }
70   return kLightCssClass;
71 }
72
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;
79   }
80   return kSansSerifJsFontFamily;
81 }
82
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;
89   }
90   return kSansSerifCssClass;
91 }
92
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);
100   }
101 }
102
103 std::string ReplaceHtmlTemplateValues(
104     const std::string& title,
105     const std::string& content,
106     const std::string& loading_indicator_class,
107     const std::string& original_url,
108     const DistilledPagePrefs::Theme theme,
109     const DistilledPagePrefs::FontFamily font_family) {
110   base::StringPiece html_template =
111       ResourceBundle::GetSharedInstance().GetRawDataResource(
112           IDR_DOM_DISTILLER_VIEWER_HTML);
113   std::vector<std::string> substitutions;
114   substitutions.push_back(title);                                         // $1
115   substitutions.push_back(kViewerCssPath);                                // $2
116   substitutions.push_back(kViewerJsPath);                                 // $3
117   substitutions.push_back(GetThemeCssClass(theme) + " " +
118                           GetFontCssClass(font_family));                  // $4
119   substitutions.push_back(content);                                       // $5
120   substitutions.push_back(loading_indicator_class);                       // $6
121   substitutions.push_back(original_url);                                  // $7
122   substitutions.push_back(
123       l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_VIEW_ORIGINAL));  // $8
124   return ReplaceStringPlaceholders(html_template, substitutions, NULL);
125 }
126
127 }  // namespace
128
129 namespace viewer {
130
131 const std::string GetUnsafeIncrementalDistilledPageJs(
132     const DistilledPageProto* page_proto,
133     const bool is_last_page) {
134   std::string output;
135   base::StringValue value(page_proto->html());
136   base::JSONWriter::Write(&value, &output);
137   std::string page_update("addToPage(");
138   page_update += output + ");";
139   return page_update + GetToggleLoadingIndicatorJs(
140       is_last_page);
141
142 }
143
144 const std::string GetToggleLoadingIndicatorJs(const bool is_last_page) {
145   if (is_last_page)
146     return "showLoadingIndicator(true);";
147   else
148     return "showLoadingIndicator(false);";
149 }
150
151 const std::string GetUnsafePartialArticleHtml(
152     const DistilledPageProto* page_proto,
153     const DistilledPagePrefs::Theme theme,
154     const DistilledPagePrefs::FontFamily font_family) {
155   DCHECK(page_proto);
156   std::string title = net::EscapeForHTML(page_proto->title());
157   std::ostringstream unsafe_output_stream;
158   unsafe_output_stream << page_proto->html();
159   std::string unsafe_article_html = unsafe_output_stream.str();
160   EnsureNonEmptyTitleAndContent(&title, &unsafe_article_html);
161   std::string original_url = page_proto->url();
162   return ReplaceHtmlTemplateValues(
163       title, unsafe_article_html, "visible", original_url, theme, font_family);
164 }
165
166 const std::string GetUnsafeArticleHtml(
167     const DistilledArticleProto* article_proto,
168     const DistilledPagePrefs::Theme theme,
169     const DistilledPagePrefs::FontFamily font_family) {
170   DCHECK(article_proto);
171   std::string title;
172   std::string unsafe_article_html;
173   if (article_proto->has_title() && article_proto->pages_size() > 0 &&
174       article_proto->pages(0).has_html()) {
175     title = net::EscapeForHTML(article_proto->title());
176     std::ostringstream unsafe_output_stream;
177     for (int page_num = 0; page_num < article_proto->pages_size(); ++page_num) {
178       unsafe_output_stream << article_proto->pages(page_num).html();
179     }
180     unsafe_article_html = unsafe_output_stream.str();
181   }
182
183   EnsureNonEmptyTitleAndContent(&title, &unsafe_article_html);
184
185   std::string original_url;
186   if (article_proto->pages_size() > 0 && article_proto->pages(0).has_url()) {
187     original_url = article_proto->pages(0).url();
188   }
189
190   return ReplaceHtmlTemplateValues(
191       title, unsafe_article_html, "hidden", original_url, theme, font_family);
192 }
193
194 const std::string GetErrorPageHtml(
195     const DistilledPagePrefs::Theme theme,
196     const DistilledPagePrefs::FontFamily font_family) {
197   std::string title = l10n_util::GetStringUTF8(
198       IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_TITLE);
199   std::string content = l10n_util::GetStringUTF8(
200       IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_CONTENT);
201   return ReplaceHtmlTemplateValues(
202       title, content, "hidden", "", theme, font_family);
203 }
204
205 const std::string GetCss() {
206   return ResourceBundle::GetSharedInstance().GetRawDataResource(
207           IDR_DISTILLER_CSS).as_string();
208 }
209
210 const std::string GetJavaScript() {
211   return ResourceBundle::GetSharedInstance()
212       .GetRawDataResource(IDR_DOM_DISTILLER_VIEWER_JS)
213       .as_string();
214 }
215
216 scoped_ptr<ViewerHandle> CreateViewRequest(
217     DomDistillerServiceInterface* dom_distiller_service,
218     const std::string& path,
219     ViewRequestDelegate* view_request_delegate,
220     const gfx::Size& render_view_size) {
221   std::string entry_id =
222       url_utils::GetValueForKeyInUrlPathQuery(path, kEntryIdKey);
223   bool has_valid_entry_id = !entry_id.empty();
224   entry_id = StringToUpperASCII(entry_id);
225
226   std::string requested_url_str =
227       url_utils::GetValueForKeyInUrlPathQuery(path, kUrlKey);
228   GURL requested_url(requested_url_str);
229   bool has_valid_url = url_utils::IsUrlDistillable(requested_url);
230
231   if (has_valid_entry_id && has_valid_url) {
232     // It is invalid to specify a query param for both |kEntryIdKey| and
233     // |kUrlKey|.
234     return scoped_ptr<ViewerHandle>();
235   }
236
237   if (has_valid_entry_id) {
238     return dom_distiller_service->ViewEntry(
239         view_request_delegate,
240         dom_distiller_service->CreateDefaultDistillerPage(render_view_size),
241         entry_id).Pass();
242   } else if (has_valid_url) {
243     return dom_distiller_service->ViewUrl(
244         view_request_delegate,
245         dom_distiller_service->CreateDefaultDistillerPage(render_view_size),
246         requested_url).Pass();
247   }
248
249   // It is invalid to not specify a query param for |kEntryIdKey| or |kUrlKey|.
250   return scoped_ptr<ViewerHandle>();
251 }
252
253 const std::string GetDistilledPageThemeJs(DistilledPagePrefs::Theme theme) {
254   return "useTheme('" + GetJsTheme(theme) + "');";
255 }
256
257 const std::string GetDistilledPageFontFamilyJs(
258     DistilledPagePrefs::FontFamily font_family) {
259   return "useFontFamily('" + GetJsFontFamily(font_family) + "');";
260 }
261
262 }  // namespace viewer
263
264 }  // namespace dom_distiller