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