Skip to content

Commit

Permalink
Add support for the legacy chrome://favicon/size/16 format.
Browse files Browse the repository at this point in the history
Refactored FaviconSource to add unittests

BUG=225235
TEST=FaviconSourceTest.*

Review URL: https://chromiumcodereview.appspot.com/14348040

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@197628 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
pkotwicz@chromium.org committed May 1, 2013
1 parent 2c1bcf9 commit 89ba386
Show file tree
Hide file tree
Showing 5 changed files with 346 additions and 88 deletions.
191 changes: 108 additions & 83 deletions chrome/browser/ui/webui/favicon_source.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ FaviconSource::IconRequest::IconRequest()

FaviconSource::IconRequest::IconRequest(
const content::URLDataSource::GotDataCallback& cb,
const std::string& path,
const GURL& path,
int size,
ui::ScaleFactor scale)
: callback(cb),
Expand Down Expand Up @@ -88,110 +88,42 @@ void FaviconSource::StartDataRequest(
const content::URLDataSource::GotDataCallback& callback) {
FaviconService* favicon_service =
FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS);
if (!favicon_service || raw_path.empty()) {
if (!favicon_service) {
SendDefaultResponse(callback);
return;
}

// Translate to regular path if |raw_path| is of the form
// chrome-search://favicon/<most_visited_item_id>, where
// "most_visited_item_id" is a uint64.
std::string path = InstantService::MaybeTranslateInstantPathOnUI(profile_,
raw_path);

DCHECK_EQ(16, gfx::kFaviconSize);
bool is_icon_url = false;
GURL url;
int size_in_dip = 16;
ui::ScaleFactor scale_factor = ui::SCALE_FACTOR_100P;
bool success = ParsePath(raw_path, &is_icon_url, &url, &size_in_dip,
&scale_factor);

size_t parsed_index = 0;
if (HasSubstringAt(path, parsed_index, kLargestParameter)) {
parsed_index += strlen(kLargestParameter);
size_in_dip = 0;
} else if (HasSubstringAt(path, parsed_index, kSizeParameter)) {
parsed_index += strlen(kSizeParameter);

size_t scale_delimiter = path.find("@", parsed_index);
if (scale_delimiter == std::string::npos) {
SendDefaultResponse(callback);
return;
}

std::string size = path.substr(parsed_index,
scale_delimiter - parsed_index);
if (!base::StringToInt(size, &size_in_dip)) {
SendDefaultResponse(callback);
return;
}

if (size_in_dip != 64 && size_in_dip != 32) {
// Only 64x64, 32x32 and 16x16 icons are supported.
size_in_dip = 16;
}

size_t slash = path.find("/", scale_delimiter);
if (slash == std::string::npos) {
SendDefaultResponse(callback);
return;
}

std::string scale_str = path.substr(scale_delimiter + 1,
slash - scale_delimiter - 1);
webui::ParseScaleFactor(scale_str, &scale_factor);

// Return the default favicon (as opposed to a resized favicon) for
// favicon sizes which are not cached by the favicon service.
// Currently the favicon service caches:
// - favicons of sizes "16 * scale factor" px of type FAVICON
// where scale factor is one of FaviconUtil::GetFaviconScaleFactors().
// - the largest TOUCH_ICON / TOUCH_PRECOMPOSED_ICON
if (size_in_dip != 16 && icon_types_ == history::FAVICON) {
SendDefaultResponse(callback);
return;
}

parsed_index = slash + 1;
if (!success) {
SendDefaultResponse(callback);
return;
}

if (HasSubstringAt(path, parsed_index, kIconURLParameter)) {
parsed_index += strlen(kIconURLParameter);
if (is_icon_url) {
// TODO(michaelbai): Change GetRawFavicon to support combination of
// IconType.
favicon_service->GetRawFavicon(
GURL(path.substr(parsed_index)),
url,
history::FAVICON,
size_in_dip,
scale_factor,
base::Bind(&FaviconSource::OnFaviconDataAvailable,
base::Unretained(this),
IconRequest(callback,
path.substr(parsed_index),
url,
size_in_dip,
scale_factor)),
&cancelable_task_tracker_);
} else {
std::string url;

// URL requests prefixed with "origin/" are converted to a form with an
// empty path and a valid scheme. (e.g., example.com -->
// http://example.com/ or http://example.com/a --> http://example.com/)
if (HasSubstringAt(path, parsed_index, kOriginParameter)) {
parsed_index += strlen(kOriginParameter);
url = path.substr(parsed_index);

// If the URL does not specify a scheme (e.g., example.com instead of
// http://example.com), add "http://" as a default.
if (!GURL(url).has_scheme())
url = "http://" + url;

// Strip the path beyond the top-level domain.
url = GURL(url).GetOrigin().spec();
} else {
url = path.substr(parsed_index);
}

// Intercept requests for prepopulated pages.
for (size_t i = 0; i < arraysize(history::kPrepopulatedPages); i++) {
if (url ==
if (url.spec() ==
l10n_util::GetStringUTF8(history::kPrepopulatedPages[i].url_id)) {
callback.Run(
ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
Expand All @@ -203,7 +135,7 @@ void FaviconSource::StartDataRequest(

favicon_service->GetRawFaviconForURL(
FaviconService::FaviconForURLParams(
profile_, GURL(url), icon_types_, size_in_dip),
profile_, url, icon_types_, size_in_dip),
scale_factor,
base::Bind(&FaviconSource::OnFaviconDataAvailable,
base::Unretained(this),
Expand Down Expand Up @@ -241,6 +173,99 @@ bool FaviconSource::HandleMissingResource(const IconRequest& request) {
return false;
}

bool FaviconSource::ParsePath(const std::string& raw_path,
bool* is_icon_url,
GURL* url,
int* size_in_dip,
ui::ScaleFactor* scale_factor) const {
DCHECK_EQ(16, gfx::kFaviconSize);

*is_icon_url = false;
*url = GURL();
*size_in_dip = 16;
*scale_factor = ui::SCALE_FACTOR_100P;

if (raw_path.empty())
return false;

// Translate to regular path if |raw_path| is of the form
// chrome-search://favicon/<most_visited_item_id>, where
// "most_visited_item_id" is a uint64.
std::string path = InstantService::MaybeTranslateInstantPathOnUI(profile_,
raw_path);
size_t parsed_index = 0;
if (HasSubstringAt(path, parsed_index, kLargestParameter)) {
parsed_index += strlen(kLargestParameter);
*size_in_dip = 0;
} else if (HasSubstringAt(path, parsed_index, kSizeParameter)) {
parsed_index += strlen(kSizeParameter);

size_t slash = path.find("/", parsed_index);
if (slash == std::string::npos)
return false;

size_t scale_delimiter = path.find("@", parsed_index);
std::string size_str;
std::string scale_str;
if (scale_delimiter == std::string::npos) {
// Support the legacy size format of 'size/aa/' where 'aa' is the desired
// size in DIP for the sake of not regressing the extensions which use it.
size_str = path.substr(parsed_index, slash - parsed_index);
} else {
size_str = path.substr(parsed_index, scale_delimiter - parsed_index);
scale_str = path.substr(scale_delimiter + 1,
slash - scale_delimiter - 1);
}

if (!base::StringToInt(size_str, size_in_dip))
return false;

if (*size_in_dip != 64 && *size_in_dip != 32) {
// Only 64x64, 32x32 and 16x16 icons are supported.
*size_in_dip = 16;
}

if (!scale_str.empty())
webui::ParseScaleFactor(scale_str, scale_factor);

// Return the default favicon (as opposed to a resized favicon) for
// favicon sizes which are not cached by the favicon service.
// Currently the favicon service caches:
// - favicons of sizes "16 * scale factor" px of type FAVICON
// where scale factor is one of FaviconUtil::GetFaviconScaleFactors().
// - the largest TOUCH_ICON / TOUCH_PRECOMPOSED_ICON
if (*size_in_dip != 16 && icon_types_ == history::FAVICON)
return false;

parsed_index = slash + 1;
}

if (HasSubstringAt(path, parsed_index, kIconURLParameter)) {
parsed_index += strlen(kIconURLParameter);
*is_icon_url = true;
*url = GURL(path.substr(parsed_index));
} else {
// URL requests prefixed with "origin/" are converted to a form with an
// empty path and a valid scheme. (e.g., example.com -->
// http://example.com/ or http://example.com/a --> http://example.com/)
if (HasSubstringAt(path, parsed_index, kOriginParameter)) {
parsed_index += strlen(kOriginParameter);
std::string possibly_invalid_url = path.substr(parsed_index);

// If the URL does not specify a scheme (e.g., example.com instead of
// http://example.com), add "http://" as a default.
if (!GURL(possibly_invalid_url).has_scheme())
possibly_invalid_url = "http://" + possibly_invalid_url;

// Strip the path beyond the top-level domain.
*url = GURL(possibly_invalid_url).GetOrigin();
} else {
*url = GURL(path.substr(parsed_index));
}
}
return true;
}

void FaviconSource::OnFaviconDataAvailable(
const IconRequest& request,
const history::FaviconBitmapResult& bitmap_result) {
Expand All @@ -255,7 +280,7 @@ void FaviconSource::OnFaviconDataAvailable(
void FaviconSource::SendDefaultResponse(
const content::URLDataSource::GotDataCallback& callback) {
SendDefaultResponse(
IconRequest(callback, std::string(), 16, ui::SCALE_FACTOR_100P));
IconRequest(callback, GURL(), 16, ui::SCALE_FACTOR_100P));
}

void FaviconSource::SendDefaultResponse(const IconRequest& icon_request) {
Expand Down
19 changes: 15 additions & 4 deletions chrome/browser/ui/webui/favicon_source.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class FaviconSource : public content::URLDataSource {
// |type| is the type of icon this FaviconSource will provide.
FaviconSource(Profile* profile, IconType type);

virtual ~FaviconSource();

// content::URLDataSource implementation.
virtual std::string GetSource() const OVERRIDE;
virtual void StartDataRequest(
Expand All @@ -84,19 +86,17 @@ class FaviconSource : public content::URLDataSource {
struct IconRequest {
IconRequest();
IconRequest(const content::URLDataSource::GotDataCallback& cb,
const std::string& path,
const GURL& path,
int size,
ui::ScaleFactor scale);
~IconRequest();

content::URLDataSource::GotDataCallback callback;
std::string request_path;
GURL request_path;
int size_in_dip;
ui::ScaleFactor scale_factor;
};

virtual ~FaviconSource();

// Called when the favicon data is missing to perform additional checks to
// locate the resource.
// |request| contains information for the failed request.
Expand All @@ -106,6 +106,9 @@ class FaviconSource : public content::URLDataSource {
Profile* profile_;

private:
FRIEND_TEST_ALL_PREFIXES(FaviconSourceTest, InstantParsing);
FRIEND_TEST_ALL_PREFIXES(FaviconSourceTest, Parsing);

// Defines the allowed pixel sizes for requested favicons.
enum IconSize {
SIZE_16,
Expand All @@ -114,6 +117,14 @@ class FaviconSource : public content::URLDataSource {
NUM_SIZES
};

// Parses |raw_path|, which should be in the format described at the top of
// the file. Returns true if |raw_path| could be parsed.
bool ParsePath(const std::string& raw_path,
bool* is_icon_url,
GURL* url,
int* size_in_dip,
ui::ScaleFactor* scale_factor) const;

// Called when favicon data is available from the history backend.
void OnFaviconDataAvailable(
const IconRequest& request,
Expand Down
Loading

0 comments on commit 89ba386

Please sign in to comment.