• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3  *           (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
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  * 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  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "config.h"
28 #include "CSSFontSelector.h"
29 
30 #include "CachedFont.h"
31 #include "CSSFontFace.h"
32 #include "CSSFontFaceRule.h"
33 #include "CSSFontFaceSource.h"
34 #include "CSSFontFaceSrcValue.h"
35 #include "CSSMutableStyleDeclaration.h"
36 #include "CSSPrimitiveValue.h"
37 #include "CSSPropertyNames.h"
38 #include "CSSSegmentedFontFace.h"
39 #include "CSSUnicodeRangeValue.h"
40 #include "CSSValueKeywords.h"
41 #include "CSSValueList.h"
42 #include "CachedResourceLoader.h"
43 #include "Document.h"
44 #include "FontCache.h"
45 #include "FontFamilyValue.h"
46 #include "Frame.h"
47 #include "RenderObject.h"
48 #include "Settings.h"
49 #include "SimpleFontData.h"
50 #include <wtf/text/AtomicString.h>
51 
52 #if ENABLE(SVG)
53 #include "SVGFontFaceElement.h"
54 #include "SVGNames.h"
55 #endif
56 
57 namespace WebCore {
58 
CSSFontSelector(Document * document)59 CSSFontSelector::CSSFontSelector(Document* document)
60     : m_document(document)
61 {
62     // FIXME: An old comment used to say there was no need to hold a reference to m_document
63     // because "we are guaranteed to be destroyed before the document". But there does not
64     // seem to be any such guarantee.
65 
66     ASSERT(m_document);
67     fontCache()->addClient(this);
68 }
69 
~CSSFontSelector()70 CSSFontSelector::~CSSFontSelector()
71 {
72     fontCache()->removeClient(this);
73     deleteAllValues(m_fontFaces);
74     deleteAllValues(m_locallyInstalledFontFaces);
75     deleteAllValues(m_fonts);
76 }
77 
isEmpty() const78 bool CSSFontSelector::isEmpty() const
79 {
80     return m_fonts.isEmpty();
81 }
82 
cachedResourceLoader() const83 CachedResourceLoader* CSSFontSelector::cachedResourceLoader() const
84 {
85     return m_document ? m_document->cachedResourceLoader() : 0;
86 }
87 
addFontFaceRule(const CSSFontFaceRule * fontFaceRule)88 void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
89 {
90     // Obtain the font-family property and the src property.  Both must be defined.
91     const CSSMutableStyleDeclaration* style = fontFaceRule->style();
92     RefPtr<CSSValue> fontFamily = style->getPropertyCSSValue(CSSPropertyFontFamily);
93     RefPtr<CSSValue> src = style->getPropertyCSSValue(CSSPropertySrc);
94     RefPtr<CSSValue> unicodeRange = style->getPropertyCSSValue(CSSPropertyUnicodeRange);
95     if (!fontFamily || !src || !fontFamily->isValueList() || !src->isValueList() || (unicodeRange && !unicodeRange->isValueList()))
96         return;
97 
98     CSSValueList* familyList = static_cast<CSSValueList*>(fontFamily.get());
99     if (!familyList->length())
100         return;
101 
102     CSSValueList* srcList = static_cast<CSSValueList*>(src.get());
103     if (!srcList->length())
104         return;
105 
106     CSSValueList* rangeList = static_cast<CSSValueList*>(unicodeRange.get());
107 
108     unsigned traitsMask = 0;
109 
110     if (RefPtr<CSSValue> fontStyle = style->getPropertyCSSValue(CSSPropertyFontStyle)) {
111         if (fontStyle->isPrimitiveValue()) {
112             RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
113             list->append(fontStyle);
114             fontStyle = list;
115         } else if (!fontStyle->isValueList())
116             return;
117 
118         CSSValueList* styleList = static_cast<CSSValueList*>(fontStyle.get());
119         unsigned numStyles = styleList->length();
120         if (!numStyles)
121             return;
122 
123         for (unsigned i = 0; i < numStyles; ++i) {
124             switch (static_cast<CSSPrimitiveValue*>(styleList->itemWithoutBoundsCheck(i))->getIdent()) {
125                 case CSSValueAll:
126                     traitsMask |= FontStyleMask;
127                     break;
128                 case CSSValueNormal:
129                     traitsMask |= FontStyleNormalMask;
130                     break;
131                 case CSSValueItalic:
132                 case CSSValueOblique:
133                     traitsMask |= FontStyleItalicMask;
134                     break;
135                 default:
136                     break;
137             }
138         }
139     } else
140         traitsMask |= FontStyleMask;
141 
142     if (RefPtr<CSSValue> fontWeight = style->getPropertyCSSValue(CSSPropertyFontWeight)) {
143         if (fontWeight->isPrimitiveValue()) {
144             RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
145             list->append(fontWeight);
146             fontWeight = list;
147         } else if (!fontWeight->isValueList())
148             return;
149 
150         CSSValueList* weightList = static_cast<CSSValueList*>(fontWeight.get());
151         unsigned numWeights = weightList->length();
152         if (!numWeights)
153             return;
154 
155         for (unsigned i = 0; i < numWeights; ++i) {
156             switch (static_cast<CSSPrimitiveValue*>(weightList->itemWithoutBoundsCheck(i))->getIdent()) {
157                 case CSSValueAll:
158                     traitsMask |= FontWeightMask;
159                     break;
160                 case CSSValueBolder:
161                 case CSSValueBold:
162                 case CSSValue700:
163                     traitsMask |= FontWeight700Mask;
164                     break;
165                 case CSSValueNormal:
166                 case CSSValue400:
167                     traitsMask |= FontWeight400Mask;
168                     break;
169                 case CSSValue900:
170                     traitsMask |= FontWeight900Mask;
171                     break;
172                 case CSSValue800:
173                     traitsMask |= FontWeight800Mask;
174                     break;
175                 case CSSValue600:
176                     traitsMask |= FontWeight600Mask;
177                     break;
178                 case CSSValue500:
179                     traitsMask |= FontWeight500Mask;
180                     break;
181                 case CSSValue300:
182                     traitsMask |= FontWeight300Mask;
183                     break;
184                 case CSSValueLighter:
185                 case CSSValue200:
186                     traitsMask |= FontWeight200Mask;
187                     break;
188                 case CSSValue100:
189                     traitsMask |= FontWeight100Mask;
190                     break;
191                 default:
192                     break;
193             }
194         }
195     } else
196         traitsMask |= FontWeightMask;
197 
198     if (RefPtr<CSSValue> fontVariant = style->getPropertyCSSValue(CSSPropertyFontVariant)) {
199         if (fontVariant->isPrimitiveValue()) {
200             RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
201             list->append(fontVariant);
202             fontVariant = list;
203         } else if (!fontVariant->isValueList())
204             return;
205 
206         CSSValueList* variantList = static_cast<CSSValueList*>(fontVariant.get());
207         unsigned numVariants = variantList->length();
208         if (!numVariants)
209             return;
210 
211         for (unsigned i = 0; i < numVariants; ++i) {
212             switch (static_cast<CSSPrimitiveValue*>(variantList->itemWithoutBoundsCheck(i))->getIdent()) {
213                 case CSSValueAll:
214                     traitsMask |= FontVariantMask;
215                     break;
216                 case CSSValueNormal:
217                     traitsMask |= FontVariantNormalMask;
218                     break;
219                 case CSSValueSmallCaps:
220                     traitsMask |= FontVariantSmallCapsMask;
221                     break;
222                 default:
223                     break;
224             }
225         }
226     } else
227         traitsMask |= FontVariantMask;
228 
229     // Each item in the src property's list is a single CSSFontFaceSource. Put them all into a CSSFontFace.
230     RefPtr<CSSFontFace> fontFace;
231 
232     int srcLength = srcList->length();
233 
234     bool foundSVGFont = false;
235 
236     for (int i = 0; i < srcLength; i++) {
237         // An item in the list either specifies a string (local font name) or a URL (remote font to download).
238         CSSFontFaceSrcValue* item = static_cast<CSSFontFaceSrcValue*>(srcList->itemWithoutBoundsCheck(i));
239         CSSFontFaceSource* source = 0;
240 
241 #if ENABLE(SVG_FONTS)
242         foundSVGFont = item->isSVGFontFaceSrc() || item->svgFontFaceElement();
243 #endif
244         if (!item->isLocal()) {
245             Settings* settings = m_document ? m_document->frame() ? m_document->frame()->settings() : 0 : 0;
246             bool allowDownloading = foundSVGFont || (settings && settings->downloadableBinaryFontsEnabled());
247             if (allowDownloading && item->isSupportedFormat() && m_document) {
248                 CachedFont* cachedFont = m_document->cachedResourceLoader()->requestFont(item->resource());
249                 if (cachedFont) {
250                     source = new CSSFontFaceSource(item->resource(), cachedFont);
251 #if ENABLE(SVG_FONTS)
252                     if (foundSVGFont)
253                         source->setHasExternalSVGFont(true);
254 #endif
255                 }
256             }
257         } else {
258             source = new CSSFontFaceSource(item->resource());
259         }
260 
261         if (!fontFace)
262             fontFace = CSSFontFace::create(static_cast<FontTraitsMask>(traitsMask));
263 
264         if (source) {
265 #if ENABLE(SVG_FONTS)
266             source->setSVGFontFaceElement(item->svgFontFaceElement());
267 #endif
268             fontFace->addSource(source);
269         }
270     }
271 
272     ASSERT(fontFace);
273 
274     if (fontFace && !fontFace->isValid())
275         return;
276 
277     if (rangeList) {
278         unsigned numRanges = rangeList->length();
279         for (unsigned i = 0; i < numRanges; i++) {
280             CSSUnicodeRangeValue* range = static_cast<CSSUnicodeRangeValue*>(rangeList->itemWithoutBoundsCheck(i));
281             fontFace->addRange(range->from(), range->to());
282         }
283     }
284 
285     // Hash under every single family name.
286     int familyLength = familyList->length();
287     for (int i = 0; i < familyLength; i++) {
288         CSSPrimitiveValue* item = static_cast<CSSPrimitiveValue*>(familyList->itemWithoutBoundsCheck(i));
289         String familyName;
290         if (item->primitiveType() == CSSPrimitiveValue::CSS_STRING)
291             familyName = static_cast<FontFamilyValue*>(item)->familyName();
292         else if (item->primitiveType() == CSSPrimitiveValue::CSS_IDENT) {
293             // We need to use the raw text for all the generic family types, since @font-face is a way of actually
294             // defining what font to use for those types.
295             String familyName;
296             switch (item->getIdent()) {
297                 case CSSValueSerif:
298                     familyName = "-webkit-serif";
299                     break;
300                 case CSSValueSansSerif:
301                     familyName = "-webkit-sans-serif";
302                     break;
303                 case CSSValueCursive:
304                     familyName = "-webkit-cursive";
305                     break;
306                 case CSSValueFantasy:
307                     familyName = "-webkit-fantasy";
308                     break;
309                 case CSSValueMonospace:
310                     familyName = "-webkit-monospace";
311                     break;
312                 default:
313                     break;
314             }
315         }
316 
317         if (familyName.isEmpty())
318             continue;
319 
320         Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(familyName);
321         if (!familyFontFaces) {
322             familyFontFaces = new Vector<RefPtr<CSSFontFace> >;
323             m_fontFaces.set(familyName, familyFontFaces);
324 
325             ASSERT(!m_locallyInstalledFontFaces.contains(familyName));
326             Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFaces;
327 
328             Vector<unsigned> locallyInstalledFontsTraitsMasks;
329             fontCache()->getTraitsInFamily(familyName, locallyInstalledFontsTraitsMasks);
330             unsigned numLocallyInstalledFaces = locallyInstalledFontsTraitsMasks.size();
331             if (numLocallyInstalledFaces) {
332                 familyLocallyInstalledFaces = new Vector<RefPtr<CSSFontFace> >;
333                 m_locallyInstalledFontFaces.set(familyName, familyLocallyInstalledFaces);
334 
335                 for (unsigned i = 0; i < numLocallyInstalledFaces; ++i) {
336                     RefPtr<CSSFontFace> locallyInstalledFontFace = CSSFontFace::create(static_cast<FontTraitsMask>(locallyInstalledFontsTraitsMasks[i]), true);
337                     locallyInstalledFontFace->addSource(new CSSFontFaceSource(familyName));
338                     ASSERT(locallyInstalledFontFace->isValid());
339                     familyLocallyInstalledFaces->append(locallyInstalledFontFace);
340                 }
341             }
342         }
343 
344         familyFontFaces->append(fontFace);
345     }
346 }
347 
registerForInvalidationCallbacks(FontSelectorClient * client)348 void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient* client)
349 {
350     m_clients.add(client);
351 }
352 
unregisterForInvalidationCallbacks(FontSelectorClient * client)353 void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient* client)
354 {
355     m_clients.remove(client);
356 }
357 
dispatchInvalidationCallbacks()358 void CSSFontSelector::dispatchInvalidationCallbacks()
359 {
360     Vector<FontSelectorClient*> clients;
361     copyToVector(m_clients, clients);
362     for (size_t i = 0; i < clients.size(); ++i)
363         clients[i]->fontsNeedUpdate(this);
364 
365     // FIXME: Make Document a FontSelectorClient so that it can simply register for invalidation callbacks.
366     if (!m_document || m_document->inPageCache() || !m_document->renderer())
367         return;
368     m_document->scheduleForcedStyleRecalc();
369 }
370 
fontLoaded()371 void CSSFontSelector::fontLoaded()
372 {
373     dispatchInvalidationCallbacks();
374 }
375 
fontCacheInvalidated()376 void CSSFontSelector::fontCacheInvalidated()
377 {
378     dispatchInvalidationCallbacks();
379 }
380 
retireCustomFont(FontData * fontData)381 void CSSFontSelector::retireCustomFont(FontData* fontData)
382 {
383     if (m_document)
384         m_document->retireCustomFont(fontData);
385     else {
386         GlyphPageTreeNode::pruneTreeCustomFontData(fontData);
387         delete fontData;
388     }
389 }
390 
fontDataForGenericFamily(Document * document,const FontDescription & fontDescription,const AtomicString & familyName)391 static FontData* fontDataForGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName)
392 {
393     if (!document || !document->frame())
394         return 0;
395 
396     const Settings* settings = document->frame()->settings();
397     if (!settings)
398         return 0;
399 
400     AtomicString genericFamily;
401     if (familyName == "-webkit-serif")
402         genericFamily = settings->serifFontFamily();
403     else if (familyName == "-webkit-sans-serif")
404         genericFamily = settings->sansSerifFontFamily();
405     else if (familyName == "-webkit-cursive")
406         genericFamily = settings->cursiveFontFamily();
407     else if (familyName == "-webkit-fantasy")
408         genericFamily = settings->fantasyFontFamily();
409     else if (familyName == "-webkit-monospace")
410         genericFamily = settings->fixedFontFamily();
411     else if (familyName == "-webkit-standard")
412         genericFamily = settings->standardFontFamily();
413 
414     if (!genericFamily.isEmpty())
415         return fontCache()->getCachedFontData(fontDescription, genericFamily);
416 
417     return 0;
418 }
419 
420 static FontTraitsMask desiredTraitsMaskForComparison;
421 
compareFontFaces(CSSFontFace * first,CSSFontFace * second)422 static inline bool compareFontFaces(CSSFontFace* first, CSSFontFace* second)
423 {
424     FontTraitsMask firstTraitsMask = first->traitsMask();
425     FontTraitsMask secondTraitsMask = second->traitsMask();
426 
427     bool firstHasDesiredVariant = firstTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
428     bool secondHasDesiredVariant = secondTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
429 
430     if (firstHasDesiredVariant != secondHasDesiredVariant)
431         return firstHasDesiredVariant;
432 
433     if ((desiredTraitsMaskForComparison & FontVariantSmallCapsMask) && !first->isLocalFallback() && !second->isLocalFallback()) {
434         // Prefer a font that has indicated that it can only support small-caps to a font that claims to support
435         // all variants.  The specialized font is more likely to be true small-caps and not require synthesis.
436         bool firstRequiresSmallCaps = (firstTraitsMask & FontVariantSmallCapsMask) && !(firstTraitsMask & FontVariantNormalMask);
437         bool secondRequiresSmallCaps = (secondTraitsMask & FontVariantSmallCapsMask) && !(secondTraitsMask & FontVariantNormalMask);
438         if (firstRequiresSmallCaps != secondRequiresSmallCaps)
439             return firstRequiresSmallCaps;
440     }
441 
442     bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
443     bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
444 
445     if (firstHasDesiredStyle != secondHasDesiredStyle)
446         return firstHasDesiredStyle;
447 
448     if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first->isLocalFallback() && !second->isLocalFallback()) {
449         // Prefer a font that has indicated that it can only support italics to a font that claims to support
450         // all styles.  The specialized font is more likely to be the one the author wants used.
451         bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask);
452         bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask);
453         if (firstRequiresItalics != secondRequiresItalics)
454             return firstRequiresItalics;
455     }
456 
457     if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
458         return false;
459     if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
460         return true;
461 
462     // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#q46 says: "If there are fewer then 9 weights in the family, the default algorithm
463     // for filling the "holes" is as follows. If '500' is unassigned, it will be assigned the same font as '400'. If any of the values '600',
464     // '700', '800', or '900' remains unassigned, they are assigned to the same face as the next darker assigned keyword, if any, or the next
465     // lighter one otherwise. If any of '300', '200', or '100' remains unassigned, it is assigned to the next lighter assigned keyword, if any,
466     // or the next darker otherwise."
467     // For '400', we made up our own rule (which then '500' follows).
468 
469     static const unsigned fallbackRuleSets = 9;
470     static const unsigned rulesPerSet = 8;
471     static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = {
472         { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
473         { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
474         { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
475         { FontWeight500Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask },
476         { FontWeight400Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask },
477         { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
478         { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
479         { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
480         { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }
481     };
482 
483     unsigned ruleSetIndex = 0;
484     unsigned w = FontWeight100Bit;
485     while (!(desiredTraitsMaskForComparison & (1 << w))) {
486         w++;
487         ruleSetIndex++;
488     }
489 
490     ASSERT(ruleSetIndex < fallbackRuleSets);
491     const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex];
492     for (unsigned i = 0; i < rulesPerSet; ++i) {
493         if (secondTraitsMask & weightFallbackRule[i])
494             return false;
495         if (firstTraitsMask & weightFallbackRule[i])
496             return true;
497     }
498 
499     return false;
500 }
501 
getFontData(const FontDescription & fontDescription,const AtomicString & familyName)502 FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
503 {
504     if (m_fontFaces.isEmpty()) {
505         if (familyName.startsWith("-webkit-"))
506             return fontDataForGenericFamily(m_document, fontDescription, familyName);
507         return 0;
508     }
509 
510     String family = familyName.string();
511 
512     Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(family);
513     // If no face was found, then return 0 and let the OS come up with its best match for the name.
514     if (!familyFontFaces || familyFontFaces->isEmpty()) {
515         // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our
516         // settings.
517         return fontDataForGenericFamily(m_document, fontDescription, familyName);
518     }
519 
520     HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >* segmentedFontFaceCache = m_fonts.get(family);
521     if (!segmentedFontFaceCache) {
522         segmentedFontFaceCache = new HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >;
523         m_fonts.set(family, segmentedFontFaceCache);
524     }
525 
526     FontTraitsMask traitsMask = fontDescription.traitsMask();
527 
528     RefPtr<CSSSegmentedFontFace> face = segmentedFontFaceCache->get(traitsMask);
529 
530     if (!face) {
531         face = CSSSegmentedFontFace::create(this);
532         segmentedFontFaceCache->set(traitsMask, face);
533         // Collect all matching faces and sort them in order of preference.
534         Vector<CSSFontFace*, 32> candidateFontFaces;
535         for (int i = familyFontFaces->size() - 1; i >= 0; --i) {
536             CSSFontFace* candidate = familyFontFaces->at(i).get();
537             unsigned candidateTraitsMask = candidate->traitsMask();
538             if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
539                 continue;
540             if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
541                 continue;
542 #if ENABLE(SVG_FONTS)
543             // For SVG Fonts that specify that they only support the "normal" variant, we will assume they are incapable
544             // of small-caps synthesis and just ignore the font face as a candidate.
545             if (candidate->hasSVGFontFaceSource() && (traitsMask & FontVariantSmallCapsMask) && !(candidateTraitsMask & FontVariantSmallCapsMask))
546                 continue;
547 #endif
548             candidateFontFaces.append(candidate);
549         }
550 
551         if (Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) {
552             unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size();
553             for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) {
554                 CSSFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get();
555                 unsigned candidateTraitsMask = candidate->traitsMask();
556                 if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
557                     continue;
558                 if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
559                     continue;
560                 candidateFontFaces.append(candidate);
561             }
562         }
563 
564         desiredTraitsMaskForComparison = traitsMask;
565         std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), compareFontFaces);
566         unsigned numCandidates = candidateFontFaces.size();
567         for (unsigned i = 0; i < numCandidates; ++i)
568             face->appendFontFace(candidateFontFaces[i]);
569     }
570 
571     // We have a face.  Ask it for a font data.  If it cannot produce one, it will fail, and the OS will take over.
572     return face->getFontData(fontDescription);
573 }
574 
575 }
576