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