15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file. 45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/font_family_cache.h" 65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <map> 85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/prefs/pref_service.h" 105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/strings/stringprintf.h" 115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/strings/utf_string_conversions.h" 125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/chrome_notification_types.h" 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/profiles/profile.h" 145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/common/pref_font_webkit_names.h" 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/common/pref_names.h" 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/public/browser/notification_source.h" 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Identifies the user data on the profile. 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const char kFontFamilyCacheKey[] = "FontFamilyCacheKey"; 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)FontFamilyCache::FontFamilyCache(Profile* profile) 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : prefs_(profile->GetPrefs()) { 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) profile_pref_registrar_.Init(profile->GetPrefs()); 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) notification_registrar_.Add(this, 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) chrome::NOTIFICATION_PROFILE_DESTROYED, 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) content::Source<Profile>(profile)); 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)FontFamilyCache::~FontFamilyCache() { 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void FontFamilyCache::FillFontFamilyMap(Profile* profile, 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const char* map_name, 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) content::ScriptFontFamilyMap* map) { 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FontFamilyCache* cache = 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) static_cast<FontFamilyCache*>(profile->GetUserData(&kFontFamilyCacheKey)); 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!cache) { 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cache = new FontFamilyCache(profile); 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // The profile takes ownership of |cache|. 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) profile->SetUserData(&kFontFamilyCacheKey, cache); 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cache->FillFontFamilyMap(map_name, map); 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void FontFamilyCache::FillFontFamilyMap(const char* map_name, 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) content::ScriptFontFamilyMap* map) { 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // TODO(falken): Get rid of the brute-force scan over possible 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // (font family / script) combinations - see http://crbug.com/308095. 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = 0; i < prefs::kWebKitScriptsForFontFamilyMapsLength; ++i) { 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const char* script = prefs::kWebKitScriptsForFontFamilyMaps[i]; 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::string16 result = FetchAndCacheFont(script, map_name); 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!result.empty()) 545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (*map)[script] = result; 555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)base::string16 FontFamilyCache::FetchFont(const char* script, 595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const char* map_name) { 605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string pref_name = base::StringPrintf("%s.%s", map_name, script); 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string font = prefs_->GetString(pref_name.c_str()); 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::string16 font16 = base::UTF8ToUTF16(font); 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Lazily constructs the map if it doesn't already exist. 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ScriptFontMap& map = font_family_map_[map_name]; 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) map[script] = font16; 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Register for profile preference changes. 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) profile_pref_registrar_.Add( 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pref_name.c_str(), 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&FontFamilyCache::OnPrefsChanged, base::Unretained(this))); 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return font16; 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)base::string16 FontFamilyCache::FetchAndCacheFont(const char* script, 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const char* map_name) { 775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FontFamilyMap::const_iterator it = font_family_map_.find(map_name); 785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (it != font_family_map_.end()) { 795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ScriptFontMap::const_iterator it2 = it->second.find(script); 805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (it2 != it->second.end()) 815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return it2->second; 825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return FetchFont(script, map_name); 855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// There are ~1000 entries in the cache. Avoid unnecessary object construction, 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// including std::string. 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void FontFamilyCache::OnPrefsChanged(const std::string& pref_name) { 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const size_t delimiter_length = 1; 915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const char delimiter = '.'; 925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (FontFamilyMap::iterator it = font_family_map_.begin(); 935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) it != font_family_map_.end(); 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++it) { 955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const char* map_name = it->first; 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t map_name_length = strlen(map_name); 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If the map name doesn't match, move on. 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (pref_name.compare(0, map_name_length, map_name) != 0) 1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) continue; 1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ScriptFontMap& map = it->second; 1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (ScriptFontMap::iterator it2 = map.begin(); it2 != map.end(); ++it2) { 1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const char* script = it2->first; 1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t script_length = strlen(script); 1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If the length doesn't match, move on. 1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (pref_name.size() != 1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) map_name_length + script_length + delimiter_length) 1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) continue; 1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If the script doesn't match, move on. 1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (pref_name.compare( 1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) map_name_length + delimiter_length, script_length, script) != 0) 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) continue; 1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If the delimiter doesn't match, move on. 1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (pref_name[map_name_length] != delimiter) 1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) continue; 1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Clear the cache and the observer. 1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) map.erase(it2); 1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) profile_pref_registrar_.Remove(pref_name.c_str()); 1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) break; 1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void FontFamilyCache::Observe(int type, 1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const content::NotificationSource& source, 1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const content::NotificationDetails& details) { 1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); 1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) profile_pref_registrar_.RemoveAll(); 1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 135