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