CSSSegmentedFontFace* FontFaceCache::get(const FontDescription& fontDescription, const AtomicString& family) { TraitsMap* familyFontFaces = m_fontFaces.get(family); if (!familyFontFaces || familyFontFaces->isEmpty()) return 0; FamilyToTraitsMap::AddResult traitsResult = m_fonts.add(family, nullptr); if (!traitsResult.storedValue->value) traitsResult.storedValue->value = adoptPtr(new TraitsMap); FontTraits traits = fontDescription.traits(); TraitsMap::AddResult faceResult = traitsResult.storedValue->value->add(traits.bitfield(), nullptr); if (!faceResult.storedValue->value) { for (TraitsMap::const_iterator i = familyFontFaces->begin(); i != familyFontFaces->end(); ++i) { CSSSegmentedFontFace* candidate = i->value.get(); FontTraits candidateTraits = candidate->traits(); if (traits.style() == FontStyleNormal && candidateTraits.style() != FontStyleNormal) continue; if (traits.variant() == FontVariantNormal && candidateTraits.variant() != FontVariantNormal) continue; if (!faceResult.storedValue->value || compareFontFaces(candidate, faceResult.storedValue->value.get(), traits)) faceResult.storedValue->value = candidate; } } return faceResult.storedValue->value.get(); }
bool FontFaceSet::check(const String& fontString, const String& text, ExceptionState& exceptionState) { if (!inActiveDocumentContext()) return false; Font font; if (!resolveFontStyle(fontString, font)) { exceptionState.ThrowDOMException(SyntaxError, "Could not resolve '" + fontString + "' as a font."); return false; } CSSFontSelector* fontSelector = document()->styleEngine()->fontSelector(); FontFaceCache* fontFaceCache = fontSelector->fontFaceCache(); bool hasLoadedFaces = false; for (const FontFamily* f = &font.fontDescription().family(); f; f = f->next()) { CSSSegmentedFontFace* face = fontFaceCache->get(font.fontDescription(), f->family()); if (face) { if (!face->checkFont(nullToSpace(text))) return false; hasLoadedFaces = true; } } if (hasLoadedFaces) return true; for (const FontFamily* f = &font.fontDescription().family(); f; f = f->next()) { if (fontSelector->isPlatformFontAvailable(font.fontDescription(), f->family())) return true; } return false; }
ScriptPromise FontFaceSet::load(ScriptState* scriptState, const String& fontString, const String& text) { if (!inActiveDocumentContext()) return ScriptPromise(); Font font; if (!resolveFontStyle(fontString, font)) { ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = resolver->promise(); resolver->reject(DOMException::create(SyntaxError, "Could not resolve '" + fontString + "' as a font.")); return promise; } FontFaceCache* fontFaceCache = document()->styleEngine().fontSelector()->fontFaceCache(); FontFaceArray faces; for (const FontFamily* f = &font.fontDescription().family(); f; f = f->next()) { CSSSegmentedFontFace* segmentedFontFace = fontFaceCache->get(font.fontDescription(), f->family()); if (segmentedFontFace) segmentedFontFace->match(text, faces); } RefPtrWillBeRawPtr<LoadFontPromiseResolver> resolver = LoadFontPromiseResolver::create(faces, scriptState); ScriptPromise promise = resolver->promise(); resolver->loadFonts(executionContext()); // After this, resolver->promise() may return null. return promise; }
bool FontLoader::checkFont(const String& fontString, const String&) { // FIXME: The second parameter (text) is ignored. FontCascade font; if (!resolveFontStyle(fontString, font)) return false; for (unsigned i = 0; i < font.familyCount(); i++) { CSSSegmentedFontFace* face = m_document->fontSelector().getFontFace(font.fontDescription(), font.familyAt(i)); if (!face || !face->checkFont()) return false; } return true; }
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); }
CSSSegmentedFontFace* CSSFontSelector::getFontFace(const FontDescription& fontDescription, const AtomicString& family) { HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >* familyFontFaces = m_fontFaces.get(family); if (!familyFontFaces || familyFontFaces->isEmpty()) return 0; OwnPtr<HashMap<unsigned, RefPtr<CSSSegmentedFontFace> > >& segmentedFontFaceCache = m_fonts.add(family, nullptr).iterator->value; if (!segmentedFontFaceCache) segmentedFontFaceCache = adoptPtr(new HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >); FontTraitsMask traitsMask = fontDescription.traitsMask(); RefPtr<CSSSegmentedFontFace>& face = segmentedFontFaceCache->add(traitsMask, 0).iterator->value; if (!face) { for (HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >::const_iterator i = familyFontFaces->begin(); i != familyFontFaces->end(); ++i) { CSSSegmentedFontFace* candidate = i->value.get(); unsigned candidateTraitsMask = candidate->traitsMask(); if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask)) continue; if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask)) continue; #if ENABLE(SVG_FONTS) // For SVG Fonts that specify that they only support the "normal" variant, we will assume they are incapable // of small-caps synthesis and just ignore the font face as a candidate. if (candidate->hasSVGFontFaceSource() && (traitsMask & FontVariantSmallCapsMask) && !(candidateTraitsMask & FontVariantSmallCapsMask)) continue; #endif if (!face || compareFontFaces(candidate, face.get(), traitsMask)) face = candidate; } if (Vector<RefPtr<CSSSegmentedFontFace> >* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) { unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size(); for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) { CSSSegmentedFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get(); unsigned candidateTraitsMask = candidate->traitsMask(); if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask)) continue; if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask)) continue; if (!face || compareFontFaces(candidate, face.get(), traitsMask)) face = candidate; } } } return face.get(); }
Vector<std::reference_wrapper<CSSFontFace>> CSSFontFaceSet::matchingFaces(const String& font, const String&, ExceptionCode& ec) { Vector<std::reference_wrapper<CSSFontFace>> result; Ref<MutableStyleProperties> style = MutableStyleProperties::create(); auto parseResult = CSSParser::parseValue(style.ptr(), CSSPropertyFont, font, true, CSSStrictMode, nullptr); if (parseResult == CSSParser::ParseResult::Error) { ec = SYNTAX_ERR; return result; } FontTraitsMask fontTraitsMask; if (auto maskOptional = computeFontTraitsMask(style.get())) fontTraitsMask = maskOptional.value(); else { ec = SYNTAX_ERR; return result; } RefPtr<CSSValue> family = style->getPropertyCSSValue(CSSPropertyFontFamily); if (!is<CSSValueList>(family.get())) { ec = SYNTAX_ERR; return result; } CSSValueList& familyList = downcast<CSSValueList>(*family); HashSet<AtomicString> uniqueFamilies; for (auto& family : familyList) { const CSSPrimitiveValue& primitive = downcast<CSSPrimitiveValue>(family.get()); if (!primitive.isFontFamily()) continue; uniqueFamilies.add(primitive.fontFamily().familyName); } for (auto& family : uniqueFamilies) { CSSSegmentedFontFace* faces = getFontFace(fontTraitsMask, family); if (!faces) continue; for (auto& constituentFace : faces->constituentFaces()) result.append(constituentFace.get()); } return result; }
void FontLoader::loadFont(const Dictionary& params) { // FIXME: The text member of params is ignored. String fontString; if (!params.get("font", fontString)) return; FontCascade font; if (!resolveFontStyle(fontString, font)) return; RefPtr<LoadFontCallback> callback = LoadFontCallback::createFromParams(params, *this, font); m_numLoadingFromJS += callback->familyCount(); for (unsigned i = 0; i < font.familyCount(); i++) { CSSSegmentedFontFace* face = m_document->fontSelector().getFontFace(font.fontDescription(), font.familyAt(i)); if (!face) { if (callback) callback->notifyError(); continue; } face->loadFont(font.fontDescription(), callback); } }
PassRefPtr<FontData> CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName) { if (m_fontFaces.isEmpty()) { if (familyName.startsWith("-webkit-")) return fontDataForGenericFamily(m_document, fontDescription, familyName); if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont()) return fontDataForGenericFamily(m_document, fontDescription, "-webkit-standard"); return 0; } CSSSegmentedFontFace* face = getFontFace(fontDescription, familyName); // If no face was found, then return 0 and let the OS come up with its best match for the name. if (!face) { // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our // settings. if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont()) return fontDataForGenericFamily(m_document, fontDescription, "-webkit-standard"); return fontDataForGenericFamily(m_document, fontDescription, familyName); } // We have a face. Ask it for a font data. If it cannot produce one, it will fail, and the OS will take over. return face->getFontData(fontDescription); }
void CSSFontSelector::willUseFontData(const FontDescription& fontDescription, const AtomicString& family) { CSSSegmentedFontFace* face = getFontFace(fontDescription, family); if (face) face->willUseFontData(fontDescription); }
void CSSFontSelector::willUseFontData(const FontDescription& fontDescription, const AtomicString& family, UChar32 character) { CSSSegmentedFontFace* face = m_fontFaceCache.get(fontDescription, family); if (face) face->willUseFontData(fontDescription, character); }