2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
31 #include "platform/fonts/FontCache.h"
33 #include "platform/FontFamilyNames.h"
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/FontPlatformData.h"
42 #include "platform/fonts/FontSmoothingMode.h"
43 #include "platform/fonts/SimpleFontData.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"
58 FontCache::FontCache()
59 : m_purgePreventCount(0)
64 typedef HashMap
<FontCacheKey
, OwnPtr
<FontPlatformData
>, FontCacheKeyHash
, FontCacheKeyTraits
> FontPlatformDataCache
;
66 static FontPlatformDataCache
* gFontPlatformDataCache
= 0;
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;
75 FontCache
* FontCache::fontCache()
77 DEFINE_STATIC_LOCAL(FontCache
, globalFontCache
, ());
78 return &globalFontCache
;
81 FontPlatformData
* FontCache::getFontPlatformData(const FontDescription
& fontDescription
,
82 const FontFaceCreationParams
& creationParams
, bool checkingAlternateName
)
84 if (!gFontPlatformDataCache
) {
85 gFontPlatformDataCache
= new FontPlatformDataCache
;
89 FontCacheKey key
= fontDescription
.cacheKey(creationParams
);
90 FontPlatformData
* result
= 0;
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
));
98 result
= it
->value
.get();
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);
111 gFontPlatformDataCache
->set(key
, adoptPtr(new FontPlatformData(*result
))); // Cache the result under the old name.
117 typedef HashMap
<FontCache::FontFileKey
, RefPtr
<OpenTypeVerticalData
>, IntHash
<FontCache::FontFileKey
>, UnsignedWithZeroKeyHashTraits
<FontCache::FontFileKey
>> FontVerticalDataCache
;
119 FontVerticalDataCache
& fontVerticalDataCacheInstance()
121 DEFINE_STATIC_LOCAL(FontVerticalDataCache
, fontVerticalDataCache
, ());
122 return fontVerticalDataCache
;
125 PassRefPtr
<OpenTypeVerticalData
> FontCache::getVerticalData(const FontFileKey
& key
, const FontPlatformData
& platformData
)
127 FontVerticalDataCache
& fontVerticalDataCache
= fontVerticalDataCacheInstance();
128 FontVerticalDataCache::iterator result
= fontVerticalDataCache
.find(key
);
129 if (result
!= fontVerticalDataCache
.end())
130 return result
.get()->value
;
132 RefPtr
<OpenTypeVerticalData
> verticalData
= OpenTypeVerticalData::create(platformData
);
133 if (!verticalData
->isOpenType())
134 verticalData
.clear();
135 fontVerticalDataCache
.set(key
, verticalData
);
139 static FontDataCache
* gFontDataCache
= 0;
141 PassRefPtr
<SimpleFontData
> FontCache::getFontData(const FontDescription
& fontDescription
, const AtomicString
& family
, bool checkingAlternateName
, ShouldRetain shouldRetain
)
143 if (FontPlatformData
* platformData
= getFontPlatformData(fontDescription
, FontFaceCreationParams(adjustFamilyNameToAvoidUnsupportedFonts(family
)), checkingAlternateName
))
144 return fontDataFromFontPlatformData(platformData
, shouldRetain
);
149 PassRefPtr
<SimpleFontData
> FontCache::fontDataFromFontPlatformData(const FontPlatformData
* platformData
, ShouldRetain shouldRetain
)
152 gFontDataCache
= new FontDataCache
;
155 if (shouldRetain
== DoNotRetain
)
156 ASSERT(m_purgePreventCount
);
159 return gFontDataCache
->get(platformData
, shouldRetain
);
162 bool FontCache::isPlatformFontAvailable(const FontDescription
& fontDescription
, const AtomicString
& family
)
164 bool checkingAlternateName
= true;
165 return getFontPlatformData(fontDescription
, FontFaceCreationParams(adjustFamilyNameToAvoidUnsupportedFonts(family
)), checkingAlternateName
);
168 SimpleFontData
* FontCache::getNonRetainedLastResortFallbackFont(const FontDescription
& fontDescription
)
170 return getLastResortFallbackFont(fontDescription
, DoNotRetain
).leakRef();
173 void FontCache::releaseFontData(const SimpleFontData
* fontData
)
175 ASSERT(gFontDataCache
);
177 gFontDataCache
->release(fontData
);
180 static inline void purgePlatformFontDataCache()
182 if (!gFontPlatformDataCache
)
185 Vector
<FontCacheKey
> keysToRemove
;
186 keysToRemove
.reserveInitialCapacity(gFontPlatformDataCache
->size());
187 FontPlatformDataCache::iterator platformDataEnd
= gFontPlatformDataCache
->end();
188 for (FontPlatformDataCache::iterator platformData
= gFontPlatformDataCache
->begin(); platformData
!= platformDataEnd
; ++platformData
) {
189 if (platformData
->value
&& !gFontDataCache
->contains(platformData
->value
.get()))
190 keysToRemove
.append(platformData
->key
);
192 gFontPlatformDataCache
->removeAll(keysToRemove
);
195 static inline void purgeFontVerticalDataCache()
197 FontVerticalDataCache
& fontVerticalDataCache
= fontVerticalDataCacheInstance();
198 if (!fontVerticalDataCache
.isEmpty()) {
199 // Mark & sweep unused verticalData
200 FontVerticalDataCache::iterator verticalDataEnd
= fontVerticalDataCache
.end();
201 for (FontVerticalDataCache::iterator verticalData
= fontVerticalDataCache
.begin(); verticalData
!= verticalDataEnd
; ++verticalData
) {
202 if (verticalData
->value
)
203 verticalData
->value
->setInFontCache(false);
206 gFontDataCache
->markAllVerticalData();
208 Vector
<FontCache::FontFileKey
> keysToRemove
;
209 keysToRemove
.reserveInitialCapacity(fontVerticalDataCache
.size());
210 for (FontVerticalDataCache::iterator verticalData
= fontVerticalDataCache
.begin(); verticalData
!= verticalDataEnd
; ++verticalData
) {
211 if (!verticalData
->value
|| !verticalData
->value
->inFontCache())
212 keysToRemove
.append(verticalData
->key
);
214 fontVerticalDataCache
.removeAll(keysToRemove
);
218 void FontCache::purge(PurgeSeverity PurgeSeverity
)
220 // We should never be forcing the purge while the FontCachePurgePreventer is in scope.
221 ASSERT(!m_purgePreventCount
|| PurgeSeverity
== PurgeIfNeeded
);
222 if (m_purgePreventCount
)
225 if (!gFontDataCache
|| !gFontDataCache
->purge(PurgeSeverity
))
228 purgePlatformFontDataCache();
229 purgeFontVerticalDataCache();
232 static bool invalidateFontCache
= false;
234 WillBeHeapHashSet
<RawPtrWillBeWeakMember
<FontCacheClient
>>& fontCacheClients()
236 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent
<WillBeHeapHashSet
<RawPtrWillBeWeakMember
<FontCacheClient
>>>, clients
, (adoptPtrWillBeNoop(new WillBeHeapHashSet
<RawPtrWillBeWeakMember
<FontCacheClient
>>())));
237 invalidateFontCache
= true;
241 void FontCache::addClient(FontCacheClient
* client
)
243 ASSERT(!fontCacheClients().contains(client
));
244 fontCacheClients().add(client
);
248 void FontCache::removeClient(FontCacheClient
* client
)
250 ASSERT(fontCacheClients().contains(client
));
251 fontCacheClients().remove(client
);
255 static unsigned short gGeneration
= 0;
257 unsigned short FontCache::generation()
262 void FontCache::invalidate()
264 if (!invalidateFontCache
) {
265 ASSERT(!gFontPlatformDataCache
);
269 if (gFontPlatformDataCache
) {
270 delete gFontPlatformDataCache
;
271 gFontPlatformDataCache
= new FontPlatformDataCache
;
276 WillBeHeapVector
<RefPtrWillBeMember
<FontCacheClient
>> clients
;
277 size_t numClients
= fontCacheClients().size();
278 clients
.reserveInitialCapacity(numClients
);
279 WillBeHeapHashSet
<RawPtrWillBeWeakMember
<FontCacheClient
>>::iterator end
= fontCacheClients().end();
280 for (WillBeHeapHashSet
<RawPtrWillBeWeakMember
<FontCacheClient
>>::iterator it
= fontCacheClients().begin(); it
!= end
; ++it
)
283 ASSERT(numClients
== clients
.size());
284 for (size_t i
= 0; i
< numClients
; ++i
)
285 clients
[i
]->fontCacheInvalidated();