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 "platform/fonts/FontCache.h" 32 33 #include "platform/FontFamilyNames.h" 34 35 #include "platform/RuntimeEnabledFeatures.h" 36 #include "platform/fonts/AlternateFontFamily.h" 37 #include "platform/fonts/FontCacheClient.h" 38 #include "platform/fonts/FontCacheKey.h" 39 #include "platform/fonts/FontDataCache.h" 40 #include "platform/fonts/FontDescription.h" 41 #include "platform/fonts/FontFallbackList.h" 42 #include "platform/fonts/FontPlatformData.h" 43 #include "platform/fonts/FontSmoothingMode.h" 44 #include "platform/fonts/TextRenderingMode.h" 45 #include "platform/fonts/opentype/OpenTypeVerticalData.h" 46 #include "wtf/HashMap.h" 47 #include "wtf/ListHashSet.h" 48 #include "wtf/StdLibExtras.h" 49 #include "wtf/Vector.h" 50 #include "wtf/text/AtomicStringHash.h" 51 #include "wtf/text/StringHash.h" 52 53 using namespace WTF; 54 55 namespace blink { 56 57 #if !OS(WIN) 58 FontCache::FontCache() 59 : m_purgePreventCount(0) 60 { 61 } 62 #endif // !OS(WIN) 63 64 typedef HashMap<FontCacheKey, OwnPtr<FontPlatformData>, FontCacheKeyHash, FontCacheKeyTraits> FontPlatformDataCache; 65 66 static FontPlatformDataCache* gFontPlatformDataCache = 0; 67 68 #if OS(WIN) 69 bool FontCache::s_useDirectWrite = false; 70 IDWriteFactory* FontCache::s_directWriteFactory = 0; 71 bool FontCache::s_useSubpixelPositioning = false; 72 float FontCache::s_deviceScaleFactor = 1.0; 73 #endif // OS(WIN) 74 75 FontCache* FontCache::fontCache() 76 { 77 DEFINE_STATIC_LOCAL(FontCache, globalFontCache, ()); 78 return &globalFontCache; 79 } 80 81 FontPlatformData* FontCache::getFontPlatformData(const FontDescription& fontDescription, 82 const FontFaceCreationParams& creationParams, bool checkingAlternateName) 83 { 84 if (!gFontPlatformDataCache) { 85 gFontPlatformDataCache = new FontPlatformDataCache; 86 platformInit(); 87 } 88 89 FontCacheKey key = fontDescription.cacheKey(creationParams); 90 FontPlatformData* result = 0; 91 bool foundResult; 92 FontPlatformDataCache::iterator it = gFontPlatformDataCache->find(key); 93 if (it == gFontPlatformDataCache->end()) { 94 result = createFontPlatformData(fontDescription, creationParams, fontDescription.effectiveFontSize()); 95 gFontPlatformDataCache->set(key, adoptPtr(result)); 96 foundResult = result; 97 } else { 98 result = it->value.get(); 99 foundResult = true; 100 } 101 102 if (!foundResult && !checkingAlternateName && creationParams.creationType() == CreateFontByFamily) { 103 // We were unable to find a font. We have a small set of fonts that we alias to other names, 104 // e.g., Arial/Helvetica, Courier/Courier New, etc. Try looking up the font under the aliased name. 105 const AtomicString& alternateName = alternateFamilyName(creationParams.family()); 106 if (!alternateName.isEmpty()) { 107 FontFaceCreationParams createByAlternateFamily(alternateName); 108 result = getFontPlatformData(fontDescription, createByAlternateFamily, true); 109 } 110 if (result) 111 gFontPlatformDataCache->set(key, adoptPtr(new FontPlatformData(*result))); // Cache the result under the old name. 112 } 113 114 return result; 115 } 116 117 #if ENABLE(OPENTYPE_VERTICAL) 118 typedef HashMap<FontCache::FontFileKey, RefPtr<OpenTypeVerticalData>, IntHash<FontCache::FontFileKey>, UnsignedWithZeroKeyHashTraits<FontCache::FontFileKey> > FontVerticalDataCache; 119 120 FontVerticalDataCache& fontVerticalDataCacheInstance() 121 { 122 DEFINE_STATIC_LOCAL(FontVerticalDataCache, fontVerticalDataCache, ()); 123 return fontVerticalDataCache; 124 } 125 126 PassRefPtr<OpenTypeVerticalData> FontCache::getVerticalData(const FontFileKey& key, const FontPlatformData& platformData) 127 { 128 FontVerticalDataCache& fontVerticalDataCache = fontVerticalDataCacheInstance(); 129 FontVerticalDataCache::iterator result = fontVerticalDataCache.find(key); 130 if (result != fontVerticalDataCache.end()) 131 return result.get()->value; 132 133 RefPtr<OpenTypeVerticalData> verticalData = OpenTypeVerticalData::create(platformData); 134 if (!verticalData->isOpenType()) 135 verticalData.clear(); 136 fontVerticalDataCache.set(key, verticalData); 137 return verticalData; 138 } 139 #endif 140 141 static FontDataCache* gFontDataCache = 0; 142 143 PassRefPtr<SimpleFontData> FontCache::getFontData(const FontDescription& fontDescription, const AtomicString& family, bool checkingAlternateName, ShouldRetain shouldRetain) 144 { 145 if (FontPlatformData* platformData = getFontPlatformData(fontDescription, FontFaceCreationParams(adjustFamilyNameToAvoidUnsupportedFonts(family)), checkingAlternateName)) 146 return fontDataFromFontPlatformData(platformData, shouldRetain); 147 148 return nullptr; 149 } 150 151 PassRefPtr<SimpleFontData> FontCache::fontDataFromFontPlatformData(const FontPlatformData* platformData, ShouldRetain shouldRetain) 152 { 153 if (!gFontDataCache) 154 gFontDataCache = new FontDataCache; 155 156 #if ENABLE(ASSERT) 157 if (shouldRetain == DoNotRetain) 158 ASSERT(m_purgePreventCount); 159 #endif 160 161 return gFontDataCache->get(platformData, shouldRetain); 162 } 163 164 bool FontCache::isPlatformFontAvailable(const FontDescription& fontDescription, const AtomicString& family) 165 { 166 bool checkingAlternateName = true; 167 return getFontPlatformData(fontDescription, FontFaceCreationParams(adjustFamilyNameToAvoidUnsupportedFonts(family)), checkingAlternateName); 168 } 169 170 SimpleFontData* FontCache::getNonRetainedLastResortFallbackFont(const FontDescription& fontDescription) 171 { 172 return getLastResortFallbackFont(fontDescription, DoNotRetain).leakRef(); 173 } 174 175 void FontCache::releaseFontData(const SimpleFontData* fontData) 176 { 177 ASSERT(gFontDataCache); 178 179 gFontDataCache->release(fontData); 180 } 181 182 static inline void purgePlatformFontDataCache() 183 { 184 if (!gFontPlatformDataCache) 185 return; 186 187 Vector<FontCacheKey> keysToRemove; 188 keysToRemove.reserveInitialCapacity(gFontPlatformDataCache->size()); 189 FontPlatformDataCache::iterator platformDataEnd = gFontPlatformDataCache->end(); 190 for (FontPlatformDataCache::iterator platformData = gFontPlatformDataCache->begin(); platformData != platformDataEnd; ++platformData) { 191 if (platformData->value && !gFontDataCache->contains(platformData->value.get())) 192 keysToRemove.append(platformData->key); 193 } 194 gFontPlatformDataCache->removeAll(keysToRemove); 195 } 196 197 static inline void purgeFontVerticalDataCache() 198 { 199 #if ENABLE(OPENTYPE_VERTICAL) 200 FontVerticalDataCache& fontVerticalDataCache = fontVerticalDataCacheInstance(); 201 if (!fontVerticalDataCache.isEmpty()) { 202 // Mark & sweep unused verticalData 203 FontVerticalDataCache::iterator verticalDataEnd = fontVerticalDataCache.end(); 204 for (FontVerticalDataCache::iterator verticalData = fontVerticalDataCache.begin(); verticalData != verticalDataEnd; ++verticalData) { 205 if (verticalData->value) 206 verticalData->value->setInFontCache(false); 207 } 208 209 gFontDataCache->markAllVerticalData(); 210 211 Vector<FontCache::FontFileKey> keysToRemove; 212 keysToRemove.reserveInitialCapacity(fontVerticalDataCache.size()); 213 for (FontVerticalDataCache::iterator verticalData = fontVerticalDataCache.begin(); verticalData != verticalDataEnd; ++verticalData) { 214 if (!verticalData->value || !verticalData->value->inFontCache()) 215 keysToRemove.append(verticalData->key); 216 } 217 fontVerticalDataCache.removeAll(keysToRemove); 218 } 219 #endif 220 } 221 222 void FontCache::purge(PurgeSeverity PurgeSeverity) 223 { 224 // We should never be forcing the purge while the FontCachePurgePreventer is in scope. 225 ASSERT(!m_purgePreventCount || PurgeSeverity == PurgeIfNeeded); 226 if (m_purgePreventCount) 227 return; 228 229 if (!gFontDataCache || !gFontDataCache->purge(PurgeSeverity)) 230 return; 231 232 purgePlatformFontDataCache(); 233 purgeFontVerticalDataCache(); 234 } 235 236 static bool invalidateFontCache = false; 237 238 WillBeHeapHashSet<RawPtrWillBeWeakMember<FontCacheClient> >& fontCacheClients() 239 { 240 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<WillBeHeapHashSet<RawPtrWillBeWeakMember<FontCacheClient> > >, clients, (adoptPtrWillBeNoop(new WillBeHeapHashSet<RawPtrWillBeWeakMember<FontCacheClient> >()))); 241 invalidateFontCache = true; 242 return *clients; 243 } 244 245 void FontCache::addClient(FontCacheClient* client) 246 { 247 ASSERT(!fontCacheClients().contains(client)); 248 fontCacheClients().add(client); 249 } 250 251 #if !ENABLE(OILPAN) 252 void FontCache::removeClient(FontCacheClient* client) 253 { 254 ASSERT(fontCacheClients().contains(client)); 255 fontCacheClients().remove(client); 256 } 257 #endif 258 259 static unsigned short gGeneration = 0; 260 261 unsigned short FontCache::generation() 262 { 263 return gGeneration; 264 } 265 266 void FontCache::invalidate() 267 { 268 if (!invalidateFontCache) { 269 ASSERT(!gFontPlatformDataCache); 270 return; 271 } 272 273 if (gFontPlatformDataCache) { 274 delete gFontPlatformDataCache; 275 gFontPlatformDataCache = new FontPlatformDataCache; 276 } 277 278 gGeneration++; 279 280 WillBeHeapVector<RefPtrWillBeMember<FontCacheClient> > clients; 281 size_t numClients = fontCacheClients().size(); 282 clients.reserveInitialCapacity(numClients); 283 WillBeHeapHashSet<RawPtrWillBeWeakMember<FontCacheClient> >::iterator end = fontCacheClients().end(); 284 for (WillBeHeapHashSet<RawPtrWillBeWeakMember<FontCacheClient> >::iterator it = fontCacheClients().begin(); it != end; ++it) 285 clients.append(*it); 286 287 ASSERT(numClients == clients.size()); 288 for (size_t i = 0; i < numClients; ++i) 289 clients[i]->fontCacheInvalidated(); 290 291 purge(ForcePurge); 292 } 293 294 } // namespace blink 295