1 // Copyright 2015 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/favicon_base/fallback_icon_url_parser.h"
9 #include "base/logging.h"
10 #include "base/macros.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "third_party/skia/include/utils/SkParse.h"
15 #include "ui/gfx/favicon_size.h"
19 // List of sizes corresponding to RGB, ARGB, RRGGBB, AARRGGBB.
20 const size_t kValidHexColorSizes
[] = {3, 4, 6, 8};
22 // Returns whether |color_str| is a valid CSS color in hex format if we prepend
23 // '#', i.e., whether |color_str| matches /^[0-9A-Fa-f]{3,4,6,8}$/.
24 bool IsHexColorString(const std::string
& color_str
) {
25 size_t len
= color_str
.length();
26 const size_t* end
= kValidHexColorSizes
+ arraysize(kValidHexColorSizes
);
27 if (std::find(kValidHexColorSizes
, end
, len
) == end
)
29 for (auto ch
: color_str
) {
30 if (!base::IsHexDigit(ch
))
40 ParsedFallbackIconPath::ParsedFallbackIconPath()
41 : size_in_pixels_(gfx::kFaviconSize
) {
44 ParsedFallbackIconPath::~ParsedFallbackIconPath() {
47 bool ParsedFallbackIconPath::Parse(const std::string
& path
) {
51 size_t slash
= path
.find("/", 0);
52 if (slash
== std::string::npos
)
54 std::string spec_str
= path
.substr(0, slash
);
55 if (!ParseSpecs(spec_str
, &size_in_pixels_
, &style_
))
56 return false; // Parse failed.
58 // Need to store the index of the URL field, so Instant Extended can translate
59 // fallback icon URLs using advanced parameters.
61 // "chrome-search://fallback-icon/48/<renderer-id>/<most-visited-id>"
62 // would be translated to:
63 // "chrome-search://fallback-icon/48/<most-visited-item-with-given-id>".
64 path_index_
= slash
+ 1;
65 url_string_
= path
.substr(path_index_
);
70 bool ParsedFallbackIconPath::ParseSpecs(
71 const std::string
& specs_str
,
73 favicon_base::FallbackIconStyle
* style
) {
77 std::vector
<std::string
> tokens
= base::SplitString(
78 specs_str
, ",", base::KEEP_WHITESPACE
, base::SPLIT_WANT_ALL
);
79 if (tokens
.size() != 5) // Force "," for empty fields.
82 *size
= gfx::kFaviconSize
;
83 if (!tokens
[0].empty() && !base::StringToInt(tokens
[0], size
))
88 if (!tokens
[1].empty() && !ParseColor(tokens
[1], &style
->background_color
))
91 if (tokens
[2].empty())
92 favicon_base::MatchFallbackIconTextColorAgainstBackgroundColor(style
);
93 else if (!ParseColor(tokens
[2], &style
->text_color
))
96 if (!tokens
[3].empty() &&
97 !base::StringToDouble(tokens
[3], &style
->font_size_ratio
))
100 if (!tokens
[4].empty() && !base::StringToDouble(tokens
[4], &style
->roundness
))
103 return favicon_base::ValidateFallbackIconStyle(*style
);
107 bool ParsedFallbackIconPath::ParseColor(const std::string
& color_str
,
110 // Exclude the empty case. Also disallow the '#' prefix, since we want color
111 // to be part of an URL, but in URL '#' is used for ref fragment.
112 if (color_str
.empty() || color_str
[0] == '#')
115 // If a valid color hex string is given, prepend '#' and parse (always works).
116 // This is unambiguous since named color never only use leters 'a' to 'f'.
117 if (IsHexColorString(color_str
)) {
118 // Default alpha to 0xFF since FindColor() preserves unspecified alpha.
119 *color
= SK_ColorWHITE
;
120 // Need temp variable to avoid use-after-free of returned pointer.
121 std::string color_str_with_hash
= "#" + color_str
;
122 const char* end
= SkParse::FindColor(color_str_with_hash
.c_str(), color
);
123 DCHECK(end
&& !*end
); // Call should succeed and consume string.
127 // Default alpha to 0xFF.
128 SkColor temp_color
= SK_ColorWHITE
;
129 const char* end
= SkParse::FindColor(color_str
.c_str(), &temp_color
);
130 if (end
&& !*end
) { // Successful if call succeeds and string is consumed.
137 } // namespace chrome