1 // Copyright 2013 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 "ui/base/webui/web_ui_util.h"
6 
7 #include <vector>
8 
9 #include "base/base64.h"
10 #include "base/feature_list.h"
11 #include "base/i18n/rtl.h"
12 #include "base/logging.h"
13 #include "base/memory/ref_counted_memory.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_piece.h"
16 #include "base/strings/string_util.h"
17 #include "base/trace_event/trace_event.h"
18 #include "build/build_config.h"
19 #include "net/base/escape.h"
20 #include "third_party/modp_b64/modp_b64.h"
21 #include "ui/base/l10n/l10n_util.h"
22 #include "ui/base/resource/resource_bundle.h"
23 #include "ui/base/template_expressions.h"
24 #include "ui/base/ui_base_features.h"
25 #include "ui/base/window_open_disposition.h"
26 #include "ui/gfx/codec/png_codec.h"
27 #include "ui/gfx/font.h"
28 #include "ui/gfx/image/image_skia.h"
29 #include "ui/resources/grit/webui_resources.h"
30 #include "ui/strings/grit/app_locale_settings.h"
31 #include "url/gurl.h"
32 
33 #if defined(OS_WIN)
34 #include "base/win/windows_version.h"
35 #endif
36 
37 namespace webui {
38 namespace {
GetWebUiCssTextDefaults(const std::string & css_template)39 std::string GetWebUiCssTextDefaults(const std::string& css_template) {
40   ui::TemplateReplacements placeholders;
41   placeholders["textDirection"] = GetTextDirection();
42   placeholders["fontFamily"] = GetFontFamily();
43   placeholders["fontSize"] = GetFontSize();
44   return ui::ReplaceTemplateExpressions(css_template, placeholders);
45 }
46 }  // namespace
47 
GetBitmapDataUrl(const SkBitmap & bitmap)48 std::string GetBitmapDataUrl(const SkBitmap& bitmap) {
49   TRACE_EVENT2("ui", "GetBitmapDataUrl", "width", bitmap.width(), "height",
50                bitmap.height());
51   std::vector<unsigned char> output;
52   gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &output);
53   return GetPngDataUrl(output.data(), output.size());
54 }
55 
GetPngDataUrl(const unsigned char * data,size_t size)56 std::string GetPngDataUrl(const unsigned char* data, size_t size) {
57   constexpr char kPrefix[] = "data:image/png;base64,";
58   constexpr size_t kPrefixLen = base::size(kPrefix) - 1;
59   // Includes room for trailing null byte.
60   size_t max_encode_len = modp_b64_encode_len(size);
61   std::string output;
62   // This initializes the characters in the string, but there's no good way to
63   // avoid that and maintain a std::string API.
64   output.resize(kPrefixLen + max_encode_len);
65   memcpy(&output[0], kPrefix, kPrefixLen);
66   // |max_encode_len| is >= 1, so &output[kPrefixLen] is valid.
67   size_t actual_encode_len = modp_b64_encode(
68       &output[kPrefixLen], reinterpret_cast<const char*>(data), size);
69   output.resize(kPrefixLen + actual_encode_len);
70   return output;
71 }
72 
GetDispositionFromClick(const base::ListValue * args,int start_index)73 WindowOpenDisposition GetDispositionFromClick(const base::ListValue* args,
74                                               int start_index) {
75   double button = 0.0;
76   bool alt_key = false;
77   bool ctrl_key = false;
78   bool meta_key = false;
79   bool shift_key = false;
80 
81   CHECK(args->GetDouble(start_index++, &button));
82   CHECK(args->GetBoolean(start_index++, &alt_key));
83   CHECK(args->GetBoolean(start_index++, &ctrl_key));
84   CHECK(args->GetBoolean(start_index++, &meta_key));
85   CHECK(args->GetBoolean(start_index++, &shift_key));
86   return ui::DispositionFromClick(
87       button == 1.0, alt_key, ctrl_key, meta_key, shift_key);
88 }
89 
ParseScaleFactor(const base::StringPiece & identifier,float * scale_factor)90 bool ParseScaleFactor(const base::StringPiece& identifier,
91                       float* scale_factor) {
92   *scale_factor = 1.0f;
93   if (identifier.empty()) {
94     LOG(WARNING) << "Invalid scale factor format: " << identifier;
95     return false;
96   }
97 
98   if (*identifier.rbegin() != 'x') {
99     LOG(WARNING) << "Invalid scale factor format: " << identifier;
100     return false;
101   }
102 
103   double scale = 0;
104   std::string stripped(identifier.substr(0, identifier.length() - 1));
105   if (!base::StringToDouble(stripped, &scale)) {
106     LOG(WARNING) << "Invalid scale factor format: " << identifier;
107     return false;
108   }
109   *scale_factor = static_cast<float>(scale);
110   return true;
111 }
112 
113 // Parse a formatted frame index string into int and sets to |frame_index|.
ParseFrameIndex(const base::StringPiece & identifier,int * frame_index)114 bool ParseFrameIndex(const base::StringPiece& identifier, int* frame_index) {
115   *frame_index = -1;
116   if (identifier.empty()) {
117     LOG(WARNING) << "Invalid frame index format: " << identifier;
118     return false;
119   }
120 
121   if (*identifier.rbegin() != ']') {
122     LOG(WARNING) << "Invalid frame index format: " << identifier;
123     return false;
124   }
125 
126   unsigned frame = 0;
127   if (!base::StringToUint(identifier.substr(0, identifier.length() - 1),
128                           &frame)) {
129     LOG(WARNING) << "Invalid frame index format: " << identifier;
130     return false;
131   }
132   *frame_index = static_cast<int>(frame);
133   return true;
134 }
135 
ParsePathAndImageSpec(const GURL & url,std::string * path,float * scale_factor,int * frame_index)136 void ParsePathAndImageSpec(const GURL& url,
137                            std::string* path,
138                            float* scale_factor,
139                            int* frame_index) {
140   *path = net::UnescapeBinaryURLComponent(url.path_piece().substr(1));
141   if (scale_factor)
142     *scale_factor = 1.0f;
143   if (frame_index)
144     *frame_index = -1;
145 
146   // Detect and parse resource string ending in @<scale>x.
147   std::size_t pos = path->rfind('@');
148   if (pos != std::string::npos) {
149     base::StringPiece stripped_path(*path);
150     float factor;
151 
152     if (ParseScaleFactor(stripped_path.substr(
153             pos + 1, stripped_path.length() - pos - 1), &factor)) {
154       // Strip scale factor specification from path.
155       stripped_path.remove_suffix(stripped_path.length() - pos);
156       path->assign(stripped_path.data(), stripped_path.size());
157     }
158     if (scale_factor)
159       *scale_factor = factor;
160   }
161 
162   // Detect and parse resource string ending in [<frame>].
163   pos = path->rfind('[');
164   if (pos != std::string::npos) {
165     base::StringPiece stripped_path(*path);
166     int index;
167 
168     if (ParseFrameIndex(
169             stripped_path.substr(pos + 1, stripped_path.length() - pos - 1),
170             &index)) {
171       // Strip frame index specification from path.
172       stripped_path.remove_suffix(stripped_path.length() - pos);
173       path->assign(stripped_path.data(), stripped_path.size());
174     }
175     if (frame_index)
176       *frame_index = index;
177   }
178 }
179 
ParsePathAndScale(const GURL & url,std::string * path,float * scale_factor)180 void ParsePathAndScale(const GURL& url,
181                        std::string* path,
182                        float* scale_factor) {
183   ParsePathAndImageSpec(url, path, scale_factor, nullptr);
184 }
185 
ParsePathAndFrame(const GURL & url,std::string * path,int * frame_index)186 void ParsePathAndFrame(const GURL& url, std::string* path, int* frame_index) {
187   ParsePathAndImageSpec(url, path, nullptr, frame_index);
188 }
189 
SetLoadTimeDataDefaults(const std::string & app_locale,base::DictionaryValue * localized_strings)190 void SetLoadTimeDataDefaults(const std::string& app_locale,
191                              base::DictionaryValue* localized_strings) {
192   localized_strings->SetString("a11yenhanced", GetA11yEnhanced());
193   localized_strings->SetString("fontfamily", GetFontFamily());
194   localized_strings->SetString("fontsize", GetFontSize());
195   localized_strings->SetString("language", l10n_util::GetLanguage(app_locale));
196   localized_strings->SetString("textdirection", GetTextDirection());
197 }
198 
SetLoadTimeDataDefaults(const std::string & app_locale,ui::TemplateReplacements * replacements)199 void SetLoadTimeDataDefaults(const std::string& app_locale,
200                              ui::TemplateReplacements* replacements) {
201   (*replacements)["a11yenhanced"] = GetA11yEnhanced();
202   (*replacements)["fontfamily"] = GetFontFamily();
203   (*replacements)["fontsize"] = GetFontSize();
204   (*replacements)["language"] = l10n_util::GetLanguage(app_locale);
205   (*replacements)["textdirection"] = GetTextDirection();
206 }
207 
GetWebUiCssTextDefaults()208 std::string GetWebUiCssTextDefaults() {
209   const ui::ResourceBundle& resource_bundle =
210       ui::ResourceBundle::GetSharedInstance();
211   return GetWebUiCssTextDefaults(
212       resource_bundle.LoadDataResourceString(IDR_WEBUI_CSS_TEXT_DEFAULTS));
213 }
214 
GetWebUiCssTextDefaultsMd()215 std::string GetWebUiCssTextDefaultsMd() {
216   const ui::ResourceBundle& resource_bundle =
217       ui::ResourceBundle::GetSharedInstance();
218   return GetWebUiCssTextDefaults(
219       resource_bundle.LoadDataResourceString(IDR_WEBUI_CSS_TEXT_DEFAULTS_MD));
220 }
221 
AppendWebUiCssTextDefaults(std::string * html)222 void AppendWebUiCssTextDefaults(std::string* html) {
223   html->append("<style>");
224   html->append(GetWebUiCssTextDefaults());
225   html->append("</style>");
226 }
227 
GetA11yEnhanced()228 std::string GetA11yEnhanced() {
229   return base::FeatureList::IsEnabled(features::kWebUIA11yEnhancements)
230              ? "a11y-enhanced"
231              : "";
232 }
233 
GetFontFamily()234 std::string GetFontFamily() {
235   std::string font_family = l10n_util::GetStringUTF8(IDS_WEB_FONT_FAMILY);
236 
237 // TODO(dnicoara) Remove Ozone check when PlatformFont support is introduced
238 // into Ozone: crbug.com/320050
239 #if (defined(OS_LINUX) || defined(OS_BSD)) && !defined(OS_CHROMEOS) && !defined(USE_OZONE)
240   font_family = ui::ResourceBundle::GetSharedInstance().GetFont(
241       ui::ResourceBundle::BaseFont).GetFontName() + ", " + font_family;
242 #endif
243 
244   return font_family;
245 }
246 
GetFontSize()247 std::string GetFontSize() {
248   return l10n_util::GetStringUTF8(IDS_WEB_FONT_SIZE);
249 }
250 
GetTextDirection()251 std::string GetTextDirection() {
252   return base::i18n::IsRTL() ? "rtl" : "ltr";
253 }
254 
255 }  // namespace webui
256