const FontRanges& FontCascadeFonts::realizeFallbackRangesAt(const FontDescription& description, unsigned index) { if (index < m_realizedFallbackRanges.size()) return m_realizedFallbackRanges[index]; ASSERT(index == m_realizedFallbackRanges.size()); ASSERT(FontCache::singleton().generation() == m_generation); m_realizedFallbackRanges.append(FontRanges()); auto& fontRanges = m_realizedFallbackRanges.last(); if (!index) { fontRanges = realizeNextFallback(description, m_lastRealizedFallbackIndex, m_fontSelector.get()); if (fontRanges.isNull() && m_fontSelector) fontRanges = m_fontSelector->fontRangesForFamily(description, standardFamily); if (fontRanges.isNull()) fontRanges = FontRanges(FontCache::singleton().lastResortFallbackFont(description)); return fontRanges; } if (m_lastRealizedFallbackIndex < description.familyCount()) fontRanges = realizeNextFallback(description, m_lastRealizedFallbackIndex, m_fontSelector.get()); if (fontRanges.isNull() && m_fontSelector) { ASSERT(m_lastRealizedFallbackIndex >= description.familyCount()); unsigned fontSelectorFallbackIndex = m_lastRealizedFallbackIndex - description.familyCount(); if (fontSelectorFallbackIndex == m_fontSelector->fallbackFontCount()) return fontRanges; ++m_lastRealizedFallbackIndex; fontRanges = FontRanges(m_fontSelector->fallbackFontAt(description, fontSelectorFallbackIndex)); } return fontRanges; }
FontRanges CSSSegmentedFontFace::fontRanges(const FontDescription& fontDescription) { if (!isValid()) return FontRanges(); FontTraitsMask desiredTraitsMask = fontDescription.traitsMask(); unsigned hashKey = ((fontDescription.computedPixelSize() + 1) << (FontTraitsMaskWidth + FontWidthVariantWidth + 1)) | ((fontDescription.orientation() == Vertical ? 1 : 0) << (FontTraitsMaskWidth + FontWidthVariantWidth)) | fontDescription.widthVariant() << FontTraitsMaskWidth | desiredTraitsMask; auto addResult = m_descriptionToRangesMap.add(hashKey, FontRanges()); auto& fontRanges = addResult.iterator->value; if (addResult.isNewEntry) { for (auto& face : m_fontFaces) { if (!face->isValid()) continue; FontTraitsMask traitsMask = face->traitsMask(); bool syntheticBold = !(traitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)) && (desiredTraitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)); bool syntheticItalic = !(traitsMask & FontStyleItalicMask) && (desiredTraitsMask & FontStyleItalicMask); if (RefPtr<Font> faceFont = face->font(fontDescription, syntheticBold, syntheticItalic)) appendFontWithInvalidUnicodeRangeIfLoading(fontRanges, faceFont.releaseNonNull(), face->ranges()); } } return fontRanges; }
static FontRanges realizeNextFallback(const FontCascadeDescription& description, unsigned& index, FontSelector* fontSelector) { ASSERT(index < description.familyCount()); auto& fontCache = FontCache::singleton(); while (index < description.familyCount()) { const AtomicString& family = description.familyAt(index++); if (family.isEmpty()) continue; if (fontSelector) { auto ranges = fontSelector->fontRangesForFamily(description, family); if (!ranges.isNull()) return ranges; } if (auto font = fontCache.fontForFamily(description, family)) return FontRanges(WTFMove(font)); } // We didn't find a font. Try to find a similar font using our own specific knowledge about our platform. // For example on OS X, we know to map any families containing the words Arabic, Pashto, or Urdu to the // Geeza Pro font. for (auto& family : description.families()) { if (auto font = fontCache.similarFont(description, family)) return FontRanges(WTFMove(font)); } return { }; }
FontCascadeFonts::FontCascadeFonts(const FontPlatformData& platformData) : m_cachedPrimaryFont(nullptr) , m_fontSelectorVersion(0) , m_generation(FontCache::singleton().generation()) , m_isForPlatformFont(true) { m_realizedFallbackRanges.append(FontRanges(FontCache::singleton().fontForPlatformData(platformData))); }
FontRanges CSSFontSelector::fontRangesForFamily(const FontDescription& fontDescription, const AtomicString& familyName) { // FIXME: The spec (and Firefox) says user specified generic families (sans-serif etc.) should be resolved before the @font-face lookup too. bool resolveGenericFamilyFirst = familyName == standardFamily; AtomicString familyForLookup = resolveGenericFamilyFirst ? resolveGenericFamily(m_document, fontDescription, familyName) : familyName; CSSSegmentedFontFace* face = getFontFace(fontDescription, familyForLookup); if (!face) { if (!resolveGenericFamilyFirst) familyForLookup = resolveGenericFamily(m_document, fontDescription, familyName); return FontRanges(FontCache::singleton().fontForFamily(fontDescription, familyForLookup)); } return face->fontRanges(fontDescription); }
FontRanges CSSSegmentedFontFace::fontRanges(const FontDescription& fontDescription) { FontTraitsMask desiredTraitsMask = fontDescription.traitsMask(); auto addResult = m_cache.add(FontDescriptionKey(fontDescription), FontRanges()); auto& fontRanges = addResult.iterator->value; if (addResult.isNewEntry) { for (auto& face : m_fontFaces) { if (face->allSourcesFailed()) continue; FontTraitsMask traitsMask = face->traitsMask(); bool syntheticBold = (fontDescription.fontSynthesis() & FontSynthesisWeight) && !(traitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)) && (desiredTraitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)); bool syntheticItalic = (fontDescription.fontSynthesis() & FontSynthesisStyle) && !(traitsMask & FontStyleItalicMask) && (desiredTraitsMask & FontStyleItalicMask); if (RefPtr<Font> faceFont = face->font(fontDescription, syntheticBold, syntheticItalic)) appendFontWithInvalidUnicodeRangeIfLoading(fontRanges, faceFont.releaseNonNull(), face->ranges()); } } return fontRanges; }