Make svn-apply/svn-unapply work with patches from git-format-patch.
[WebKit-https.git] / WebCore / platform / graphics / FontCache.cpp
1 /*
2  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "FontCache.h"
31
32 #include "Font.h"
33 #include "FontFallbackList.h"
34 #include "FontPlatformData.h"
35 #include "FontSelector.h"
36 #include "StringHash.h"
37 #include <wtf/HashMap.h>
38
39 namespace WebCore {
40
41 struct FontPlatformDataCacheKey {
42     FontPlatformDataCacheKey(const AtomicString& family = AtomicString(), unsigned size = 0, bool bold = false, bool italic = false,
43                              bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode)
44         : m_family(family)
45         , m_size(size)
46         , m_bold(bold)
47         , m_italic(italic)
48         , m_printerFont(isPrinterFont)
49         , m_renderingMode(renderingMode)
50     {
51     }
52
53     bool operator==(const FontPlatformDataCacheKey& other) const
54     {
55         return equalIgnoringCase(m_family, other.m_family) && m_size == other.m_size && 
56                m_bold == other.m_bold && m_italic == other.m_italic && m_printerFont == other.m_printerFont &&
57                m_renderingMode == other.m_renderingMode;
58     }
59     
60     AtomicString m_family;
61     unsigned m_size;
62     bool m_bold;
63     bool m_italic;
64     bool m_printerFont;
65     FontRenderingMode m_renderingMode;
66 };
67
68 inline unsigned computeHash(const FontPlatformDataCacheKey& fontKey)
69 {
70     unsigned hashCodes[4] = {
71         CaseFoldingHash::hash(fontKey.m_family),
72         fontKey.m_size,
73         static_cast<unsigned>(fontKey.m_bold) << 3 | static_cast<unsigned>(fontKey.m_italic) << 2 | static_cast<unsigned>(fontKey.m_printerFont) << 1 |
74         static_cast<unsigned>(fontKey.m_renderingMode)
75     };
76     return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), 4 * sizeof(unsigned) / sizeof(UChar));
77 }
78
79 struct FontPlatformDataCacheKeyHash {
80     static unsigned hash(const FontPlatformDataCacheKey& font)
81     {
82         return computeHash(font);
83     }
84          
85     static bool equal(const FontPlatformDataCacheKey& a, const FontPlatformDataCacheKey& b)
86     {
87         return a == b;
88     }
89
90     static const bool safeToCompareToEmptyOrDeleted = true;
91 };
92
93 struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> {
94     static const bool emptyValueIsZero = true;
95     static const bool needsDestruction = false;
96     static const FontPlatformDataCacheKey& deletedValue()
97     {
98         static FontPlatformDataCacheKey key(nullAtom, 0xFFFFFFFFU, false, false);
99         return key;
100     }
101     static const FontPlatformDataCacheKey& emptyValue()
102     {
103         static FontPlatformDataCacheKey key(nullAtom, 0, false, false);
104         return key;
105     }
106 };
107
108 typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache;
109
110 static FontPlatformDataCache* gFontPlatformDataCache = 0;
111
112 static const AtomicString& alternateFamilyName(const AtomicString& familyName)
113 {
114     // Alias Courier <-> Courier New
115     static AtomicString courier("Courier"), courierNew("Courier New");
116     if (equalIgnoringCase(familyName, courier))
117         return courierNew;
118     if (equalIgnoringCase(familyName, courierNew))
119         return courier;
120
121     // Alias Times and Times New Roman.
122     static AtomicString times("Times"), timesNewRoman("Times New Roman");
123     if (equalIgnoringCase(familyName, times))
124         return timesNewRoman;
125     if (equalIgnoringCase(familyName, timesNewRoman))
126         return times;
127     
128     // Alias Arial and Helvetica
129     static AtomicString arial("Arial"), helvetica("Helvetica");
130     if (equalIgnoringCase(familyName, arial))
131         return helvetica;
132     if (equalIgnoringCase(familyName, helvetica))
133         return arial;
134
135     return emptyAtom;
136 }
137
138 FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fontDescription, 
139                                                        const AtomicString& familyName,
140                                                        bool checkingAlternateName)
141 {
142     if (!gFontPlatformDataCache) {
143         gFontPlatformDataCache = new FontPlatformDataCache;
144         platformInit();
145     }
146
147     FontPlatformDataCacheKey key(familyName, fontDescription.computedPixelSize(), fontDescription.bold(), fontDescription.italic(),
148                                  fontDescription.usePrinterFont(), fontDescription.renderingMode());
149     FontPlatformData* result = 0;
150     bool foundResult;
151     FontPlatformDataCache::iterator it = gFontPlatformDataCache->find(key);
152     if (it == gFontPlatformDataCache->end()) {
153         result = createFontPlatformData(fontDescription, familyName);
154         gFontPlatformDataCache->set(key, result);
155         foundResult = result;
156     } else {
157         result = it->second;
158         foundResult = true;
159     }
160
161     if (!foundResult && !checkingAlternateName) {
162         // We were unable to find a font.  We have a small set of fonts that we alias to other names, 
163         // e.g., Arial/Helvetica, Courier/Courier New, etc.  Try looking up the font under the aliased name.
164         const AtomicString& alternateName = alternateFamilyName(familyName);
165         if (!alternateName.isEmpty())
166             result = getCachedFontPlatformData(fontDescription, alternateName, true);
167         if (result)
168             gFontPlatformDataCache->set(key, new FontPlatformData(*result)); // Cache the result under the old name.
169     }
170
171     return result;
172 }
173
174 struct FontDataCacheKeyHash {
175     static unsigned hash(const FontPlatformData& platformData)
176     {
177         return platformData.hash();
178     }
179          
180     static bool equal(const FontPlatformData& a, const FontPlatformData& b)
181     {
182         return a == b;
183     }
184
185     static const bool safeToCompareToEmptyOrDeleted = true;
186 };
187
188 struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> {
189     static const bool emptyValueIsZero = true;
190     static const bool needsDestruction = false;
191     static const FontPlatformData& deletedValue()
192     {
193         static FontPlatformData key = FontPlatformData::Deleted();
194         return key;
195     }
196     static const FontPlatformData& emptyValue()
197     {
198         static FontPlatformData key;
199         return key;
200     }
201 };
202
203 typedef HashMap<FontPlatformData, FontData*, FontDataCacheKeyHash, FontDataCacheKeyTraits> FontDataCache;
204
205 static FontDataCache* gFontDataCache = 0;
206
207 FontData* FontCache::getCachedFontData(const FontPlatformData* platformData)
208 {
209     if (!platformData)
210         return 0;
211
212     if (!gFontDataCache)
213         gFontDataCache = new FontDataCache;
214     
215     FontData* result = gFontDataCache->get(*platformData);
216     if (!result) {
217         result = new FontData(*platformData);
218         gFontDataCache->set(*platformData, result);
219     }
220         
221     return result;
222 }
223
224 const FontData* FontCache::getFontData(const Font& font, int& familyIndex, FontSelector* fontSelector)
225 {
226     FontPlatformData* result = 0;
227
228     int startIndex = familyIndex;
229     const FontFamily* startFamily = &font.fontDescription().family();
230     for (int i = 0; startFamily && i < startIndex; i++)
231         startFamily = startFamily->next();
232     const FontFamily* currFamily = startFamily;
233     while (currFamily && !result) {
234         familyIndex++;
235         if (currFamily->family().length()) {
236             if (fontSelector) {
237                 FontData* data = fontSelector->getFontData(font.fontDescription(), currFamily->family());
238                 if (data)
239                     return data;
240             }
241             result = getCachedFontPlatformData(font.fontDescription(), currFamily->family());
242         }
243         currFamily = currFamily->next();
244     }
245
246     if (!currFamily)
247         familyIndex = cAllFamiliesScanned;
248
249     if (!result)
250         // We didn't find a font. Try to find a similar font using our own specific knowledge about our platform.
251         // For example on OS X, we know to map any families containing the words Arabic, Pashto, or Urdu to the
252         // Geeza Pro font.
253         result = getSimilarFontPlatformData(font);
254
255     if (!result && startIndex == 0)
256         // We still don't have a result.  Hand back our last resort fallback font.  We only do the last resort fallback
257         // when trying to find the primary font.  Otherwise our fallback will rely on the actual characters used.
258         result = getLastResortFallbackFont(font.fontDescription());
259
260     // Now that we have a result, we need to go from FontPlatformData -> FontData.
261     return getCachedFontData(result);
262 }
263
264 } // namespace WebCore