Commit c32b1cd8 authored by huangs's avatar huangs Committed by Commit bot

[Favicon] Adding FallbackIconUrlParser.

Design: go/chrome-fallback-icons

This adds FallbackIconUrlParser, which will be used to parse the
"explict flow" host chrome://fallback-icon/ to extract size,
FallbackIconStyle, and URL needed to render Fallback icons.

This CL is sliced off from https://codereview.chromium.org/835903005/ .

BUG=455063

Review URL: https://codereview.chromium.org/924063003

Cr-Commit-Position: refs/heads/master@{#318771}
parent 0c8b5e25
...@@ -51,6 +51,8 @@ ...@@ -51,6 +51,8 @@
'common/custom_handlers/protocol_handler.cc', 'common/custom_handlers/protocol_handler.cc',
'common/custom_handlers/protocol_handler.h', 'common/custom_handlers/protocol_handler.h',
'common/descriptors_android.h', 'common/descriptors_android.h',
'common/favicon/fallback_icon_url_parser.cc',
'common/favicon/fallback_icon_url_parser.h',
'common/favicon/favicon_url_parser.cc', 'common/favicon/favicon_url_parser.cc',
'common/favicon/favicon_url_parser.h', 'common/favicon/favicon_url_parser.h',
'common/icon_with_badge_image_source.cc', 'common/icon_with_badge_image_source.cc',
...@@ -317,6 +319,7 @@ ...@@ -317,6 +319,7 @@
'<(DEPTH)/crypto/crypto.gyp:crypto', '<(DEPTH)/crypto/crypto.gyp:crypto',
'<(DEPTH)/net/net.gyp:net', '<(DEPTH)/net/net.gyp:net',
'<(DEPTH)/skia/skia.gyp:skia', '<(DEPTH)/skia/skia.gyp:skia',
'<(DEPTH)/skia/skia.gyp:skia_library',
'<(DEPTH)/third_party/icu/icu.gyp:icui18n', '<(DEPTH)/third_party/icu/icu.gyp:icui18n',
'<(DEPTH)/third_party/icu/icu.gyp:icuuc', '<(DEPTH)/third_party/icu/icu.gyp:icuuc',
'<(DEPTH)/third_party/libxml/libxml.gyp:libxml', '<(DEPTH)/third_party/libxml/libxml.gyp:libxml',
......
...@@ -541,6 +541,7 @@ ...@@ -541,6 +541,7 @@
'common/chrome_paths_unittest.cc', 'common/chrome_paths_unittest.cc',
'common/cloud_print/cloud_print_helpers_unittest.cc', 'common/cloud_print/cloud_print_helpers_unittest.cc',
'common/crash_keys_unittest.cc', 'common/crash_keys_unittest.cc',
'common/favicon/fallback_icon_url_parser_unittest.cc',
'common/favicon/favicon_url_parser_unittest.cc', 'common/favicon/favicon_url_parser_unittest.cc',
'common/ini_parser_unittest.cc', 'common/ini_parser_unittest.cc',
'common/instant_types_unittest.cc', 'common/instant_types_unittest.cc',
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/common/favicon/fallback_icon_url_parser.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "third_party/skia/include/utils/SkParse.h"
#include "ui/gfx/favicon_size.h"
namespace chrome {
ParsedFallbackIconPath::ParsedFallbackIconPath()
: size_in_pixels_(gfx::kFaviconSize) {
}
ParsedFallbackIconPath::~ParsedFallbackIconPath() {
}
bool ParsedFallbackIconPath::Parse(const std::string& path) {
if (path.empty())
return false;
size_t slash = path.find("/", 0);
if (slash == std::string::npos)
return false;
std::string spec_str = path.substr(0, slash);
if (!ParseSpecs(spec_str, &size_in_pixels_, &style_))
return false; // Parse failed.
// Extract URL, which may be empty (if first slash appears at the end).
std::string url_str = path.substr(slash + 1);
url_ = GURL(url_str);
return url_str.empty() || url_.is_valid(); // Allow empty URL.
}
// static
bool ParsedFallbackIconPath::ParseSpecs(
const std::string& specs_str,
int *size,
favicon_base::FallbackIconStyle* style) {
DCHECK(size);
DCHECK(style);
std::vector<std::string> tokens;
base::SplitStringDontTrim(specs_str, ',', &tokens);
if (tokens.size() != 5) // Force "," for empty fields.
return false;
*size = gfx::kFaviconSize;
if (!tokens[0].empty() && !base::StringToInt(tokens[0], size))
return false;
if (*size <= 0)
return false;
if (!tokens[1].empty() && !ParseColor(tokens[1], &style->background_color))
return false;
if (tokens[2].empty())
favicon_base::MatchFallbackIconTextColorAgainstBackgroundColor(style);
else if (!ParseColor(tokens[2], &style->text_color))
return false;
if (!tokens[3].empty() &&
!base::StringToDouble(tokens[3], &style->font_size_ratio))
return false;
if (!tokens[4].empty() && !base::StringToDouble(tokens[4], &style->roundness))
return false;
return favicon_base::ValidateFallbackIconStyle(*style);
}
// static
bool ParsedFallbackIconPath::ParseColor(const std::string& color_str,
SkColor* color) {
const char* end = SkParse::FindColor(color_str.c_str(), color);
// Return true if FindColor() succeeds and |color_str| is entirely consumed.
return end && !*end;
}
} // namespace chrome
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_COMMON_FAVICON_FALLBACK_ICON_URL_PARSER_H_
#define CHROME_COMMON_FAVICON_FALLBACK_ICON_URL_PARSER_H_
#include <string>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "components/favicon_base/fallback_icon_style.h"
#include "third_party/skia/include/core/SkColor.h"
#include "url/gurl.h"
namespace chrome {
class ParsedFallbackIconPath {
public:
ParsedFallbackIconPath();
~ParsedFallbackIconPath();
const GURL& url() const { return url_; }
int size_in_pixels() const { return size_in_pixels_; }
const favicon_base::FallbackIconStyle& style() const { return style_; }
// Parses |path|, which should be in the format described at the top of the
// file "chrome/browser/ui/webui/fallback_icon_source.h".
bool Parse(const std::string& path);
private:
// Parses |specs_str|, which should be the comma-separated value portion
// in the format described at the top of the file
// "chrome/browser/ui/webui/fallback_icon_source.h".
static bool ParseSpecs(const std::string& specs_str,
int *size,
favicon_base::FallbackIconStyle* style);
// Helper to parse color string (e.g., "red", "#f00", "#fF0000"). Returns true
// on success.
static bool ParseColor(const std::string& color_str, SkColor* color);
friend class FallbackIconUrlParserTest;
FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseColorSuccess);
FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseColorFailure);
FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseSpecsEmpty);
FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseSpecsPartial);
FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseSpecsFull);
FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseSpecsFailure);
// The page URL the fallback icon is requested for.
GURL url_;
// The size of the requested fallback icon in pixels.
int size_in_pixels_;
// Styling specifications of fallback icon.
favicon_base::FallbackIconStyle style_;
DISALLOW_COPY_AND_ASSIGN(ParsedFallbackIconPath);
};
} // namespace chrome
#endif // CHROME_COMMON_FAVICON_FALLBACK_ICON_URL_PARSER_H_
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/common/favicon/fallback_icon_url_parser.h"
#include "base/memory/scoped_ptr.h"
#include "components/favicon_base/fallback_icon_style.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/favicon_size.h"
#include "url/gurl.h"
using chrome::ParsedFallbackIconPath;
using favicon_base::FallbackIconStyle;
namespace chrome {
namespace {
// Default values for FallbackIconStyle, from
// /components/favicon_base/fallback_icon_style.h
SkColor kDefaultBackgroundColor = SkColorSetRGB(0x80, 0x80, 0x80);
SkColor kDefaultTextColorDark = SK_ColorBLACK;
SkColor kDefaultTextColorLight = SK_ColorWHITE;
double kDefaultFontSizeRatio = 0.8;
double kDefaultRoundness = 0.125; // 1 / 8.
const char kTestUrlStr[] = "https://www.google.ca/imghp?hl=en&tab=wi";
} // namespace
class FallbackIconUrlParserTest : public testing::Test {
public:
FallbackIconUrlParserTest() {
}
bool ParseSpecs(const std::string& specs_str,
int *size,
favicon_base::FallbackIconStyle* style) {
return ParsedFallbackIconPath::ParseSpecs(specs_str, size, style);
}
bool ParseColor(const std::string& color_str, SkColor* color) {
int size_dummy;
favicon_base::FallbackIconStyle style;
std::string spec_str = "16," + color_str + ",,,";
if (!ParseSpecs(spec_str, &size_dummy, &style))
return false;
*color = style.background_color;
return true;
}
private:
DISALLOW_COPY_AND_ASSIGN(FallbackIconUrlParserTest);
};
TEST_F(FallbackIconUrlParserTest, ParseColorSuccess) {
SkColor c;
EXPECT_TRUE(ParseColor("#01aBf0f4", &c));
EXPECT_EQ(SkColorSetARGB(0x01, 0xAB, 0xF0, 0xF4), c);
EXPECT_TRUE(ParseColor("#01aBf0", &c));
EXPECT_EQ(SkColorSetRGB(0x01, 0xAB, 0xF0), c);
EXPECT_TRUE(ParseColor("#01a", &c));
EXPECT_EQ(SkColorSetRGB(0x00, 0x11, 0xAA), c);
EXPECT_TRUE(ParseColor("#000000", &c));
EXPECT_EQ(SkColorSetARGB(0xFF, 0x00, 0x00, 0x00), c);
EXPECT_TRUE(ParseColor("red", &c));
EXPECT_EQ(SkColorSetARGB(0xFF, 0xFF, 0x00, 0x00), c);
}
TEST_F(FallbackIconUrlParserTest, ParseColorFailure) {
const char* test_cases[] = {
"#00000",
"#000000000",
" #000000",
"#ABCDEFG",
"000000",
"#000000 ",
};
for (size_t i = 0; i < arraysize(test_cases); ++i) {
SkColor c;
EXPECT_FALSE(ParseColor(test_cases[i], &c))
<< "test_cases[" << i << "]";
}
}
TEST_F(FallbackIconUrlParserTest, ParseSpecsEmpty) {
int size;
FallbackIconStyle style;
EXPECT_TRUE(ParseSpecs(",,,,", &size, &style));
EXPECT_EQ(16, size);
EXPECT_EQ(kDefaultBackgroundColor, style.background_color);
EXPECT_EQ(kDefaultTextColorLight, style.text_color);
EXPECT_EQ(kDefaultFontSizeRatio, style.font_size_ratio);
EXPECT_EQ(kDefaultRoundness, style.roundness);
}
TEST_F(FallbackIconUrlParserTest, ParseSpecsPartial) {
int size;
FallbackIconStyle style;
EXPECT_TRUE(ParseSpecs(",,#aCE,,0.1", &size, &style));
EXPECT_EQ(16, size);
EXPECT_EQ(kDefaultBackgroundColor, style.background_color);
EXPECT_EQ(SkColorSetRGB(0xAA, 0xCC, 0xEE), style.text_color);
EXPECT_EQ(kDefaultFontSizeRatio, style.font_size_ratio);
EXPECT_EQ(0.1, style.roundness);
}
TEST_F(FallbackIconUrlParserTest, ParseSpecsFull) {
int size;
{
FallbackIconStyle style;
EXPECT_TRUE(ParseSpecs("16,#000,#f01,0.75,0.25", &size, &style));
EXPECT_EQ(16, size);
EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
EXPECT_EQ(SkColorSetRGB(0xff, 0x00, 0x11), style.text_color);
EXPECT_EQ(0.75, style.font_size_ratio);
EXPECT_EQ(0.25, style.roundness);
}
{
FallbackIconStyle style;
EXPECT_TRUE(ParseSpecs("48,black,#123456,0.5,0.3", &size, &style));
EXPECT_EQ(48, size);
EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
EXPECT_EQ(SkColorSetRGB(0x12, 0x34, 0x56), style.text_color);
EXPECT_EQ(0.5, style.font_size_ratio);
EXPECT_EQ(0.3, style.roundness);
}
{
FallbackIconStyle style;
EXPECT_TRUE(ParseSpecs("1,#000,red,0,0", &size, &style));
EXPECT_EQ(1, size);
EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
EXPECT_EQ(SkColorSetRGB(0xFF, 0x00, 0x00), style.text_color);
EXPECT_EQ(0, style.font_size_ratio);
EXPECT_EQ(0, style.roundness);
}
}
TEST_F(FallbackIconUrlParserTest, ParseSpecsDefaultTextColor) {
int size;
{
// Dark background -> Light text.
FallbackIconStyle style;
EXPECT_TRUE(ParseSpecs(",#000,,,", &size, &style));
EXPECT_EQ(kDefaultTextColorLight, style.text_color);
}
{
// Light background -> Dark text.
FallbackIconStyle style;
EXPECT_TRUE(ParseSpecs(",#fff,,,", &size, &style));
EXPECT_EQ(kDefaultTextColorDark, style.text_color);
}
{
// Light background -> Dark text, more params don't matter.
FallbackIconStyle style;
EXPECT_TRUE(ParseSpecs("107,#fff,,0.3,0.5", &size, &style));
EXPECT_EQ(kDefaultTextColorDark, style.text_color);
}
}
TEST_F(FallbackIconUrlParserTest, ParseSpecsFailure) {
const char* test_cases[] = {
// Need exactly 5 params.
"",
"16",
"16,black",
"16,black,#fff",
"16,black,#fff,0.75",
",,,"
",,,,,",
"16,black,#fff,0.75,0.25,junk",
// Don't allow any space.
"16,black,#fff, 0.75,0.25",
"16,black ,#fff,0.75,0.25",
"16,black,#fff,0.75,0.25 ",
// Adding junk text.
"16,black,#fff,0.75,0.25junk",
"junk,black,#fff,0.75,0.25",
"16,#junk,#fff,0.75,0.25",
"16,black,#junk,0.75,0.25",
"16,black,#fff,junk,0.25",
"16,black,#fff,0.75,junk",
// Out of bound.
"0,black,#fff,0.75,0.25", // size.
"4294967296,black,#fff,0.75,0.25", // size.
"-1,black,#fff,0.75,0.25", // size.
"16,black,#fff,-0.1,0.25", // font_size_ratio.
"16,black,#fff,1.1,0.25", // font_size_ratio.
"16,black,#fff,0.75,-0.1", // roundness.
"16,black,#fff,0.75,1.1", // roundness.
};
for (size_t i = 0; i < arraysize(test_cases); ++i) {
int size;
FallbackIconStyle style;
EXPECT_FALSE(ParseSpecs(test_cases[i], &size, &style))
<< "test_cases[" << i << "]";
}
}
TEST_F(FallbackIconUrlParserTest, ParseFallbackIconPathSuccess) {
const std::string specs = "31,black,#fff,0.75,0.25";
// Everything populated.
{
chrome::ParsedFallbackIconPath parsed;
EXPECT_TRUE(parsed.Parse(specs + "/" + kTestUrlStr));
EXPECT_EQ(GURL(kTestUrlStr), parsed.url());
EXPECT_EQ(31, parsed.size_in_pixels());
const favicon_base::FallbackIconStyle& style = parsed.style();
EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
EXPECT_EQ(SkColorSetRGB(0xFF, 0xFF, 0xFF), style.text_color);
EXPECT_EQ(0.75, style.font_size_ratio);
EXPECT_EQ(0.25, style.roundness);
}
// Empty URL.
{
chrome::ParsedFallbackIconPath parsed;
EXPECT_TRUE(parsed.Parse(specs + "/"));
EXPECT_EQ(GURL(), parsed.url());
EXPECT_EQ(31, parsed.size_in_pixels());
const favicon_base::FallbackIconStyle& style = parsed.style();
EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
EXPECT_EQ(SkColorSetRGB(0xFF, 0xFF, 0xFF), style.text_color);
EXPECT_EQ(0.75, style.font_size_ratio);
EXPECT_EQ(0.25, style.roundness);
}
// Size and style are default.
{
chrome::ParsedFallbackIconPath parsed;
EXPECT_TRUE(parsed.Parse(std::string(",,,,/") + kTestUrlStr));
EXPECT_EQ(GURL(kTestUrlStr), parsed.url());
EXPECT_EQ(gfx::kFaviconSize, parsed.size_in_pixels());
const favicon_base::FallbackIconStyle& style = parsed.style();
EXPECT_EQ(kDefaultBackgroundColor, style.background_color);
EXPECT_EQ(kDefaultTextColorLight, style.text_color);
EXPECT_EQ(kDefaultFontSizeRatio, style.font_size_ratio);
EXPECT_EQ(kDefaultRoundness, style.roundness);
}
}
TEST_F(FallbackIconUrlParserTest, ParseFallbackIconPathFailure) {
const char* test_cases[] = {
// Bad size.
"-1,#000,#fff,0.75,0.25/http://www.google.com/",
// Bad specs.
"32,#junk,#fff,0.75,0.25/http://www.google.com/",
// Bad URL.
"32,#000,#fff,0.75,0.25/NOT A VALID URL",
};
for (size_t i = 0; i < arraysize(test_cases); ++i) {
chrome::ParsedFallbackIconPath parsed;
EXPECT_FALSE(parsed.Parse(test_cases[i])) << "test_cases[" << i << "]";
}
}
} // namespace chrome
...@@ -255,7 +255,6 @@ config("skia_library_config") { ...@@ -255,7 +255,6 @@ config("skia_library_config") {
"/wd4554", # 'operator' : check operator precedence for possible error "/wd4554", # 'operator' : check operator precedence for possible error
"/wd4748", # compiler will disable optimizations if a function has inline "/wd4748", # compiler will disable optimizations if a function has inline
# assembly code contains flow control(jmp or jcc) statements. # assembly code contains flow control(jmp or jcc) statements.
"/wd4800", # forcing value to bool 'true/false'(assigning int to bool). "/wd4800", # forcing value to bool 'true/false'(assigning int to bool).
] ]
} }
...@@ -343,7 +342,6 @@ component("skia") { ...@@ -343,7 +342,6 @@ component("skia") {
"//third_party/skia/include/utils/SkLayer.h", "//third_party/skia/include/utils/SkLayer.h",
"//third_party/skia/include/utils/SkMeshUtils.h", "//third_party/skia/include/utils/SkMeshUtils.h",
"//third_party/skia/include/utils/SkNinePatch.h", "//third_party/skia/include/utils/SkNinePatch.h",
"//third_party/skia/include/utils/SkParse.h",
"//third_party/skia/include/utils/SkParsePaint.h", "//third_party/skia/include/utils/SkParsePaint.h",
"//third_party/skia/include/utils/SkParsePath.h", "//third_party/skia/include/utils/SkParsePath.h",
"//third_party/skia/include/utils/SkRandom.h", "//third_party/skia/include/utils/SkRandom.h",
...@@ -364,8 +362,6 @@ component("skia") { ...@@ -364,8 +362,6 @@ component("skia") {
"//third_party/skia/src/utils/SkMeshUtils.cpp", "//third_party/skia/src/utils/SkMeshUtils.cpp",
"//third_party/skia/src/utils/SkNinePatch.cpp", "//third_party/skia/src/utils/SkNinePatch.cpp",
"//third_party/skia/src/utils/SkOSFile.cpp", "//third_party/skia/src/utils/SkOSFile.cpp",
"//third_party/skia/src/utils/SkParse.cpp",
"//third_party/skia/src/utils/SkParseColor.cpp",
"//third_party/skia/src/utils/SkParsePath.cpp", "//third_party/skia/src/utils/SkParsePath.cpp",
"//third_party/skia/src/utils/SkPathUtils.cpp", "//third_party/skia/src/utils/SkPathUtils.cpp",
"//third_party/skia/src/utils/SkSHA1.cpp", "//third_party/skia/src/utils/SkSHA1.cpp",
......
...@@ -102,7 +102,6 @@ ...@@ -102,7 +102,6 @@
'../third_party/skia/include/utils/SkLayer.h', '../third_party/skia/include/utils/SkLayer.h',
'../third_party/skia/include/utils/SkMeshUtils.h', '../third_party/skia/include/utils/SkMeshUtils.h',
'../third_party/skia/include/utils/SkNinePatch.h', '../third_party/skia/include/utils/SkNinePatch.h',
'../third_party/skia/include/utils/SkParse.h',
'../third_party/skia/include/utils/SkParsePaint.h', '../third_party/skia/include/utils/SkParsePaint.h',
'../third_party/skia/include/utils/SkParsePath.h', '../third_party/skia/include/utils/SkParsePath.h',
'../third_party/skia/include/utils/SkRandom.h', '../third_party/skia/include/utils/SkRandom.h',
...@@ -124,8 +123,6 @@ ...@@ -124,8 +123,6 @@
'../third_party/skia/src/utils/SkMeshUtils.cpp', '../third_party/skia/src/utils/SkMeshUtils.cpp',
'../third_party/skia/src/utils/SkNinePatch.cpp', '../third_party/skia/src/utils/SkNinePatch.cpp',
'../third_party/skia/src/utils/SkOSFile.cpp', '../third_party/skia/src/utils/SkOSFile.cpp',
'../third_party/skia/src/utils/SkParse.cpp',
'../third_party/skia/src/utils/SkParseColor.cpp',
'../third_party/skia/src/utils/SkParsePath.cpp', '../third_party/skia/src/utils/SkParsePath.cpp',
'../third_party/skia/src/utils/SkPathUtils.cpp', '../third_party/skia/src/utils/SkPathUtils.cpp',
'../third_party/skia/src/utils/SkSHA1.cpp', '../third_party/skia/src/utils/SkSHA1.cpp',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment