Home | History | Annotate | Download | only in css
      1 /*
      2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
      3  *           (C) 2007, 2008 Nikolas Zimmermann <zimmermann (at) 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 
     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 
     70 CSSFontSelector::~CSSFontSelector()
     71 {
     72     fontCache()->removeClient(this);
     73     deleteAllValues(m_fontFaces);
     74     deleteAllValues(m_locallyInstalledFontFaces);
     75     deleteAllValues(m_fonts);
     76 }
     77 
     78 bool CSSFontSelector::isEmpty() const
     79 {
     80     return m_fonts.isEmpty();
     81 }
     82 
     83 CachedResourceLoader* CSSFontSelector::cachedResourceLoader() const
     84 {
     85     return m_document ? m_document->cachedResourceLoader() : 0;
     86 }
     87 
     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 
    348 void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient* client)
    349 {
    350     m_clients.add(client);
    351 }
    352 
    353 void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient* client)
    354 {
    355     m_clients.remove(client);
    356 }
    357 
    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 
    371 void CSSFontSelector::fontLoaded()
    372 {
    373     dispatchInvalidationCallbacks();
    374 }
    375 
    376 void CSSFontSelector::fontCacheInvalidated()
    377 {
    378     dispatchInvalidationCallbacks();
    379 }
    380 
    381 static FontData* fontDataForGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName)
    382 {
    383     if (!document || !document->frame())
    384         return 0;
    385 
    386     const Settings* settings = document->frame()->settings();
    387     if (!settings)
    388         return 0;
    389 
    390     AtomicString genericFamily;
    391     if (familyName == "-webkit-serif")
    392         genericFamily = settings->serifFontFamily();
    393     else if (familyName == "-webkit-sans-serif")
    394         genericFamily = settings->sansSerifFontFamily();
    395     else if (familyName == "-webkit-cursive")
    396         genericFamily = settings->cursiveFontFamily();
    397     else if (familyName == "-webkit-fantasy")
    398         genericFamily = settings->fantasyFontFamily();
    399     else if (familyName == "-webkit-monospace")
    400         genericFamily = settings->fixedFontFamily();
    401     else if (familyName == "-webkit-standard")
    402         genericFamily = settings->standardFontFamily();
    403 
    404     if (!genericFamily.isEmpty())
    405         return fontCache()->getCachedFontData(fontDescription, genericFamily);
    406 
    407     return 0;
    408 }
    409 
    410 static FontTraitsMask desiredTraitsMaskForComparison;
    411 
    412 static inline bool compareFontFaces(CSSFontFace* first, CSSFontFace* second)
    413 {
    414     FontTraitsMask firstTraitsMask = first->traitsMask();
    415     FontTraitsMask secondTraitsMask = second->traitsMask();
    416 
    417     bool firstHasDesiredVariant = firstTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
    418     bool secondHasDesiredVariant = secondTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
    419 
    420     if (firstHasDesiredVariant != secondHasDesiredVariant)
    421         return firstHasDesiredVariant;
    422 
    423     if ((desiredTraitsMaskForComparison & FontVariantSmallCapsMask) && !first->isLocalFallback() && !second->isLocalFallback()) {
    424         // Prefer a font that has indicated that it can only support small-caps to a font that claims to support
    425         // all variants.  The specialized font is more likely to be true small-caps and not require synthesis.
    426         bool firstRequiresSmallCaps = (firstTraitsMask & FontVariantSmallCapsMask) && !(firstTraitsMask & FontVariantNormalMask);
    427         bool secondRequiresSmallCaps = (secondTraitsMask & FontVariantSmallCapsMask) && !(secondTraitsMask & FontVariantNormalMask);
    428         if (firstRequiresSmallCaps != secondRequiresSmallCaps)
    429             return firstRequiresSmallCaps;
    430     }
    431 
    432     bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
    433     bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
    434 
    435     if (firstHasDesiredStyle != secondHasDesiredStyle)
    436         return firstHasDesiredStyle;
    437 
    438     if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first->isLocalFallback() && !second->isLocalFallback()) {
    439         // Prefer a font that has indicated that it can only support italics to a font that claims to support
    440         // all styles.  The specialized font is more likely to be the one the author wants used.
    441         bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask);
    442         bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask);
    443         if (firstRequiresItalics != secondRequiresItalics)
    444             return firstRequiresItalics;
    445     }
    446 
    447     if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
    448         return false;
    449     if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
    450         return true;
    451 
    452     // 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
    453     // 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',
    454     // '700', '800', or '900' remains unassigned, they are assigned to the same face as the next darker assigned keyword, if any, or the next
    455     // lighter one otherwise. If any of '300', '200', or '100' remains unassigned, it is assigned to the next lighter assigned keyword, if any,
    456     // or the next darker otherwise."
    457     // For '400', we made up our own rule (which then '500' follows).
    458 
    459     static const unsigned fallbackRuleSets = 9;
    460     static const unsigned rulesPerSet = 8;
    461     static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = {
    462         { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
    463         { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
    464         { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
    465         { FontWeight500Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask },
    466         { FontWeight400Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask },
    467         { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
    468         { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
    469         { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
    470         { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }
    471     };
    472 
    473     unsigned ruleSetIndex = 0;
    474     unsigned w = FontWeight100Bit;
    475     while (!(desiredTraitsMaskForComparison & (1 << w))) {
    476         w++;
    477         ruleSetIndex++;
    478     }
    479 
    480     ASSERT(ruleSetIndex < fallbackRuleSets);
    481     const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex];
    482     for (unsigned i = 0; i < rulesPerSet; ++i) {
    483         if (secondTraitsMask & weightFallbackRule[i])
    484             return false;
    485         if (firstTraitsMask & weightFallbackRule[i])
    486             return true;
    487     }
    488 
    489     return false;
    490 }
    491 
    492 FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
    493 {
    494     if (m_fontFaces.isEmpty()) {
    495         if (familyName.startsWith("-webkit-"))
    496             return fontDataForGenericFamily(m_document, fontDescription, familyName);
    497         return 0;
    498     }
    499 
    500     String family = familyName.string();
    501 
    502     Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(family);
    503     // If no face was found, then return 0 and let the OS come up with its best match for the name.
    504     if (!familyFontFaces || familyFontFaces->isEmpty()) {
    505         // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our
    506         // settings.
    507         return fontDataForGenericFamily(m_document, fontDescription, familyName);
    508     }
    509 
    510     HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >* segmentedFontFaceCache = m_fonts.get(family);
    511     if (!segmentedFontFaceCache) {
    512         segmentedFontFaceCache = new HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >;
    513         m_fonts.set(family, segmentedFontFaceCache);
    514     }
    515 
    516     FontTraitsMask traitsMask = fontDescription.traitsMask();
    517 
    518     RefPtr<CSSSegmentedFontFace> face = segmentedFontFaceCache->get(traitsMask);
    519 
    520     if (!face) {
    521         face = CSSSegmentedFontFace::create(this);
    522         segmentedFontFaceCache->set(traitsMask, face);
    523         // Collect all matching faces and sort them in order of preference.
    524         Vector<CSSFontFace*, 32> candidateFontFaces;
    525         for (int i = familyFontFaces->size() - 1; i >= 0; --i) {
    526             CSSFontFace* candidate = familyFontFaces->at(i).get();
    527             unsigned candidateTraitsMask = candidate->traitsMask();
    528             if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
    529                 continue;
    530             if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
    531                 continue;
    532 #if ENABLE(SVG_FONTS)
    533             // For SVG Fonts that specify that they only support the "normal" variant, we will assume they are incapable
    534             // of small-caps synthesis and just ignore the font face as a candidate.
    535             if (candidate->hasSVGFontFaceSource() && (traitsMask & FontVariantSmallCapsMask) && !(candidateTraitsMask & FontVariantSmallCapsMask))
    536                 continue;
    537 #endif
    538             candidateFontFaces.append(candidate);
    539         }
    540 
    541         if (Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) {
    542             unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size();
    543             for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) {
    544                 CSSFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get();
    545                 unsigned candidateTraitsMask = candidate->traitsMask();
    546                 if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
    547                     continue;
    548                 if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
    549                     continue;
    550                 candidateFontFaces.append(candidate);
    551             }
    552         }
    553 
    554         desiredTraitsMaskForComparison = traitsMask;
    555         std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), compareFontFaces);
    556         unsigned numCandidates = candidateFontFaces.size();
    557         for (unsigned i = 0; i < numCandidates; ++i)
    558             face->appendFontFace(candidateFontFaces[i]);
    559     }
    560 
    561     // We have a face.  Ask it for a font data.  If it cannot produce one, it will fail, and the OS will take over.
    562     return face->getFontData(fontDescription);
    563 }
    564 
    565 }
    566