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
57 namespace WebCore {
58
CSSFontSelector(Document * document)59 CSSFontSelector::CSSFontSelector(Document* document)
60 : m_document(document)
61 {
62 // FIXME: An old comment used to say there was no need to hold a reference to m_document
63 // because "we are guaranteed to be destroyed before the document". But there does not
64 // seem to be any such guarantee.
65
66 ASSERT(m_document);
67 fontCache()->addClient(this);
68 }
69
~CSSFontSelector()70 CSSFontSelector::~CSSFontSelector()
71 {
72 fontCache()->removeClient(this);
73 deleteAllValues(m_fontFaces);
74 deleteAllValues(m_locallyInstalledFontFaces);
75 deleteAllValues(m_fonts);
76 }
77
isEmpty() const78 bool CSSFontSelector::isEmpty() const
79 {
80 return m_fonts.isEmpty();
81 }
82
cachedResourceLoader() const83 CachedResourceLoader* CSSFontSelector::cachedResourceLoader() const
84 {
85 return m_document ? m_document->cachedResourceLoader() : 0;
86 }
87
addFontFaceRule(const CSSFontFaceRule * fontFaceRule)88 void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
89 {
90 // Obtain the font-family property and the src property. Both must be defined.
91 const CSSMutableStyleDeclaration* style = fontFaceRule->style();
92 RefPtr<CSSValue> fontFamily = style->getPropertyCSSValue(CSSPropertyFontFamily);
93 RefPtr<CSSValue> src = style->getPropertyCSSValue(CSSPropertySrc);
94 RefPtr<CSSValue> unicodeRange = style->getPropertyCSSValue(CSSPropertyUnicodeRange);
95 if (!fontFamily || !src || !fontFamily->isValueList() || !src->isValueList() || (unicodeRange && !unicodeRange->isValueList()))
96 return;
97
98 CSSValueList* familyList = static_cast<CSSValueList*>(fontFamily.get());
99 if (!familyList->length())
100 return;
101
102 CSSValueList* srcList = static_cast<CSSValueList*>(src.get());
103 if (!srcList->length())
104 return;
105
106 CSSValueList* rangeList = static_cast<CSSValueList*>(unicodeRange.get());
107
108 unsigned traitsMask = 0;
109
110 if (RefPtr<CSSValue> fontStyle = style->getPropertyCSSValue(CSSPropertyFontStyle)) {
111 if (fontStyle->isPrimitiveValue()) {
112 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
113 list->append(fontStyle);
114 fontStyle = list;
115 } else if (!fontStyle->isValueList())
116 return;
117
118 CSSValueList* styleList = static_cast<CSSValueList*>(fontStyle.get());
119 unsigned numStyles = styleList->length();
120 if (!numStyles)
121 return;
122
123 for (unsigned i = 0; i < numStyles; ++i) {
124 switch (static_cast<CSSPrimitiveValue*>(styleList->itemWithoutBoundsCheck(i))->getIdent()) {
125 case CSSValueAll:
126 traitsMask |= FontStyleMask;
127 break;
128 case CSSValueNormal:
129 traitsMask |= FontStyleNormalMask;
130 break;
131 case CSSValueItalic:
132 case CSSValueOblique:
133 traitsMask |= FontStyleItalicMask;
134 break;
135 default:
136 break;
137 }
138 }
139 } else
140 traitsMask |= FontStyleMask;
141
142 if (RefPtr<CSSValue> fontWeight = style->getPropertyCSSValue(CSSPropertyFontWeight)) {
143 if (fontWeight->isPrimitiveValue()) {
144 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
145 list->append(fontWeight);
146 fontWeight = list;
147 } else if (!fontWeight->isValueList())
148 return;
149
150 CSSValueList* weightList = static_cast<CSSValueList*>(fontWeight.get());
151 unsigned numWeights = weightList->length();
152 if (!numWeights)
153 return;
154
155 for (unsigned i = 0; i < numWeights; ++i) {
156 switch (static_cast<CSSPrimitiveValue*>(weightList->itemWithoutBoundsCheck(i))->getIdent()) {
157 case CSSValueAll:
158 traitsMask |= FontWeightMask;
159 break;
160 case CSSValueBolder:
161 case CSSValueBold:
162 case CSSValue700:
163 traitsMask |= FontWeight700Mask;
164 break;
165 case CSSValueNormal:
166 case CSSValue400:
167 traitsMask |= FontWeight400Mask;
168 break;
169 case CSSValue900:
170 traitsMask |= FontWeight900Mask;
171 break;
172 case CSSValue800:
173 traitsMask |= FontWeight800Mask;
174 break;
175 case CSSValue600:
176 traitsMask |= FontWeight600Mask;
177 break;
178 case CSSValue500:
179 traitsMask |= FontWeight500Mask;
180 break;
181 case CSSValue300:
182 traitsMask |= FontWeight300Mask;
183 break;
184 case CSSValueLighter:
185 case CSSValue200:
186 traitsMask |= FontWeight200Mask;
187 break;
188 case CSSValue100:
189 traitsMask |= FontWeight100Mask;
190 break;
191 default:
192 break;
193 }
194 }
195 } else
196 traitsMask |= FontWeightMask;
197
198 if (RefPtr<CSSValue> fontVariant = style->getPropertyCSSValue(CSSPropertyFontVariant)) {
199 if (fontVariant->isPrimitiveValue()) {
200 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
201 list->append(fontVariant);
202 fontVariant = list;
203 } else if (!fontVariant->isValueList())
204 return;
205
206 CSSValueList* variantList = static_cast<CSSValueList*>(fontVariant.get());
207 unsigned numVariants = variantList->length();
208 if (!numVariants)
209 return;
210
211 for (unsigned i = 0; i < numVariants; ++i) {
212 switch (static_cast<CSSPrimitiveValue*>(variantList->itemWithoutBoundsCheck(i))->getIdent()) {
213 case CSSValueAll:
214 traitsMask |= FontVariantMask;
215 break;
216 case CSSValueNormal:
217 traitsMask |= FontVariantNormalMask;
218 break;
219 case CSSValueSmallCaps:
220 traitsMask |= FontVariantSmallCapsMask;
221 break;
222 default:
223 break;
224 }
225 }
226 } else
227 traitsMask |= FontVariantMask;
228
229 // Each item in the src property's list is a single CSSFontFaceSource. Put them all into a CSSFontFace.
230 RefPtr<CSSFontFace> fontFace;
231
232 int srcLength = srcList->length();
233
234 bool foundSVGFont = false;
235
236 for (int i = 0; i < srcLength; i++) {
237 // An item in the list either specifies a string (local font name) or a URL (remote font to download).
238 CSSFontFaceSrcValue* item = static_cast<CSSFontFaceSrcValue*>(srcList->itemWithoutBoundsCheck(i));
239 CSSFontFaceSource* source = 0;
240
241 #if ENABLE(SVG_FONTS)
242 foundSVGFont = item->isSVGFontFaceSrc() || item->svgFontFaceElement();
243 #endif
244 if (!item->isLocal()) {
245 Settings* settings = m_document ? m_document->frame() ? m_document->frame()->settings() : 0 : 0;
246 bool allowDownloading = foundSVGFont || (settings && settings->downloadableBinaryFontsEnabled());
247 if (allowDownloading && item->isSupportedFormat() && m_document) {
248 CachedFont* cachedFont = m_document->cachedResourceLoader()->requestFont(item->resource());
249 if (cachedFont) {
250 source = new CSSFontFaceSource(item->resource(), cachedFont);
251 #if ENABLE(SVG_FONTS)
252 if (foundSVGFont)
253 source->setHasExternalSVGFont(true);
254 #endif
255 }
256 }
257 } else {
258 source = new CSSFontFaceSource(item->resource());
259 }
260
261 if (!fontFace)
262 fontFace = CSSFontFace::create(static_cast<FontTraitsMask>(traitsMask));
263
264 if (source) {
265 #if ENABLE(SVG_FONTS)
266 source->setSVGFontFaceElement(item->svgFontFaceElement());
267 #endif
268 fontFace->addSource(source);
269 }
270 }
271
272 ASSERT(fontFace);
273
274 if (fontFace && !fontFace->isValid())
275 return;
276
277 if (rangeList) {
278 unsigned numRanges = rangeList->length();
279 for (unsigned i = 0; i < numRanges; i++) {
280 CSSUnicodeRangeValue* range = static_cast<CSSUnicodeRangeValue*>(rangeList->itemWithoutBoundsCheck(i));
281 fontFace->addRange(range->from(), range->to());
282 }
283 }
284
285 // Hash under every single family name.
286 int familyLength = familyList->length();
287 for (int i = 0; i < familyLength; i++) {
288 CSSPrimitiveValue* item = static_cast<CSSPrimitiveValue*>(familyList->itemWithoutBoundsCheck(i));
289 String familyName;
290 if (item->primitiveType() == CSSPrimitiveValue::CSS_STRING)
291 familyName = static_cast<FontFamilyValue*>(item)->familyName();
292 else if (item->primitiveType() == CSSPrimitiveValue::CSS_IDENT) {
293 // We need to use the raw text for all the generic family types, since @font-face is a way of actually
294 // defining what font to use for those types.
295 String familyName;
296 switch (item->getIdent()) {
297 case CSSValueSerif:
298 familyName = "-webkit-serif";
299 break;
300 case CSSValueSansSerif:
301 familyName = "-webkit-sans-serif";
302 break;
303 case CSSValueCursive:
304 familyName = "-webkit-cursive";
305 break;
306 case CSSValueFantasy:
307 familyName = "-webkit-fantasy";
308 break;
309 case CSSValueMonospace:
310 familyName = "-webkit-monospace";
311 break;
312 default:
313 break;
314 }
315 }
316
317 if (familyName.isEmpty())
318 continue;
319
320 Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(familyName);
321 if (!familyFontFaces) {
322 familyFontFaces = new Vector<RefPtr<CSSFontFace> >;
323 m_fontFaces.set(familyName, familyFontFaces);
324
325 ASSERT(!m_locallyInstalledFontFaces.contains(familyName));
326 Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFaces;
327
328 Vector<unsigned> locallyInstalledFontsTraitsMasks;
329 fontCache()->getTraitsInFamily(familyName, locallyInstalledFontsTraitsMasks);
330 unsigned numLocallyInstalledFaces = locallyInstalledFontsTraitsMasks.size();
331 if (numLocallyInstalledFaces) {
332 familyLocallyInstalledFaces = new Vector<RefPtr<CSSFontFace> >;
333 m_locallyInstalledFontFaces.set(familyName, familyLocallyInstalledFaces);
334
335 for (unsigned i = 0; i < numLocallyInstalledFaces; ++i) {
336 RefPtr<CSSFontFace> locallyInstalledFontFace = CSSFontFace::create(static_cast<FontTraitsMask>(locallyInstalledFontsTraitsMasks[i]), true);
337 locallyInstalledFontFace->addSource(new CSSFontFaceSource(familyName));
338 ASSERT(locallyInstalledFontFace->isValid());
339 familyLocallyInstalledFaces->append(locallyInstalledFontFace);
340 }
341 }
342 }
343
344 familyFontFaces->append(fontFace);
345 }
346 }
347
registerForInvalidationCallbacks(FontSelectorClient * client)348 void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient* client)
349 {
350 m_clients.add(client);
351 }
352
unregisterForInvalidationCallbacks(FontSelectorClient * client)353 void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient* client)
354 {
355 m_clients.remove(client);
356 }
357
dispatchInvalidationCallbacks()358 void CSSFontSelector::dispatchInvalidationCallbacks()
359 {
360 Vector<FontSelectorClient*> clients;
361 copyToVector(m_clients, clients);
362 for (size_t i = 0; i < clients.size(); ++i)
363 clients[i]->fontsNeedUpdate(this);
364
365 // FIXME: Make Document a FontSelectorClient so that it can simply register for invalidation callbacks.
366 if (!m_document || m_document->inPageCache() || !m_document->renderer())
367 return;
368 m_document->scheduleForcedStyleRecalc();
369 }
370
fontLoaded()371 void CSSFontSelector::fontLoaded()
372 {
373 dispatchInvalidationCallbacks();
374 }
375
fontCacheInvalidated()376 void CSSFontSelector::fontCacheInvalidated()
377 {
378 dispatchInvalidationCallbacks();
379 }
380
retireCustomFont(FontData * fontData)381 void 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
fontDataForGenericFamily(Document * document,const FontDescription & fontDescription,const AtomicString & familyName)391 static 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
420 static FontTraitsMask desiredTraitsMaskForComparison;
421
compareFontFaces(CSSFontFace * first,CSSFontFace * second)422 static 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
getFontData(const FontDescription & fontDescription,const AtomicString & familyName)502 FontData* 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