Index: chrome/browser/history/history_backend.cc |
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc |
index 7488b353720ba31d2142d85fb21626aec5dbb3e5..e5e7420254171b6db28dba58b0242eaa37295ffa 100644 |
--- a/chrome/browser/history/history_backend.cc |
+++ b/chrome/browser/history/history_backend.cc |
@@ -36,6 +36,7 @@ |
#include "grit/chromium_strings.h" |
#include "grit/generated_resources.h" |
#include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
+#include "ui/gfx/favicon_size.h" |
#if defined(OS_ANDROID) |
#include "chrome/browser/history/android/android_provider_backend.h" |
@@ -94,6 +95,9 @@ static const int kMaxRedirectCount = 32; |
// and is archived. |
static const int kArchiveDaysThreshold = 90; |
+// The maximum number of favicon bitmaps stored for a single page. |
+const size_t kMaxFaviconsPerPage = 30; |
+ |
// Converts from PageUsageData to MostVisitedURL. |redirects| is a |
// list of redirects for this URL. Empty list means no redirects. |
MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data, |
@@ -1773,16 +1777,20 @@ bool HistoryBackend::GetThumbnailFromOlderRedirect( |
void HistoryBackend::GetFavicon(scoped_refptr<GetFaviconRequest> request, |
const GURL& icon_url, |
+ const gfx::Size& pixel_size, |
int icon_types) { |
- UpdateFaviconMappingAndFetchImpl(NULL, icon_url, request, icon_types); |
+ UpdateFaviconMappingAndFetchImpl(NULL, icon_url, request, pixel_size, |
+ icon_types); |
} |
void HistoryBackend::UpdateFaviconMappingAndFetch( |
scoped_refptr<GetFaviconRequest> request, |
const GURL& page_url, |
const GURL& icon_url, |
+ const gfx::Size& pixel_size, |
IconType icon_type) { |
- UpdateFaviconMappingAndFetchImpl(&page_url, icon_url, request, icon_type); |
+ UpdateFaviconMappingAndFetchImpl(&page_url, icon_url, request, pixel_size, |
+ icon_type); |
} |
void HistoryBackend::SetFaviconOutOfDateForPage(const GURL& page_url) { |
@@ -1824,16 +1832,24 @@ void HistoryBackend::SetImportedFavicons( |
std::set<GURL> favicons_changed; |
for (size_t i = 0; i < favicon_usage.size(); i++) { |
- FaviconID favicon_id = thumbnail_db_->GetFaviconIDForFaviconURL( |
- favicon_usage[i].favicon_url, history::FAVICON, NULL); |
- if (!favicon_id) { |
+ std::vector<FaviconIDAndSize> favicon_id_size_listing; |
+ thumbnail_db_->GetFaviconIDsForFaviconURL(favicon_usage[i].favicon_url, |
+ history::FAVICON, &favicon_id_size_listing); |
+ if (favicon_id_size_listing.empty()) { |
// This favicon doesn't exist yet, so we create it using the given data. |
- favicon_id = thumbnail_db_->AddFavicon(favicon_usage[i].favicon_url, |
- history::FAVICON); |
+ gfx::Size default_size = |
+ gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize); |
+ FaviconID favicon_id = thumbnail_db_->AddFavicon( |
+ favicon_usage[i].favicon_url, default_size, history::FAVICON); |
if (!favicon_id) |
continue; // Unable to add the favicon. |
thumbnail_db_->SetFavicon(favicon_id, |
new base::RefCountedBytes(favicon_usage[i].png_data), now); |
+ |
+ FaviconIDAndSize favicon_id_size; |
+ favicon_id_size.icon_id = favicon_id; |
+ favicon_id_size.icon_size = default_size; |
+ favicon_id_size_listing.push_back(favicon_id_size); |
} |
// Save the mapping from all the URLs to the favicon. |
@@ -1854,14 +1870,25 @@ void HistoryBackend::SetImportedFavicons( |
url_info.set_last_visit(base::Time()); |
url_info.set_hidden(false); |
db_->AddURL(url_info); |
- thumbnail_db_->AddIconMapping(*url, favicon_id); |
+ |
+ for (std::vector<FaviconIDAndSize>::iterator favicon_id_size = |
+ favicon_id_size_listing.begin(); |
+ favicon_id_size != favicon_id_size_listing.end(); |
+ ++favicon_id_size) { |
+ thumbnail_db_->AddIconMapping(*url, favicon_id_size->icon_id); |
+ } |
favicons_changed.insert(*url); |
} |
} else { |
- if (!thumbnail_db_->GetIconMappingForPageURL(*url, FAVICON, NULL)) { |
+ if (!thumbnail_db_->GetIconMappingsForPageURL(*url, FAVICON, NULL)) { |
// URL is present in history, update the favicon *only* if it is not |
// set already. |
- thumbnail_db_->AddIconMapping(*url, favicon_id); |
+ for (std::vector<FaviconIDAndSize>::iterator favicon_id_size = |
+ favicon_id_size_listing.begin(); |
+ favicon_id_size != favicon_id_size_listing.end(); |
+ ++favicon_id_size) { |
+ thumbnail_db_->AddIconMapping(*url, favicon_id_size->icon_id); |
+ } |
favicons_changed.insert(*url); |
} |
} |
@@ -1881,6 +1908,7 @@ void HistoryBackend::UpdateFaviconMappingAndFetchImpl( |
const GURL* page_url, |
const GURL& icon_url, |
scoped_refptr<GetFaviconRequest> request, |
+ const gfx::Size& pixel_size, |
int icon_types) { |
// Check only a single type was given when the page_url was specified. |
DCHECK(!page_url || (page_url && (icon_types == FAVICON || |
@@ -1892,22 +1920,15 @@ void HistoryBackend::UpdateFaviconMappingAndFetchImpl( |
FaviconData favicon; |
if (thumbnail_db_.get()) { |
- const FaviconID favicon_id = |
- thumbnail_db_->GetFaviconIDForFaviconURL( |
- icon_url, icon_types, &favicon.icon_type); |
+ std::vector<FaviconIDAndSize> favicon_id_size_listing; |
+ thumbnail_db_->GetFaviconIDsForFaviconURL(icon_url, icon_types, |
+ &favicon_id_size_listing); |
+ FaviconID favicon_id = GetFaviconID(favicon_id_size_listing, pixel_size); |
if (favicon_id) { |
- scoped_refptr<base::RefCountedBytes> data = new base::RefCountedBytes(); |
- favicon.known_icon = true; |
- Time last_updated; |
- if (thumbnail_db_->GetFavicon(favicon_id, &last_updated, &data->data(), |
- NULL, NULL)) { |
- favicon.expired = (Time::Now() - last_updated) > |
- TimeDelta::FromDays(kFaviconRefetchDays); |
- favicon.image_data = data; |
+ GetFaviconFromDB(favicon_id, &favicon); |
+ if (page_url) { |
+ SetFaviconMapping(*page_url, favicon_id, pixel_size, favicon.icon_type); |
} |
- |
- if (page_url) |
- SetFaviconMapping(*page_url, favicon_id, favicon.icon_type); |
} |
// else case, haven't cached entry yet. Caller is responsible for |
// downloading the favicon and invoking SetFavicon. |
@@ -1915,9 +1936,36 @@ void HistoryBackend::UpdateFaviconMappingAndFetchImpl( |
request->ForwardResult(request->handle(), favicon); |
} |
+FaviconID HistoryBackend::GetFaviconID( |
+ const std::vector<FaviconIDAndSize>& favicon_id_size_listing, |
+ const gfx::Size& desired_pixel_size) const { |
+ // Give preference to favicon sizes which will result in downscaling rather |
+ // than upscaling. |
+ FaviconID closest_favicon_id = 0; |
+ gfx::Size closest_pixel_size; |
+ for (size_t i = 0; i < favicon_id_size_listing.size(); ++i) { |
+ gfx::Size size = favicon_id_size_listing[i].icon_size; |
+ if (closest_pixel_size.GetArea() < desired_pixel_size.GetArea() && |
stevenjb
2012/08/01 00:00:31
Area may not be the best method for comparison. Fo
pkotwicz
2012/08/02 19:47:52
Agree
|
+ size.GetArea() > closest_pixel_size.GetArea()) { |
+ closest_favicon_id = favicon_id_size_listing[i].icon_id; |
+ closest_pixel_size = size; |
+ } else if (closest_pixel_size.GetArea() > desired_pixel_size.GetArea() && |
+ size.GetArea() < closest_pixel_size.GetArea() && |
+ size.GetArea() >= desired_pixel_size.GetArea()) { |
+ closest_favicon_id = favicon_id_size_listing[i].icon_id; |
+ closest_pixel_size = size; |
+ } |
+ |
+ if (closest_pixel_size == desired_pixel_size) |
+ break; |
+ } |
+ return closest_favicon_id; |
+} |
+ |
void HistoryBackend::GetFaviconForURL( |
scoped_refptr<GetFaviconRequest> request, |
const GURL& page_url, |
+ const gfx::Size& pixel_size, |
int icon_types) { |
if (request->canceled()) |
return; |
@@ -1925,7 +1973,7 @@ void HistoryBackend::GetFaviconForURL( |
FaviconData favicon; |
// Get the favicon from DB. |
- GetFaviconFromDB(page_url, icon_types, &favicon); |
+ GetFaviconFromDB(page_url, pixel_size, icon_types, &favicon); |
request->ForwardResult(request->handle(), favicon); |
} |
@@ -1944,24 +1992,38 @@ void HistoryBackend::SetFavicon( |
const GURL& page_url, |
const GURL& icon_url, |
scoped_refptr<base::RefCountedMemory> data, |
+ const gfx::Size& requested_size, |
IconType icon_type) { |
+ // For M22, store |requested_size| as the favicon's pixel size into the |
+ // favicon database table. |
+ // TODO(pkotwicz): Fix this. |
DCHECK(data.get()); |
if (!thumbnail_db_.get() || !db_.get()) |
return; |
- FaviconID id = thumbnail_db_->GetFaviconIDForFaviconURL( |
- icon_url, icon_type, NULL); |
- if (!id) |
- id = thumbnail_db_->AddFavicon(icon_url, icon_type); |
+ std::vector<FaviconIDAndSize> favicon_id_size_listing; |
+ thumbnail_db_->GetFaviconIDsForFaviconURL(icon_url, icon_type, |
+ &favicon_id_size_listing); |
+ FaviconID id = 0; |
+ for (size_t i = 0; i < favicon_id_size_listing.size(); ++i) { |
+ if (favicon_id_size_listing[i].icon_size == requested_size) { |
+ id = favicon_id_size_listing[i].icon_id; |
+ break; |
+ } |
+ } |
+ |
+ if (!id) |
+ id = thumbnail_db_->AddFavicon(icon_url, requested_size, icon_type); |
// Set the image data. |
thumbnail_db_->SetFavicon(id, data, Time::Now()); |
- SetFaviconMapping(page_url, id, icon_type); |
+ SetFaviconMapping(page_url, id, requested_size, icon_type); |
} |
void HistoryBackend::SetFaviconMapping(const GURL& page_url, |
FaviconID id, |
+ const gfx::Size& pixel_size, |
IconType icon_type) { |
if (!thumbnail_db_.get()) |
return; |
@@ -1990,7 +2052,7 @@ void HistoryBackend::SetFaviconMapping(const GURL& page_url, |
for (history::RedirectList::const_iterator i(redirects->begin()); |
i != redirects->end(); ++i) { |
FaviconID replaced_id; |
- if (AddOrUpdateIconMapping(*i, id, icon_type, &replaced_id)) { |
+ if (AddOrUpdateIconMapping(*i, id, pixel_size, icon_type, &replaced_id)) { |
// The page's favicon ID changed. This means that the one we just |
// changed from could have been orphaned, and we need to re-check it. |
// This is not super fast, but this case will get triggered rarely, |
@@ -2014,6 +2076,7 @@ void HistoryBackend::SetFaviconMapping(const GURL& page_url, |
bool HistoryBackend::AddOrUpdateIconMapping(const GURL& page_url, |
FaviconID id, |
+ const gfx::Size& pixel_size, |
IconType icon_type, |
FaviconID* replaced_icon) { |
*replaced_icon = 0; |
@@ -2025,26 +2088,41 @@ bool HistoryBackend::AddOrUpdateIconMapping(const GURL& page_url, |
} |
// Iterate all matched icon mappings, |
// a. If the given icon id and matched icon id are same, return. |
- // b. If the given icon type and matched icon type are same, but icon id |
- // are not, update the IconMapping. |
- // c. If the given icon_type and matched icon type are not same, but |
- // either of them is ICON_TOUCH or ICON_PRECOMPOSED_TOUCH, update the |
- // IconMapping. |
- // d. Otherwise add a icon mapping. |
+ // b. If the given icon size and the matched icon size are the same and |
+ // either: |
+ // i. the given icon type and the matched icon type are the same. |
+ // ii. the given icon type and matched icon type are not the same |
+ // but either of them is ICON_TOUCH or ICON_PRECOMPOSED_TOUCH. |
stevenjb
2012/08/01 00:00:31
Do we care about differentiating between touch and
pkotwicz
2012/08/02 19:47:52
I'll look into this.
|
+ // update the IconMapping. |
+ // c. If there are no matches, but the number of mappings for page url |
+ // has exceeded kMaxFaviconsPerPage, update an arbitrary mapping. This |
+ // is a last line of defense and this property should be enforced |
+ // elsewhere as well. |
stevenjb
2012/08/01 00:00:31
This seems a bit arbitrary. Have we considered def
pkotwicz
2012/08/02 19:47:52
We are actually going to be doing this too.
It sti
|
+ // d. Otherwise add an icon mapping. |
+ |
for (std::vector<IconMapping>::iterator m = icon_mappings.begin(); |
m != icon_mappings.end(); ++m) { |
if (m->icon_id == id) |
// The mapping is already there. |
return false; |
- if ((icon_type == TOUCH_ICON && m->icon_type == TOUCH_PRECOMPOSED_ICON) || |
- (icon_type == TOUCH_PRECOMPOSED_ICON && m->icon_type == TOUCH_ICON) || |
- (icon_type == m->icon_type)) { |
- thumbnail_db_->UpdateIconMapping(m->mapping_id, id); |
- *replaced_icon = m->icon_id; |
- return true; |
+ if (pixel_size == m->icon_pixel_size) { |
+ if ((icon_type == TOUCH_ICON && m->icon_type == TOUCH_PRECOMPOSED_ICON) || |
+ (icon_type == TOUCH_PRECOMPOSED_ICON && m->icon_type == TOUCH_ICON) || |
+ (icon_type == m->icon_type)) { |
+ thumbnail_db_->UpdateIconMapping(m->mapping_id, id); |
+ *replaced_icon = m->icon_id; |
+ return true; |
+ } |
} |
} |
+ |
+ if (icon_mappings.size() >= kMaxFaviconsPerPage) { |
+ thumbnail_db_->UpdateIconMapping(icon_mappings[0].mapping_id, id); |
+ *replaced_icon = icon_mappings[0].icon_id; |
stevenjb
2012/08/01 00:00:31
Shouldn't this logic be in AddIconMapping? It's no
pkotwicz
2012/08/02 19:47:52
I would rather not add extra SQL queries to AddIco
|
+ return true; |
+ } |
+ |
thumbnail_db_->AddIconMapping(page_url, id); |
return true; |
} |
@@ -2434,6 +2512,7 @@ BookmarkService* HistoryBackend::GetBookmarkService() { |
bool HistoryBackend::GetFaviconFromDB( |
const GURL& page_url, |
+ const gfx::Size& pixel_size, |
int icon_types, |
FaviconData* favicon) { |
DCHECK(favicon); |
@@ -2446,17 +2525,20 @@ bool HistoryBackend::GetFaviconFromDB( |
TimeTicks beginning_time = TimeTicks::Now(); |
std::vector<IconMapping> icon_mappings; |
- // Iterate over the known icons looking for one that includes one of the |
- // requested types. |
- if (thumbnail_db_->GetIconMappingsForPageURL(page_url, &icon_mappings)) { |
+ if (thumbnail_db_->GetIconMappingsForPageURL(page_url, icon_types, |
+ &icon_mappings)) { |
+ std::vector<FaviconIDAndSize> favicon_id_size_listing; |
for (std::vector<IconMapping>::iterator i = icon_mappings.begin(); |
i != icon_mappings.end(); ++i) { |
- if ((i->icon_type & icon_types) && |
- GetFaviconFromDB(i->icon_id, favicon)) { |
- success = true; |
- break; |
- } |
+ FaviconIDAndSize favicon_id_size; |
+ favicon_id_size.icon_id = i->icon_id; |
+ favicon_id_size.icon_size = i->icon_pixel_size; |
+ favicon_id_size_listing.push_back(favicon_id_size); |
} |
+ FaviconID favicon_id = GetFaviconID(favicon_id_size_listing, pixel_size); |
+ |
+ if (favicon_id && GetFaviconFromDB(favicon_id, favicon)) |
+ success = true; |
} |
UMA_HISTOGRAM_TIMES("History.GetFavIconFromDB", // historical name |
TimeTicks::Now() - beginning_time); |
@@ -2468,14 +2550,14 @@ bool HistoryBackend::GetFaviconFromDB(FaviconID favicon_id, |
Time last_updated; |
scoped_refptr<base::RefCountedBytes> data = new base::RefCountedBytes(); |
+ favicon->known_icon = true; |
if (!thumbnail_db_->GetFavicon(favicon_id, &last_updated, &data->data(), |
- &favicon->icon_url, &favicon->icon_type)) |
+ &favicon->icon_url, &favicon->requested_size, &favicon->icon_type)) |
return false; |
favicon->expired = (Time::Now() - last_updated) > |
TimeDelta::FromDays(kFaviconRefetchDays); |
- favicon->known_icon = true; |
- favicon->image_data = data; |
+ favicon->bitmap_data = data; |
return true; |
} |