Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
      3  * Copyright (C) 2007 Nicholas Shanks <webkit (at) nickshanks.com>
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1.  Redistributions of source code must retain the above copyright
     10  *     notice, this list of conditions and the following disclaimer.
     11  * 2.  Redistributions in binary form must reproduce the above copyright
     12  *     notice, this list of conditions and the following disclaimer in the
     13  *     documentation and/or other materials provided with the distribution.
     14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     15  *     its contributors may be used to endorse or promote products derived
     16  *     from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include "config.h"
     31 #include "core/platform/graphics/FontCache.h"
     32 
     33 #include "FontFamilyNames.h"
     34 #include "core/platform/graphics/Font.h"
     35 #include "core/platform/graphics/FontFallbackList.h"
     36 #include "core/platform/graphics/FontPlatformData.h"
     37 #include "core/platform/graphics/FontSelector.h"
     38 #include "core/platform/graphics/opentype/OpenTypeVerticalData.h"
     39 #include "wtf/HashMap.h"
     40 #include "wtf/HashTableDeletedValueType.h"
     41 #include "wtf/ListHashSet.h"
     42 #include "wtf/StdLibExtras.h"
     43 #include "wtf/text/AtomicStringHash.h"
     44 #include "wtf/text/StringHash.h"
     45 
     46 using namespace WTF;
     47 
     48 namespace WebCore {
     49 
     50 FontCache* fontCache()
     51 {
     52     DEFINE_STATIC_LOCAL(FontCache, globalFontCache, ());
     53     return &globalFontCache;
     54 }
     55 
     56 FontCache::FontCache()
     57     : m_purgePreventCount(0)
     58 {
     59 }
     60 
     61 struct FontPlatformDataCacheKey {
     62     WTF_MAKE_FAST_ALLOCATED;
     63 public:
     64     FontPlatformDataCacheKey(const AtomicString& family = AtomicString(), unsigned size = 0, unsigned weight = 0, bool italic = false,
     65         bool isPrinterFont = false, FontOrientation orientation = Horizontal, FontWidthVariant widthVariant = RegularWidth)
     66         : m_size(size)
     67         , m_weight(weight)
     68         , m_family(family)
     69         , m_italic(italic)
     70         , m_printerFont(isPrinterFont)
     71         , m_orientation(orientation)
     72         , m_widthVariant(widthVariant)
     73     {
     74     }
     75 
     76     FontPlatformDataCacheKey(HashTableDeletedValueType) : m_size(hashTableDeletedSize()) { }
     77     bool isHashTableDeletedValue() const { return m_size == hashTableDeletedSize(); }
     78 
     79     bool operator==(const FontPlatformDataCacheKey& other) const
     80     {
     81         return equalIgnoringCase(m_family, other.m_family) && m_size == other.m_size
     82             && m_weight == other.m_weight && m_italic == other.m_italic && m_printerFont == other.m_printerFont
     83             && m_orientation == other.m_orientation && m_widthVariant == other.m_widthVariant;
     84     }
     85 
     86     unsigned m_size;
     87     unsigned m_weight;
     88     AtomicString m_family;
     89     bool m_italic;
     90     bool m_printerFont;
     91     FontOrientation m_orientation;
     92     FontWidthVariant m_widthVariant;
     93 
     94 private:
     95     static unsigned hashTableDeletedSize() { return 0xFFFFFFFFU; }
     96 };
     97 
     98 inline unsigned computeHash(const FontPlatformDataCacheKey& fontKey)
     99 {
    100     unsigned hashCodes[5] = {
    101         CaseFoldingHash::hash(fontKey.m_family),
    102         fontKey.m_size,
    103         fontKey.m_weight,
    104         fontKey.m_widthVariant,
    105         static_cast<unsigned>(fontKey.m_orientation) << 2 | static_cast<unsigned>(fontKey.m_italic) << 1 | static_cast<unsigned>(fontKey.m_printerFont)
    106     };
    107     return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes);
    108 }
    109 
    110 struct FontPlatformDataCacheKeyHash {
    111     static unsigned hash(const FontPlatformDataCacheKey& font)
    112     {
    113         return computeHash(font);
    114     }
    115 
    116     static bool equal(const FontPlatformDataCacheKey& a, const FontPlatformDataCacheKey& b)
    117     {
    118         return a == b;
    119     }
    120 
    121     static const bool safeToCompareToEmptyOrDeleted = true;
    122 };
    123 
    124 struct FontPlatformDataCacheKeyTraits : WTF::SimpleClassHashTraits<FontPlatformDataCacheKey> { };
    125 
    126 typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache;
    127 
    128 static FontPlatformDataCache* gFontPlatformDataCache = 0;
    129 
    130 static const AtomicString& alternateFamilyName(const AtomicString& familyName)
    131 {
    132     // Alias Courier <-> Courier New
    133     DEFINE_STATIC_LOCAL(AtomicString, courier, ("Courier", AtomicString::ConstructFromLiteral));
    134     DEFINE_STATIC_LOCAL(AtomicString, courierNew, ("Courier New", AtomicString::ConstructFromLiteral));
    135     if (equalIgnoringCase(familyName, courier))
    136         return courierNew;
    137 #if !OS(WINDOWS)
    138     // On Windows, Courier New (truetype font) is always present and
    139     // Courier is a bitmap font. So, we don't want to map Courier New to
    140     // Courier.
    141     if (equalIgnoringCase(familyName, courierNew))
    142         return courier;
    143 #endif
    144 
    145     // Alias Times and Times New Roman.
    146     DEFINE_STATIC_LOCAL(AtomicString, times, ("Times", AtomicString::ConstructFromLiteral));
    147     DEFINE_STATIC_LOCAL(AtomicString, timesNewRoman, ("Times New Roman", AtomicString::ConstructFromLiteral));
    148     if (equalIgnoringCase(familyName, times))
    149         return timesNewRoman;
    150     if (equalIgnoringCase(familyName, timesNewRoman))
    151         return times;
    152 
    153     // Alias Arial and Helvetica
    154     DEFINE_STATIC_LOCAL(AtomicString, arial, ("Arial", AtomicString::ConstructFromLiteral));
    155     DEFINE_STATIC_LOCAL(AtomicString, helvetica, ("Helvetica", AtomicString::ConstructFromLiteral));
    156     if (equalIgnoringCase(familyName, arial))
    157         return helvetica;
    158     if (equalIgnoringCase(familyName, helvetica))
    159         return arial;
    160 
    161 #if OS(WINDOWS)
    162     // On Windows, bitmap fonts are blocked altogether so that we have to
    163     // alias MS Sans Serif (bitmap font) -> Microsoft Sans Serif (truetype font)
    164     DEFINE_STATIC_LOCAL(AtomicString, msSans, ("MS Sans Serif", AtomicString::ConstructFromLiteral));
    165     DEFINE_STATIC_LOCAL(AtomicString, microsoftSans, ("Microsoft Sans Serif", AtomicString::ConstructFromLiteral));
    166     if (equalIgnoringCase(familyName, msSans))
    167         return microsoftSans;
    168 
    169     // Alias MS Serif (bitmap) -> Times New Roman (truetype font). There's no
    170     // 'Microsoft Sans Serif-equivalent' for Serif.
    171     DEFINE_STATIC_LOCAL(AtomicString, msSerif, ("MS Serif", AtomicString::ConstructFromLiteral));
    172     if (equalIgnoringCase(familyName, msSerif))
    173         return timesNewRoman;
    174 #endif
    175 
    176     return emptyAtom;
    177 }
    178 
    179 FontPlatformData* FontCache::getFontResourcePlatformData(const FontDescription& fontDescription,
    180                                                        const AtomicString& passedFamilyName,
    181                                                        bool checkingAlternateName)
    182 {
    183 #if OS(WINDOWS) && ENABLE(OPENTYPE_VERTICAL)
    184     // Leading "@" in the font name enables Windows vertical flow flag for the font.
    185     // Because we do vertical flow by ourselves, we don't want to use the Windows feature.
    186     // IE disregards "@" regardless of the orientatoin, so we follow the behavior.
    187     const AtomicString& familyName = (passedFamilyName.isEmpty() || passedFamilyName[0] != '@') ?
    188         passedFamilyName : AtomicString(passedFamilyName.impl()->substring(1));
    189 #else
    190     const AtomicString& familyName = passedFamilyName;
    191 #endif
    192 
    193     if (!gFontPlatformDataCache) {
    194         gFontPlatformDataCache = new FontPlatformDataCache;
    195         platformInit();
    196     }
    197 
    198     FontPlatformDataCacheKey key(familyName, fontDescription.computedPixelSize(), fontDescription.weight(), fontDescription.italic(),
    199         fontDescription.usePrinterFont(), fontDescription.orientation(), fontDescription.widthVariant());
    200     FontPlatformData* result = 0;
    201     bool foundResult;
    202     FontPlatformDataCache::iterator it = gFontPlatformDataCache->find(key);
    203     if (it == gFontPlatformDataCache->end()) {
    204         result = createFontPlatformData(fontDescription, familyName);
    205         gFontPlatformDataCache->set(key, result);
    206         foundResult = result;
    207     } else {
    208         result = it->value;
    209         foundResult = true;
    210     }
    211 
    212     if (!foundResult && !checkingAlternateName) {
    213         // We were unable to find a font.  We have a small set of fonts that we alias to other names,
    214         // e.g., Arial/Helvetica, Courier/Courier New, etc.  Try looking up the font under the aliased name.
    215         const AtomicString& alternateName = alternateFamilyName(familyName);
    216         if (!alternateName.isEmpty())
    217             result = getFontResourcePlatformData(fontDescription, alternateName, true);
    218         if (result)
    219             gFontPlatformDataCache->set(key, new FontPlatformData(*result)); // Cache the result under the old name.
    220     }
    221 
    222     return result;
    223 }
    224 
    225 #if ENABLE(OPENTYPE_VERTICAL)
    226 typedef HashMap<FontCache::FontFileKey, RefPtr<OpenTypeVerticalData>, WTF::IntHash<FontCache::FontFileKey>, WTF::UnsignedWithZeroKeyHashTraits<FontCache::FontFileKey> > FontVerticalDataCache;
    227 
    228 FontVerticalDataCache& fontVerticalDataCacheInstance()
    229 {
    230     DEFINE_STATIC_LOCAL(FontVerticalDataCache, fontVerticalDataCache, ());
    231     return fontVerticalDataCache;
    232 }
    233 
    234 PassRefPtr<OpenTypeVerticalData> FontCache::getVerticalData(const FontFileKey& key, const FontPlatformData& platformData)
    235 {
    236     FontVerticalDataCache& fontVerticalDataCache = fontVerticalDataCacheInstance();
    237     FontVerticalDataCache::iterator result = fontVerticalDataCache.find(key);
    238     if (result != fontVerticalDataCache.end())
    239         return result.get()->value;
    240 
    241     RefPtr<OpenTypeVerticalData> verticalData = OpenTypeVerticalData::create(platformData);
    242     if (!verticalData->isOpenType())
    243         verticalData.clear();
    244     fontVerticalDataCache.set(key, verticalData);
    245     return verticalData;
    246 }
    247 #endif
    248 
    249 struct FontDataCacheKeyHash {
    250     static unsigned hash(const FontPlatformData& platformData)
    251     {
    252         return platformData.hash();
    253     }
    254 
    255     static bool equal(const FontPlatformData& a, const FontPlatformData& b)
    256     {
    257         return a == b;
    258     }
    259 
    260     static const bool safeToCompareToEmptyOrDeleted = true;
    261 };
    262 
    263 struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> {
    264     static const bool emptyValueIsZero = true;
    265     static const bool needsDestruction = true;
    266     static const FontPlatformData& emptyValue()
    267     {
    268         DEFINE_STATIC_LOCAL(FontPlatformData, key, (0.f, false, false));
    269         return key;
    270     }
    271     static void constructDeletedValue(FontPlatformData& slot)
    272     {
    273         new (NotNull, &slot) FontPlatformData(HashTableDeletedValue);
    274     }
    275     static bool isDeletedValue(const FontPlatformData& value)
    276     {
    277         return value.isHashTableDeletedValue();
    278     }
    279 };
    280 
    281 typedef HashMap<FontPlatformData, pair<RefPtr<SimpleFontData>, unsigned>, FontDataCacheKeyHash, FontDataCacheKeyTraits> FontDataCache;
    282 
    283 static FontDataCache* gFontDataCache = 0;
    284 
    285 #if !OS(ANDROID)
    286 const int cMaxInactiveFontData = 250;
    287 const int cTargetInactiveFontData = 200;
    288 #else
    289 const int cMaxInactiveFontData = 225;
    290 const int cTargetInactiveFontData = 200;
    291 #endif
    292 static ListHashSet<RefPtr<SimpleFontData> >* gInactiveFontData = 0;
    293 
    294 PassRefPtr<SimpleFontData> FontCache::getFontResourceData(const FontDescription& fontDescription, const AtomicString& family, bool checkingAlternateName, ShouldRetain shouldRetain)
    295 {
    296     FontPlatformData* platformData = getFontResourcePlatformData(fontDescription, family, checkingAlternateName);
    297     if (!platformData)
    298         return 0;
    299 
    300     return getFontResourceData(platformData, shouldRetain);
    301 }
    302 
    303 PassRefPtr<SimpleFontData> FontCache::getFontResourceData(const FontPlatformData* platformData, ShouldRetain shouldRetain)
    304 {
    305     if (!platformData)
    306         return 0;
    307 
    308 #if !ASSERT_DISABLED
    309     if (shouldRetain == DoNotRetain)
    310         ASSERT(m_purgePreventCount);
    311 #endif
    312 
    313     if (!gFontDataCache) {
    314         gFontDataCache = new FontDataCache;
    315         gInactiveFontData = new ListHashSet<RefPtr<SimpleFontData> >;
    316     }
    317 
    318     FontDataCache::iterator result = gFontDataCache->find(*platformData);
    319     if (result == gFontDataCache->end()) {
    320         pair<RefPtr<SimpleFontData>, unsigned> newValue(SimpleFontData::create(*platformData), shouldRetain == Retain ? 1 : 0);
    321         gFontDataCache->set(*platformData, newValue);
    322         if (shouldRetain == DoNotRetain)
    323             gInactiveFontData->add(newValue.first);
    324         return newValue.first.release();
    325     }
    326 
    327     if (!result.get()->value.second) {
    328         ASSERT(gInactiveFontData->contains(result.get()->value.first));
    329         gInactiveFontData->remove(result.get()->value.first);
    330     }
    331 
    332     if (shouldRetain == Retain)
    333         result.get()->value.second++;
    334     else if (!result.get()->value.second) {
    335         // If shouldRetain is DoNotRetain and count is 0, we want to remove the fontData from
    336         // gInactiveFontData (above) and re-add here to update LRU position.
    337         gInactiveFontData->add(result.get()->value.first);
    338     }
    339 
    340     return result.get()->value.first;
    341 }
    342 
    343 SimpleFontData* FontCache::getNonRetainedLastResortFallbackFont(const FontDescription& fontDescription)
    344 {
    345     return getLastResortFallbackFont(fontDescription, DoNotRetain).leakRef();
    346 }
    347 
    348 void FontCache::releaseFontData(const SimpleFontData* fontData)
    349 {
    350     ASSERT(gFontDataCache);
    351     ASSERT(!fontData->isCustomFont());
    352 
    353     FontDataCache::iterator it = gFontDataCache->find(fontData->platformData());
    354     ASSERT(it != gFontDataCache->end());
    355     if (it == gFontDataCache->end())
    356         return;
    357 
    358     ASSERT(it->value.second);
    359     if (!--it->value.second)
    360         gInactiveFontData->add(it->value.first);
    361 }
    362 
    363 void FontCache::purgeInactiveFontDataIfNeeded()
    364 {
    365     if (gInactiveFontData && !m_purgePreventCount && gInactiveFontData->size() > cMaxInactiveFontData)
    366         purgeInactiveFontData(gInactiveFontData->size() - cTargetInactiveFontData);
    367 }
    368 
    369 void FontCache::purgeInactiveFontData(int count)
    370 {
    371     if (!gInactiveFontData || m_purgePreventCount)
    372         return;
    373 
    374     static bool isPurging;  // Guard against reentry when e.g. a deleted FontData releases its small caps FontData.
    375     if (isPurging)
    376         return;
    377 
    378     isPurging = true;
    379 
    380     Vector<RefPtr<SimpleFontData>, 20> fontDataToDelete;
    381     ListHashSet<RefPtr<SimpleFontData> >::iterator end = gInactiveFontData->end();
    382     ListHashSet<RefPtr<SimpleFontData> >::iterator it = gInactiveFontData->begin();
    383     for (int i = 0; i < count && it != end; ++it, ++i) {
    384         RefPtr<SimpleFontData>& fontData = *it.get();
    385         gFontDataCache->remove(fontData->platformData());
    386         // We should not delete SimpleFontData here because deletion can modify gInactiveFontData. See http://trac.webkit.org/changeset/44011
    387         fontDataToDelete.append(fontData);
    388     }
    389 
    390     if (it == end) {
    391         // Removed everything
    392         gInactiveFontData->clear();
    393     } else {
    394         for (int i = 0; i < count; ++i)
    395             gInactiveFontData->remove(gInactiveFontData->begin());
    396     }
    397 
    398     fontDataToDelete.clear();
    399 
    400     if (gFontPlatformDataCache) {
    401         Vector<FontPlatformDataCacheKey> keysToRemove;
    402         keysToRemove.reserveInitialCapacity(gFontPlatformDataCache->size());
    403         FontPlatformDataCache::iterator platformDataEnd = gFontPlatformDataCache->end();
    404         for (FontPlatformDataCache::iterator platformData = gFontPlatformDataCache->begin(); platformData != platformDataEnd; ++platformData) {
    405             if (platformData->value && !gFontDataCache->contains(*platformData->value))
    406                 keysToRemove.append(platformData->key);
    407         }
    408 
    409         size_t keysToRemoveCount = keysToRemove.size();
    410         for (size_t i = 0; i < keysToRemoveCount; ++i)
    411             delete gFontPlatformDataCache->take(keysToRemove[i]);
    412     }
    413 
    414 #if ENABLE(OPENTYPE_VERTICAL)
    415     FontVerticalDataCache& fontVerticalDataCache = fontVerticalDataCacheInstance();
    416     if (!fontVerticalDataCache.isEmpty()) {
    417         // Mark & sweep unused verticalData
    418         FontVerticalDataCache::iterator verticalDataEnd = fontVerticalDataCache.end();
    419         for (FontVerticalDataCache::iterator verticalData = fontVerticalDataCache.begin(); verticalData != verticalDataEnd; ++verticalData) {
    420             if (verticalData->value)
    421                 verticalData->value->m_inFontCache = false;
    422         }
    423         FontDataCache::iterator fontDataEnd = gFontDataCache->end();
    424         for (FontDataCache::iterator fontData = gFontDataCache->begin(); fontData != fontDataEnd; ++fontData) {
    425             OpenTypeVerticalData* verticalData = const_cast<OpenTypeVerticalData*>(fontData->value.first->verticalData());
    426             if (verticalData)
    427                 verticalData->m_inFontCache = true;
    428         }
    429         Vector<FontFileKey> keysToRemove;
    430         keysToRemove.reserveInitialCapacity(fontVerticalDataCache.size());
    431         for (FontVerticalDataCache::iterator verticalData = fontVerticalDataCache.begin(); verticalData != verticalDataEnd; ++verticalData) {
    432             if (!verticalData->value || !verticalData->value->m_inFontCache)
    433                 keysToRemove.append(verticalData->key);
    434         }
    435         for (size_t i = 0, count = keysToRemove.size(); i < count; ++i)
    436             fontVerticalDataCache.take(keysToRemove[i]);
    437     }
    438 #endif
    439 
    440     isPurging = false;
    441 }
    442 
    443 size_t FontCache::fontDataCount()
    444 {
    445     if (gFontDataCache)
    446         return gFontDataCache->size();
    447     return 0;
    448 }
    449 
    450 size_t FontCache::inactiveFontDataCount()
    451 {
    452     if (gInactiveFontData)
    453         return gInactiveFontData->size();
    454     return 0;
    455 }
    456 
    457 PassRefPtr<FontData> FontCache::getFontData(const Font& font, int& familyIndex, FontSelector* fontSelector)
    458 {
    459     RefPtr<FontData> result;
    460 
    461     int startIndex = familyIndex;
    462     const FontFamily* startFamily = &font.fontDescription().family();
    463     for (int i = 0; startFamily && i < startIndex; i++)
    464         startFamily = startFamily->next();
    465     const FontFamily* currFamily = startFamily;
    466     while (currFamily && !result) {
    467         familyIndex++;
    468         if (currFamily->family().length()) {
    469             if (fontSelector)
    470                 result = fontSelector->getFontData(font.fontDescription(), currFamily->family());
    471 
    472             if (!result)
    473                 result = getFontResourceData(font.fontDescription(), currFamily->family());
    474         }
    475         currFamily = currFamily->next();
    476     }
    477 
    478     if (!currFamily)
    479         familyIndex = cAllFamiliesScanned;
    480 
    481     if (!result)
    482         // We didn't find a font. Try to find a similar font using our own specific knowledge about our platform.
    483         // For example on OS X, we know to map any families containing the words Arabic, Pashto, or Urdu to the
    484         // Geeza Pro font.
    485         result = getSimilarFontPlatformData(font);
    486 
    487     if (!result && startIndex == 0) {
    488         // If it's the primary font that we couldn't find, we try the following. In all other cases, we will
    489         // just use per-character system fallback.
    490 
    491         if (fontSelector) {
    492             // Try the user's preferred standard font.
    493             if (RefPtr<FontData> data = fontSelector->getFontData(font.fontDescription(), standardFamily))
    494                 return data.release();
    495         }
    496 
    497         // Still no result.  Hand back our last resort fallback font.
    498         result = getLastResortFallbackFont(font.fontDescription());
    499     }
    500     return result.release();
    501 }
    502 
    503 static HashSet<FontSelector*>* gClients;
    504 
    505 void FontCache::addClient(FontSelector* client)
    506 {
    507     if (!gClients)
    508         gClients = new HashSet<FontSelector*>;
    509 
    510     ASSERT(!gClients->contains(client));
    511     gClients->add(client);
    512 }
    513 
    514 void FontCache::removeClient(FontSelector* client)
    515 {
    516     ASSERT(gClients);
    517     ASSERT(gClients->contains(client));
    518 
    519     gClients->remove(client);
    520 }
    521 
    522 static unsigned short gGeneration = 0;
    523 
    524 unsigned short FontCache::generation()
    525 {
    526     return gGeneration;
    527 }
    528 
    529 void FontCache::invalidate()
    530 {
    531     if (!gClients) {
    532         ASSERT(!gFontPlatformDataCache);
    533         return;
    534     }
    535 
    536     if (gFontPlatformDataCache) {
    537         deleteAllValues(*gFontPlatformDataCache);
    538         delete gFontPlatformDataCache;
    539         gFontPlatformDataCache = new FontPlatformDataCache;
    540     }
    541 
    542     gGeneration++;
    543 
    544     Vector<RefPtr<FontSelector> > clients;
    545     size_t numClients = gClients->size();
    546     clients.reserveInitialCapacity(numClients);
    547     HashSet<FontSelector*>::iterator end = gClients->end();
    548     for (HashSet<FontSelector*>::iterator it = gClients->begin(); it != end; ++it)
    549         clients.append(*it);
    550 
    551     ASSERT(numClients == clients.size());
    552     for (size_t i = 0; i < numClients; ++i)
    553         clients[i]->fontCacheInvalidated();
    554 
    555     purgeInactiveFontData();
    556 }
    557 
    558 const FontPlatformData* FontCache::getFallbackFontData(const FontDescription& description)
    559 {
    560     DEFINE_STATIC_LOCAL(const AtomicString, sansStr, ("Sans", AtomicString::ConstructFromLiteral));
    561     DEFINE_STATIC_LOCAL(const AtomicString, serifStr, ("Serif", AtomicString::ConstructFromLiteral));
    562     DEFINE_STATIC_LOCAL(const AtomicString, monospaceStr, ("Monospace", AtomicString::ConstructFromLiteral));
    563 
    564     FontPlatformData* fontPlatformData = 0;
    565     switch (description.genericFamily()) {
    566     case FontDescription::SerifFamily:
    567         fontPlatformData = getFontResourcePlatformData(description, serifStr);
    568         break;
    569     case FontDescription::MonospaceFamily:
    570         fontPlatformData = getFontResourcePlatformData(description, monospaceStr);
    571         break;
    572     case FontDescription::SansSerifFamily:
    573     default:
    574         fontPlatformData = getFontResourcePlatformData(description, sansStr);
    575         break;
    576     }
    577 
    578     return fontPlatformData;
    579 }
    580 
    581 } // namespace WebCore
    582