Home | History | Annotate | Download | only in css
      1 /*
      2  * Copyright (C) 2007, 2008, 2011 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 "core/css/CSSFontSelector.h"
     29 
     30 #include "CSSPropertyNames.h"
     31 #include "CSSValueKeywords.h"
     32 #include "FontFamilyNames.h"
     33 #include "RuntimeEnabledFeatures.h"
     34 #include "core/css/CSSFontFace.h"
     35 #include "core/css/CSSFontFaceRule.h"
     36 #include "core/css/CSSFontFaceSource.h"
     37 #include "core/css/CSSFontFaceSrcValue.h"
     38 #include "core/css/CSSPrimitiveValue.h"
     39 #include "core/css/CSSSegmentedFontFace.h"
     40 #include "core/css/CSSUnicodeRangeValue.h"
     41 #include "core/css/CSSValueList.h"
     42 #include "core/css/StylePropertySet.h"
     43 #include "core/css/StyleRule.h"
     44 #include "core/css/resolver/StyleResolver.h"
     45 #include "core/dom/Document.h"
     46 #include "core/loader/FrameLoader.h"
     47 #include "core/loader/cache/FontResource.h"
     48 #include "core/loader/cache/ResourceFetcher.h"
     49 #include "core/page/Frame.h"
     50 #include "core/page/Settings.h"
     51 #include "core/platform/graphics/FontCache.h"
     52 #include "core/platform/graphics/SimpleFontData.h"
     53 #include "core/svg/SVGFontFaceElement.h"
     54 #include "wtf/text/AtomicString.h"
     55 
     56 using namespace std;
     57 
     58 namespace WebCore {
     59 
     60 CSSFontSelector::CSSFontSelector(Document* document)
     61     : m_document(document)
     62     , m_beginLoadingTimer(this, &CSSFontSelector::beginLoadTimerFired)
     63     , m_version(0)
     64 {
     65     // FIXME: An old comment used to say there was no need to hold a reference to m_document
     66     // because "we are guaranteed to be destroyed before the document". But there does not
     67     // seem to be any such guarantee.
     68 
     69     ASSERT(m_document);
     70     fontCache()->addClient(this);
     71 }
     72 
     73 CSSFontSelector::~CSSFontSelector()
     74 {
     75     clearDocument();
     76     fontCache()->removeClient(this);
     77 }
     78 
     79 bool CSSFontSelector::isEmpty() const
     80 {
     81     return m_fonts.isEmpty();
     82 }
     83 
     84 void CSSFontSelector::addFontFaceRule(const StyleRuleFontFace* fontFaceRule)
     85 {
     86     // Obtain the font-family property and the src property.  Both must be defined.
     87     const StylePropertySet* style = fontFaceRule->properties();
     88     RefPtr<CSSValue> fontFamily = style->getPropertyCSSValue(CSSPropertyFontFamily);
     89     RefPtr<CSSValue> src = style->getPropertyCSSValue(CSSPropertySrc);
     90     RefPtr<CSSValue> unicodeRange = style->getPropertyCSSValue(CSSPropertyUnicodeRange);
     91     if (!fontFamily || !src || !fontFamily->isValueList() || !src->isValueList() || (unicodeRange && !unicodeRange->isValueList()))
     92         return;
     93 
     94     // The font-family descriptor has to have exactly one family name.
     95     CSSValueList* familyList = toCSSValueList(fontFamily.get());
     96     if (familyList->length() != 1)
     97         return;
     98 
     99     CSSValueList* srcList = toCSSValueList(src.get());
    100     if (!srcList->length())
    101         return;
    102 
    103     CSSValueList* rangeList = toCSSValueList(unicodeRange.get());
    104 
    105     unsigned traitsMask = 0;
    106 
    107     if (RefPtr<CSSValue> fontStyle = style->getPropertyCSSValue(CSSPropertyFontStyle)) {
    108         if (!fontStyle->isPrimitiveValue())
    109             return;
    110 
    111         switch (toCSSPrimitiveValue(fontStyle.get())->getValueID()) {
    112         case CSSValueNormal:
    113             traitsMask |= FontStyleNormalMask;
    114             break;
    115         case CSSValueItalic:
    116         case CSSValueOblique:
    117             traitsMask |= FontStyleItalicMask;
    118             break;
    119         default:
    120             break;
    121         }
    122     } else
    123         traitsMask |= FontStyleNormalMask;
    124 
    125     if (RefPtr<CSSValue> fontWeight = style->getPropertyCSSValue(CSSPropertyFontWeight)) {
    126         if (!fontWeight->isPrimitiveValue())
    127             return;
    128 
    129         switch (toCSSPrimitiveValue(fontWeight.get())->getValueID()) {
    130         case CSSValueBold:
    131         case CSSValue700:
    132             traitsMask |= FontWeight700Mask;
    133             break;
    134         case CSSValueNormal:
    135         case CSSValue400:
    136             traitsMask |= FontWeight400Mask;
    137             break;
    138         case CSSValue900:
    139             traitsMask |= FontWeight900Mask;
    140             break;
    141         case CSSValue800:
    142             traitsMask |= FontWeight800Mask;
    143             break;
    144         case CSSValue600:
    145             traitsMask |= FontWeight600Mask;
    146             break;
    147         case CSSValue500:
    148             traitsMask |= FontWeight500Mask;
    149             break;
    150         case CSSValue300:
    151             traitsMask |= FontWeight300Mask;
    152             break;
    153         case CSSValue200:
    154             traitsMask |= FontWeight200Mask;
    155             break;
    156         case CSSValue100:
    157             traitsMask |= FontWeight100Mask;
    158             break;
    159         default:
    160             break;
    161         }
    162     } else
    163         traitsMask |= FontWeight400Mask;
    164 
    165     if (RefPtr<CSSValue> fontVariant = style->getPropertyCSSValue(CSSPropertyFontVariant)) {
    166         // font-variant descriptor can be a value list.
    167         if (fontVariant->isPrimitiveValue()) {
    168             RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
    169             list->append(fontVariant);
    170             fontVariant = list;
    171         } else if (!fontVariant->isValueList())
    172             return;
    173 
    174         CSSValueList* variantList = toCSSValueList(fontVariant.get());
    175         unsigned numVariants = variantList->length();
    176         if (!numVariants)
    177             return;
    178 
    179         for (unsigned i = 0; i < numVariants; ++i) {
    180             switch (toCSSPrimitiveValue(variantList->itemWithoutBoundsCheck(i))->getValueID()) {
    181                 case CSSValueNormal:
    182                     traitsMask |= FontVariantNormalMask;
    183                     break;
    184                 case CSSValueSmallCaps:
    185                     traitsMask |= FontVariantSmallCapsMask;
    186                     break;
    187                 default:
    188                     break;
    189             }
    190         }
    191     } else {
    192         traitsMask |= FontVariantNormalMask;
    193     }
    194 
    195     // Each item in the src property's list is a single CSSFontFaceSource. Put them all into a CSSFontFace.
    196     RefPtr<CSSFontFace> fontFace;
    197 
    198     int srcLength = srcList->length();
    199 
    200     bool foundSVGFont = false;
    201 
    202     for (int i = 0; i < srcLength; i++) {
    203         // An item in the list either specifies a string (local font name) or a URL (remote font to download).
    204         CSSFontFaceSrcValue* item = static_cast<CSSFontFaceSrcValue*>(srcList->itemWithoutBoundsCheck(i));
    205         OwnPtr<CSSFontFaceSource> source;
    206 
    207 #if ENABLE(SVG_FONTS)
    208         foundSVGFont = item->isSVGFontFaceSrc() || item->svgFontFaceElement();
    209 #endif
    210         if (!item->isLocal()) {
    211             Settings* settings = m_document ? m_document->frame() ? m_document->frame()->settings() : 0 : 0;
    212             bool allowDownloading = foundSVGFont || (settings && settings->downloadableBinaryFontsEnabled());
    213             if (allowDownloading && item->isSupportedFormat() && m_document) {
    214                 FontResource* fetched = item->fetch(m_document);
    215                 if (fetched) {
    216                     source = adoptPtr(new CSSFontFaceSource(item->resource(), fetched));
    217 #if ENABLE(SVG_FONTS)
    218                     if (foundSVGFont)
    219                         source->setHasExternalSVGFont(true);
    220 #endif
    221                 }
    222             }
    223         } else {
    224             source = adoptPtr(new CSSFontFaceSource(item->resource()));
    225         }
    226 
    227         if (!fontFace) {
    228             RefPtr<CSSFontFaceRule> rule;
    229             // FIXME: https://bugs.webkit.org/show_bug.cgi?id=112116 - This CSSFontFaceRule has no parent.
    230             if (RuntimeEnabledFeatures::fontLoadEventsEnabled())
    231                 rule = static_pointer_cast<CSSFontFaceRule>(fontFaceRule->createCSSOMWrapper());
    232             fontFace = CSSFontFace::create(static_cast<FontTraitsMask>(traitsMask), rule);
    233         }
    234 
    235         if (source) {
    236 #if ENABLE(SVG_FONTS)
    237             source->setSVGFontFaceElement(item->svgFontFaceElement());
    238 #endif
    239             fontFace->addSource(source.release());
    240         }
    241     }
    242 
    243     ASSERT(fontFace);
    244 
    245     if (fontFace && !fontFace->isValid())
    246         return;
    247 
    248     if (rangeList) {
    249         unsigned numRanges = rangeList->length();
    250         for (unsigned i = 0; i < numRanges; i++) {
    251             CSSUnicodeRangeValue* range = static_cast<CSSUnicodeRangeValue*>(rangeList->itemWithoutBoundsCheck(i));
    252             fontFace->addRange(range->from(), range->to());
    253         }
    254     }
    255 
    256     CSSPrimitiveValue* familyValue = toCSSPrimitiveValue(familyList->itemWithoutBoundsCheck(0));
    257     String familyName;
    258     if (familyValue->isString()) {
    259         familyName = familyValue->getStringValue();
    260     } else if (familyValue->isValueID()) {
    261         // We need to use the raw text for all the generic family types, since @font-face is a way of actually
    262         // defining what font to use for those types.
    263         switch (familyValue->getValueID()) {
    264         case CSSValueSerif:
    265             familyName =  serifFamily;
    266             break;
    267         case CSSValueSansSerif:
    268             familyName =  sansSerifFamily;
    269             break;
    270         case CSSValueCursive:
    271             familyName =  cursiveFamily;
    272             break;
    273         case CSSValueFantasy:
    274             familyName =  fantasyFamily;
    275             break;
    276         case CSSValueMonospace:
    277             familyName =  monospaceFamily;
    278             break;
    279         case CSSValueWebkitPictograph:
    280             familyName =  pictographFamily;
    281             break;
    282         default:
    283             break;
    284         }
    285     }
    286 
    287     if (familyName.isEmpty())
    288         return;
    289 
    290     OwnPtr<Vector<RefPtr<CSSFontFace> > >& familyFontFaces = m_fontFaces.add(familyName, nullptr).iterator->value;
    291     if (!familyFontFaces) {
    292         familyFontFaces = adoptPtr(new Vector<RefPtr<CSSFontFace> >);
    293 
    294         ASSERT(!m_locallyInstalledFontFaces.contains(familyName));
    295 
    296         Vector<unsigned> locallyInstalledFontsTraitsMasks;
    297         fontCache()->getTraitsInFamily(familyName, locallyInstalledFontsTraitsMasks);
    298         if (unsigned numLocallyInstalledFaces = locallyInstalledFontsTraitsMasks.size()) {
    299             OwnPtr<Vector<RefPtr<CSSFontFace> > > familyLocallyInstalledFaces = adoptPtr(new Vector<RefPtr<CSSFontFace> >);
    300 
    301             for (unsigned i = 0; i < numLocallyInstalledFaces; ++i) {
    302                 RefPtr<CSSFontFace> locallyInstalledFontFace = CSSFontFace::create(static_cast<FontTraitsMask>(locallyInstalledFontsTraitsMasks[i]), 0, true);
    303                 locallyInstalledFontFace->addSource(adoptPtr(new CSSFontFaceSource(familyName)));
    304                 ASSERT(locallyInstalledFontFace->isValid());
    305                 familyLocallyInstalledFaces->append(locallyInstalledFontFace);
    306             }
    307 
    308             m_locallyInstalledFontFaces.set(familyName, familyLocallyInstalledFaces.release());
    309         }
    310     }
    311 
    312     familyFontFaces->append(fontFace);
    313 
    314     ++m_version;
    315 }
    316 
    317 void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient* client)
    318 {
    319     m_clients.add(client);
    320 }
    321 
    322 void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient* client)
    323 {
    324     m_clients.remove(client);
    325 }
    326 
    327 void CSSFontSelector::dispatchInvalidationCallbacks()
    328 {
    329     Vector<FontSelectorClient*> clients;
    330     copyToVector(m_clients, clients);
    331     for (size_t i = 0; i < clients.size(); ++i)
    332         clients[i]->fontsNeedUpdate(this);
    333 
    334     // FIXME: Make Document a FontSelectorClient so that it can simply register for invalidation callbacks.
    335     if (!m_document)
    336         return;
    337     if (StyleResolver* styleResolver = m_document->styleResolverIfExists())
    338         styleResolver->invalidateMatchedPropertiesCache();
    339     if (!m_document->renderer())
    340         return;
    341     m_document->setNeedsStyleRecalc();
    342 }
    343 
    344 void CSSFontSelector::fontLoaded()
    345 {
    346     dispatchInvalidationCallbacks();
    347 }
    348 
    349 void CSSFontSelector::fontCacheInvalidated()
    350 {
    351     dispatchInvalidationCallbacks();
    352 }
    353 
    354 static PassRefPtr<FontData> fontDataForGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName)
    355 {
    356     if (!document || !document->frame())
    357         return 0;
    358 
    359     const Settings* settings = document->frame()->settings();
    360     if (!settings)
    361         return 0;
    362 
    363     AtomicString genericFamily;
    364     UScriptCode script = fontDescription.script();
    365 
    366 #if OS(ANDROID)
    367     genericFamily = FontCache::getGenericFamilyNameForScript(familyName, script);
    368 #else
    369     if (familyName == serifFamily)
    370          genericFamily = settings->serifFontFamily(script);
    371     else if (familyName == sansSerifFamily)
    372          genericFamily = settings->sansSerifFontFamily(script);
    373     else if (familyName == cursiveFamily)
    374          genericFamily = settings->cursiveFontFamily(script);
    375     else if (familyName == fantasyFamily)
    376          genericFamily = settings->fantasyFontFamily(script);
    377     else if (familyName == monospaceFamily)
    378          genericFamily = settings->fixedFontFamily(script);
    379     else if (familyName == pictographFamily)
    380          genericFamily = settings->pictographFontFamily(script);
    381     else if (familyName == standardFamily)
    382          genericFamily = settings->standardFontFamily(script);
    383 #endif
    384 
    385     if (!genericFamily.isEmpty())
    386         return fontCache()->getFontResourceData(fontDescription, genericFamily);
    387 
    388     return 0;
    389 }
    390 
    391 static FontTraitsMask desiredTraitsMaskForComparison;
    392 
    393 static inline bool compareFontFaces(CSSFontFace* first, CSSFontFace* second)
    394 {
    395     FontTraitsMask firstTraitsMask = first->traitsMask();
    396     FontTraitsMask secondTraitsMask = second->traitsMask();
    397 
    398     bool firstHasDesiredVariant = firstTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
    399     bool secondHasDesiredVariant = secondTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
    400 
    401     if (firstHasDesiredVariant != secondHasDesiredVariant)
    402         return firstHasDesiredVariant;
    403 
    404     // We need to check font-variant css property for CSS2.1 compatibility.
    405     if ((desiredTraitsMaskForComparison & FontVariantSmallCapsMask) && !first->isLocalFallback() && !second->isLocalFallback()) {
    406         // Prefer a font that has indicated that it can only support small-caps to a font that claims to support
    407         // all variants.  The specialized font is more likely to be true small-caps and not require synthesis.
    408         bool firstRequiresSmallCaps = (firstTraitsMask & FontVariantSmallCapsMask) && !(firstTraitsMask & FontVariantNormalMask);
    409         bool secondRequiresSmallCaps = (secondTraitsMask & FontVariantSmallCapsMask) && !(secondTraitsMask & FontVariantNormalMask);
    410         if (firstRequiresSmallCaps != secondRequiresSmallCaps)
    411             return firstRequiresSmallCaps;
    412     }
    413 
    414     bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
    415     bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
    416 
    417     if (firstHasDesiredStyle != secondHasDesiredStyle)
    418         return firstHasDesiredStyle;
    419 
    420     if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first->isLocalFallback() && !second->isLocalFallback()) {
    421         // Prefer a font that has indicated that it can only support italics to a font that claims to support
    422         // all styles.  The specialized font is more likely to be the one the author wants used.
    423         bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask);
    424         bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask);
    425         if (firstRequiresItalics != secondRequiresItalics)
    426             return firstRequiresItalics;
    427     }
    428 
    429     if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
    430         return false;
    431     if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
    432         return true;
    433 
    434     // http://www.w3.org/TR/2011/WD-css3-fonts-20111004/#font-matching-algorithm says :
    435     //   - If the desired weight is less than 400, weights below the desired weight are checked in descending order followed by weights above the desired weight in ascending order until a match is found.
    436     //   - If the desired weight is greater than 500, weights above the desired weight are checked in ascending order followed by weights below the desired weight in descending order until a match is found.
    437     //   - If the desired weight is 400, 500 is checked first and then the rule for desired weights less than 400 is used.
    438     //   - If the desired weight is 500, 400 is checked first and then the rule for desired weights less than 400 is used.
    439 
    440     static const unsigned fallbackRuleSets = 9;
    441     static const unsigned rulesPerSet = 8;
    442     static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = {
    443         { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
    444         { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
    445         { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
    446         { FontWeight500Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
    447         { FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
    448         { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
    449         { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
    450         { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
    451         { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }
    452     };
    453 
    454     unsigned ruleSetIndex = 0;
    455     unsigned w = FontWeight100Bit;
    456     while (!(desiredTraitsMaskForComparison & (1 << w))) {
    457         w++;
    458         ruleSetIndex++;
    459     }
    460 
    461     ASSERT(ruleSetIndex < fallbackRuleSets);
    462     const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex];
    463     for (unsigned i = 0; i < rulesPerSet; ++i) {
    464         if (secondTraitsMask & weightFallbackRule[i])
    465             return false;
    466         if (firstTraitsMask & weightFallbackRule[i])
    467             return true;
    468     }
    469 
    470     return false;
    471 }
    472 
    473 PassRefPtr<FontData> CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
    474 {
    475     if (m_fontFaces.isEmpty()) {
    476         if (familyName.startsWith("-webkit-"))
    477             return fontDataForGenericFamily(m_document, fontDescription, familyName);
    478         if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont())
    479             return fontDataForGenericFamily(m_document, fontDescription, "-webkit-standard");
    480         return 0;
    481     }
    482 
    483     CSSSegmentedFontFace* face = getFontFace(fontDescription, familyName);
    484     // If no face was found, then return 0 and let the OS come up with its best match for the name.
    485     if (!face) {
    486         // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our
    487         // settings.
    488         if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont())
    489             return fontDataForGenericFamily(m_document, fontDescription, "-webkit-standard");
    490         return fontDataForGenericFamily(m_document, fontDescription, familyName);
    491     }
    492 
    493     // We have a face. Ask it for a font data. If it cannot produce one, it will fail, and the OS will take over.
    494     return face->getFontData(fontDescription);
    495 }
    496 
    497 CSSSegmentedFontFace* CSSFontSelector::getFontFace(const FontDescription& fontDescription, const AtomicString& family)
    498 {
    499     Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(family);
    500     if (!familyFontFaces || familyFontFaces->isEmpty())
    501         return 0;
    502 
    503     OwnPtr<HashMap<unsigned, RefPtr<CSSSegmentedFontFace> > >& segmentedFontFaceCache = m_fonts.add(family, nullptr).iterator->value;
    504     if (!segmentedFontFaceCache)
    505         segmentedFontFaceCache = adoptPtr(new HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >);
    506 
    507     FontTraitsMask traitsMask = fontDescription.traitsMask();
    508 
    509     RefPtr<CSSSegmentedFontFace>& face = segmentedFontFaceCache->add(traitsMask, 0).iterator->value;
    510     if (!face) {
    511         face = CSSSegmentedFontFace::create(this);
    512 
    513         // Collect all matching faces and sort them in order of preference.
    514         Vector<CSSFontFace*, 32> candidateFontFaces;
    515         for (int i = familyFontFaces->size() - 1; i >= 0; --i) {
    516             CSSFontFace* candidate = familyFontFaces->at(i).get();
    517             unsigned candidateTraitsMask = candidate->traitsMask();
    518             if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
    519                 continue;
    520             if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
    521                 continue;
    522 #if ENABLE(SVG_FONTS)
    523             // For SVG Fonts that specify that they only support the "normal" variant, we will assume they are incapable
    524             // of small-caps synthesis and just ignore the font face as a candidate.
    525             if (candidate->hasSVGFontFaceSource() && (traitsMask & FontVariantSmallCapsMask) && !(candidateTraitsMask & FontVariantSmallCapsMask))
    526                 continue;
    527 #endif
    528             candidateFontFaces.append(candidate);
    529         }
    530 
    531         if (Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) {
    532             unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size();
    533             for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) {
    534                 CSSFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get();
    535                 unsigned candidateTraitsMask = candidate->traitsMask();
    536                 if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
    537                     continue;
    538                 if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
    539                     continue;
    540                 candidateFontFaces.append(candidate);
    541             }
    542         }
    543 
    544         desiredTraitsMaskForComparison = traitsMask;
    545         stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), compareFontFaces);
    546         unsigned numCandidates = candidateFontFaces.size();
    547         for (unsigned i = 0; i < numCandidates; ++i)
    548             face->appendFontFace(candidateFontFaces[i]);
    549     }
    550     return face.get();
    551 }
    552 
    553 void CSSFontSelector::clearDocument()
    554 {
    555     if (!m_document) {
    556         ASSERT(!m_beginLoadingTimer.isActive());
    557         ASSERT(m_fontsToBeginLoading.isEmpty());
    558         return;
    559     }
    560 
    561     m_beginLoadingTimer.stop();
    562 
    563     ResourceFetcher* fetcher = m_document->fetcher();
    564     for (size_t i = 0; i < m_fontsToBeginLoading.size(); ++i) {
    565         // Balances incrementRequestCount() in beginLoadingFontSoon().
    566         fetcher->decrementRequestCount(m_fontsToBeginLoading[i].get());
    567     }
    568 
    569     m_fontsToBeginLoading.clear();
    570 
    571     m_document = 0;
    572 }
    573 
    574 void CSSFontSelector::beginLoadingFontSoon(FontResource* font)
    575 {
    576     if (!m_document)
    577         return;
    578 
    579     m_fontsToBeginLoading.append(font);
    580     // Increment the request count now, in order to prevent didFinishLoad from being dispatched
    581     // after this font has been requested but before it began loading. Balanced by
    582     // decrementRequestCount() in beginLoadTimerFired() and in clearDocument().
    583     m_document->fetcher()->incrementRequestCount(font);
    584     m_beginLoadingTimer.startOneShot(0);
    585 }
    586 
    587 void CSSFontSelector::beginLoadTimerFired(Timer<WebCore::CSSFontSelector>*)
    588 {
    589     Vector<ResourcePtr<FontResource> > fontsToBeginLoading;
    590     fontsToBeginLoading.swap(m_fontsToBeginLoading);
    591 
    592     // CSSFontSelector could get deleted via beginLoadIfNeeded() or loadDone() unless protected.
    593     RefPtr<CSSFontSelector> protect(this);
    594 
    595     ResourceFetcher* fetcher = m_document->fetcher();
    596     for (size_t i = 0; i < fontsToBeginLoading.size(); ++i) {
    597         fontsToBeginLoading[i]->beginLoadIfNeeded(fetcher);
    598         // Balances incrementRequestCount() in beginLoadingFontSoon().
    599         fetcher->decrementRequestCount(fontsToBeginLoading[i].get());
    600     }
    601     // Ensure that if the request count reaches zero, the frame loader will know about it.
    602     fetcher->didLoadResource(0);
    603     // New font loads may be triggered by layout after the document load is complete but before we have dispatched
    604     // didFinishLoading for the frame. Make sure the delegate is always dispatched by checking explicitly.
    605     if (m_document && m_document->frame())
    606         m_document->frame()->loader()->checkLoadComplete();
    607 }
    608 
    609 }
    610