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