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 "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
56using namespace std;
57
58namespace WebCore {
59
60CSSFontSelector::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
73CSSFontSelector::~CSSFontSelector()
74{
75    clearDocument();
76    fontCache()->removeClient(this);
77}
78
79bool CSSFontSelector::isEmpty() const
80{
81    return m_fonts.isEmpty();
82}
83
84void 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
317void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient* client)
318{
319    m_clients.add(client);
320}
321
322void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient* client)
323{
324    m_clients.remove(client);
325}
326
327void 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
344void CSSFontSelector::fontLoaded()
345{
346    dispatchInvalidationCallbacks();
347}
348
349void CSSFontSelector::fontCacheInvalidated()
350{
351    dispatchInvalidationCallbacks();
352}
353
354static 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
391static FontTraitsMask desiredTraitsMaskForComparison;
392
393static 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
473PassRefPtr<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
497CSSSegmentedFontFace* 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
553void 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
574void 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
587void 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