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 "chrome/common/favicon/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
)
39 ParsedFallbackIconPath::ParsedFallbackIconPath()
40 : size_in_pixels_(gfx::kFaviconSize
) {
43 ParsedFallbackIconPath::~ParsedFallbackIconPath() {
46 bool ParsedFallbackIconPath::Parse(const std::string
& path
) {
50 size_t slash
= path
.find("/", 0);
51 if (slash
== std::string::npos
)
53 std::string spec_str
= path
.substr(0, slash
);
54 if (!ParseSpecs(spec_str
, &size_in_pixels_
, &style_
))
55 return false; // Parse failed.
57 // Need to store the index of the URL field, so Instant Extended can translate
58 // fallback icon URLs using advanced parameters.
60 // "chrome-search://fallback-icon/48/<renderer-id>/<most-visited-id>"
61 // would be translated to:
62 // "chrome-search://fallback-icon/48/<most-visited-item-with-given-id>".
63 path_index_
= slash
+ 1;
64 url_string_
= path
.substr(path_index_
);
69 bool ParsedFallbackIconPath::ParseSpecs(
70 const std::string
& specs_str
,
72 favicon_base::FallbackIconStyle
* style
) {
76 std::vector
<std::string
> tokens
;
77 base::SplitStringDontTrim(specs_str
, ',', &tokens
);
78 if (tokens
.size() != 5) // Force "," for empty fields.
81 *size
= gfx::kFaviconSize
;
82 if (!tokens
[0].empty() && !base::StringToInt(tokens
[0], size
))
87 if (!tokens
[1].empty() && !ParseColor(tokens
[1], &style
->background_color
))
90 if (tokens
[2].empty())
91 favicon_base::MatchFallbackIconTextColorAgainstBackgroundColor(style
);
92 else if (!ParseColor(tokens
[2], &style
->text_color
))
95 if (!tokens
[3].empty() &&
96 !base::StringToDouble(tokens
[3], &style
->font_size_ratio
))
99 if (!tokens
[4].empty() && !base::StringToDouble(tokens
[4], &style
->roundness
))
102 return favicon_base::ValidateFallbackIconStyle(*style
);
106 bool ParsedFallbackIconPath::ParseColor(const std::string
& color_str
,
109 // Exclude the empty case. Also disallow the '#' prefix, since we want color
110 // to be part of an URL, but in URL '#' is used for ref fragment.
111 if (color_str
.empty() || color_str
[0] == '#')
114 // If a valid color hex string is given, prepend '#' and parse (always works).
115 // This is unambiguous since named color never only use leters 'a' to 'f'.
116 if (IsHexColorString(color_str
)) {
117 // Default alpha to 0xFF since FindColor() preserves unspecified alpha.
118 *color
= SK_ColorWHITE
;
119 // Need temp variable to avoid use-after-free of returned pointer.
120 std::string color_str_with_hash
= "#" + color_str
;
121 const char* end
= SkParse::FindColor(color_str_with_hash
.c_str(), color
);
122 DCHECK(end
&& !*end
); // Call should succeed and consume string.
126 // Default alpha to 0xFF.
127 SkColor temp_color
= SK_ColorWHITE
;
128 const char* end
= SkParse::FindColor(color_str
.c_str(), &temp_color
);
129 if (end
&& !*end
) { // Successful if call succeeds and string is consumed.
136 } // namespace chrome