1/*
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 *           (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "CSSFontSelector.h"
29
30#include "CachedFont.h"
31#include "CSSFontFace.h"
32#include "CSSFontFaceRule.h"
33#include "CSSFontFaceSource.h"
34#include "CSSFontFaceSrcValue.h"
35#include "CSSMutableStyleDeclaration.h"
36#include "CSSPrimitiveValue.h"
37#include "CSSPropertyNames.h"
38#include "CSSSegmentedFontFace.h"
39#include "CSSUnicodeRangeValue.h"
40#include "CSSValueKeywords.h"
41#include "CSSValueList.h"
42#include "CachedResourceLoader.h"
43#include "Document.h"
44#include "FontCache.h"
45#include "FontFamilyValue.h"
46#include "Frame.h"
47#include "RenderObject.h"
48#include "Settings.h"
49#include "SimpleFontData.h"
50#include <wtf/text/AtomicString.h>
51
52#if ENABLE(SVG)
53#include "SVGFontFaceElement.h"
54#include "SVGNames.h"
55#endif
56
57namespace WebCore {
58
59CSSFontSelector::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
70CSSFontSelector::~CSSFontSelector()
71{
72    fontCache()->removeClient(this);
73    deleteAllValues(m_fontFaces);
74    deleteAllValues(m_locallyInstalledFontFaces);
75    deleteAllValues(m_fonts);
76}
77
78bool CSSFontSelector::isEmpty() const
79{
80    return m_fonts.isEmpty();
81}
82
83CachedResourceLoader* CSSFontSelector::cachedResourceLoader() const
84{
85    return m_document ? m_document->cachedResourceLoader() : 0;
86}
87
88void 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
348void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient* client)
349{
350    m_clients.add(client);
351}
352
353void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient* client)
354{
355    m_clients.remove(client);
356}
357
358void 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
371void CSSFontSelector::fontLoaded()
372{
373    dispatchInvalidationCallbacks();
374}
375
376void CSSFontSelector::fontCacheInvalidated()
377{
378    dispatchInvalidationCallbacks();
379}
380
381void CSSFontSelector::retireCustomFont(FontData* fontData)
382{
383    if (m_document)
384        m_document->retireCustomFont(fontData);
385    else {
386        GlyphPageTreeNode::pruneTreeCustomFontData(fontData);
387        delete fontData;
388    }
389}
390
391static FontData* fontDataForGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName)
392{
393    if (!document || !document->frame())
394        return 0;
395
396    const Settings* settings = document->frame()->settings();
397    if (!settings)
398        return 0;
399
400    AtomicString genericFamily;
401    if (familyName == "-webkit-serif")
402        genericFamily = settings->serifFontFamily();
403    else if (familyName == "-webkit-sans-serif")
404        genericFamily = settings->sansSerifFontFamily();
405    else if (familyName == "-webkit-cursive")
406        genericFamily = settings->cursiveFontFamily();
407    else if (familyName == "-webkit-fantasy")
408        genericFamily = settings->fantasyFontFamily();
409    else if (familyName == "-webkit-monospace")
410        genericFamily = settings->fixedFontFamily();
411    else if (familyName == "-webkit-standard")
412        genericFamily = settings->standardFontFamily();
413
414    if (!genericFamily.isEmpty())
415        return fontCache()->getCachedFontData(fontDescription, genericFamily);
416
417    return 0;
418}
419
420static FontTraitsMask desiredTraitsMaskForComparison;
421
422static inline bool compareFontFaces(CSSFontFace* first, CSSFontFace* second)
423{
424    FontTraitsMask firstTraitsMask = first->traitsMask();
425    FontTraitsMask secondTraitsMask = second->traitsMask();
426
427    bool firstHasDesiredVariant = firstTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
428    bool secondHasDesiredVariant = secondTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
429
430    if (firstHasDesiredVariant != secondHasDesiredVariant)
431        return firstHasDesiredVariant;
432
433    if ((desiredTraitsMaskForComparison & FontVariantSmallCapsMask) && !first->isLocalFallback() && !second->isLocalFallback()) {
434        // Prefer a font that has indicated that it can only support small-caps to a font that claims to support
435        // all variants.  The specialized font is more likely to be true small-caps and not require synthesis.
436        bool firstRequiresSmallCaps = (firstTraitsMask & FontVariantSmallCapsMask) && !(firstTraitsMask & FontVariantNormalMask);
437        bool secondRequiresSmallCaps = (secondTraitsMask & FontVariantSmallCapsMask) && !(secondTraitsMask & FontVariantNormalMask);
438        if (firstRequiresSmallCaps != secondRequiresSmallCaps)
439            return firstRequiresSmallCaps;
440    }
441
442    bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
443    bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
444
445    if (firstHasDesiredStyle != secondHasDesiredStyle)
446        return firstHasDesiredStyle;
447
448    if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first->isLocalFallback() && !second->isLocalFallback()) {
449        // Prefer a font that has indicated that it can only support italics to a font that claims to support
450        // all styles.  The specialized font is more likely to be the one the author wants used.
451        bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask);
452        bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask);
453        if (firstRequiresItalics != secondRequiresItalics)
454            return firstRequiresItalics;
455    }
456
457    if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
458        return false;
459    if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
460        return true;
461
462    // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#q46 says: "If there are fewer then 9 weights in the family, the default algorithm
463    // for filling the "holes" is as follows. If '500' is unassigned, it will be assigned the same font as '400'. If any of the values '600',
464    // '700', '800', or '900' remains unassigned, they are assigned to the same face as the next darker assigned keyword, if any, or the next
465    // lighter one otherwise. If any of '300', '200', or '100' remains unassigned, it is assigned to the next lighter assigned keyword, if any,
466    // or the next darker otherwise."
467    // For '400', we made up our own rule (which then '500' follows).
468
469    static const unsigned fallbackRuleSets = 9;
470    static const unsigned rulesPerSet = 8;
471    static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = {
472        { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
473        { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
474        { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
475        { FontWeight500Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask },
476        { FontWeight400Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask },
477        { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
478        { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
479        { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
480        { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }
481    };
482
483    unsigned ruleSetIndex = 0;
484    unsigned w = FontWeight100Bit;
485    while (!(desiredTraitsMaskForComparison & (1 << w))) {
486        w++;
487        ruleSetIndex++;
488    }
489
490    ASSERT(ruleSetIndex < fallbackRuleSets);
491    const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex];
492    for (unsigned i = 0; i < rulesPerSet; ++i) {
493        if (secondTraitsMask & weightFallbackRule[i])
494            return false;
495        if (firstTraitsMask & weightFallbackRule[i])
496            return true;
497    }
498
499    return false;
500}
501
502FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
503{
504    if (m_fontFaces.isEmpty()) {
505        if (familyName.startsWith("-webkit-"))
506            return fontDataForGenericFamily(m_document, fontDescription, familyName);
507        return 0;
508    }
509
510    String family = familyName.string();
511
512    Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(family);
513    // If no face was found, then return 0 and let the OS come up with its best match for the name.
514    if (!familyFontFaces || familyFontFaces->isEmpty()) {
515        // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our
516        // settings.
517        return fontDataForGenericFamily(m_document, fontDescription, familyName);
518    }
519
520    HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >* segmentedFontFaceCache = m_fonts.get(family);
521    if (!segmentedFontFaceCache) {
522        segmentedFontFaceCache = new HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >;
523        m_fonts.set(family, segmentedFontFaceCache);
524    }
525
526    FontTraitsMask traitsMask = fontDescription.traitsMask();
527
528    RefPtr<CSSSegmentedFontFace> face = segmentedFontFaceCache->get(traitsMask);
529
530    if (!face) {
531        face = CSSSegmentedFontFace::create(this);
532        segmentedFontFaceCache->set(traitsMask, face);
533        // Collect all matching faces and sort them in order of preference.
534        Vector<CSSFontFace*, 32> candidateFontFaces;
535        for (int i = familyFontFaces->size() - 1; i >= 0; --i) {
536            CSSFontFace* candidate = familyFontFaces->at(i).get();
537            unsigned candidateTraitsMask = candidate->traitsMask();
538            if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
539                continue;
540            if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
541                continue;
542#if ENABLE(SVG_FONTS)
543            // For SVG Fonts that specify that they only support the "normal" variant, we will assume they are incapable
544            // of small-caps synthesis and just ignore the font face as a candidate.
545            if (candidate->hasSVGFontFaceSource() && (traitsMask & FontVariantSmallCapsMask) && !(candidateTraitsMask & FontVariantSmallCapsMask))
546                continue;
547#endif
548            candidateFontFaces.append(candidate);
549        }
550
551        if (Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) {
552            unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size();
553            for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) {
554                CSSFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get();
555                unsigned candidateTraitsMask = candidate->traitsMask();
556                if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
557                    continue;
558                if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
559                    continue;
560                candidateFontFaces.append(candidate);
561            }
562        }
563
564        desiredTraitsMaskForComparison = traitsMask;
565        std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), compareFontFaces);
566        unsigned numCandidates = candidateFontFaces.size();
567        for (unsigned i = 0; i < numCandidates; ++i)
568            face->appendFontFace(candidateFontFaces[i]);
569    }
570
571    // We have a face.  Ask it for a font data.  If it cannot produce one, it will fail, and the OS will take over.
572    return face->getFontData(fontDescription);
573}
574
575}
576