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