static bool fontFaceComparator(FontTraitsMask desiredTraitsMaskForComparison, const CSSFontFace& first, const CSSFontFace& second) { FontTraitsMask firstTraitsMask = first.traitsMask(); FontTraitsMask secondTraitsMask = second.traitsMask(); bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask; bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask; if (firstHasDesiredStyle != secondHasDesiredStyle) return firstHasDesiredStyle; if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first.isLocalFallback() && !second.isLocalFallback()) { // Prefer a font that has indicated that it can only support italics to a font that claims to support // all styles. The specialized font is more likely to be the one the author wants used. bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask); bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask); if (firstRequiresItalics != secondRequiresItalics) return firstRequiresItalics; } if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) return false; if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) return true; // http://www.w3.org/TR/2011/WD-css3-fonts-20111004/#font-matching-algorithm says : // - 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. // - 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. // - If the desired weight is 400, 500 is checked first and then the rule for desired weights less than 400 is used. // - If the desired weight is 500, 400 is checked first and then the rule for desired weights less than 400 is used. static const unsigned fallbackRuleSets = 9; static const unsigned rulesPerSet = 8; static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = { { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, { FontWeight500Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, { FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask } }; unsigned ruleSetIndex = 0; for (; !(desiredTraitsMaskForComparison & (1 << (FontWeight100Bit + ruleSetIndex))); ruleSetIndex++) { } const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex]; for (unsigned i = 0; i < rulesPerSet; ++i) { if (secondTraitsMask & weightFallbackRule[i]) return false; if (firstTraitsMask & weightFallbackRule[i]) return true; } return false; }
CSSSegmentedFontFace* CSSFontSelector::getFontFace(const FontDescription& fontDescription, const AtomicString& family) { Vector<RefPtr<CSSFontFace> >* 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) { face = CSSSegmentedFontFace::create(this); // Collect all matching faces and sort them in order of preference. Vector<CSSFontFace*, 32> candidateFontFaces; for (int i = familyFontFaces->size() - 1; i >= 0; --i) { CSSFontFace* candidate = familyFontFaces->at(i).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 candidateFontFaces.append(candidate); } if (Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) { unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size(); for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) { CSSFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get(); unsigned candidateTraitsMask = candidate->traitsMask(); if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask)) continue; if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask)) continue; candidateFontFaces.append(candidate); } } desiredTraitsMaskForComparison = traitsMask; stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), compareFontFaces); unsigned numCandidates = candidateFontFaces.size(); for (unsigned i = 0; i < numCandidates; ++i) face->appendFontFace(candidateFontFaces[i]); } return face.get(); }
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; } String family = familyName.string(); Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(family); // If no face was found, then return 0 and let the OS come up with its best match for the name. if (!familyFontFaces || familyFontFaces->isEmpty()) { // 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); } OwnPtr<HashMap<unsigned, RefPtr<CSSSegmentedFontFace> > >& segmentedFontFaceCache = m_fonts.add(family, nullptr).first->second; if (!segmentedFontFaceCache) segmentedFontFaceCache = adoptPtr(new HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >); FontTraitsMask traitsMask = fontDescription.traitsMask(); RefPtr<CSSSegmentedFontFace>& face = segmentedFontFaceCache->add(traitsMask, 0).first->second; if (!face) { face = CSSSegmentedFontFace::create(this); // Collect all matching faces and sort them in order of preference. Vector<CSSFontFace*, 32> candidateFontFaces; for (int i = familyFontFaces->size() - 1; i >= 0; --i) { CSSFontFace* candidate = familyFontFaces->at(i).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 candidateFontFaces.append(candidate); } if (Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) { unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size(); for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) { CSSFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get(); unsigned candidateTraitsMask = candidate->traitsMask(); if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask)) continue; if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask)) continue; candidateFontFaces.append(candidate); } } desiredTraitsMaskForComparison = traitsMask; stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), compareFontFaces); unsigned numCandidates = candidateFontFaces.size(); for (unsigned i = 0; i < numCandidates; ++i) face->appendFontFace(candidateFontFaces[i]); } // 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); }
FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName) { if (m_fontFaces.isEmpty()) { if (familyName.startsWith("-webkit-")) return fontDataForGenericFamily(m_document, fontDescription, familyName); return 0; } String family = familyName.string(); #if ENABLE(SVG_FONTS) if (fontDescription.smallCaps()) family += "-webkit-svg-small-caps"; #endif Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(family); // If no face was found, then return 0 and let the OS come up with its best match for the name. if (!familyFontFaces || familyFontFaces->isEmpty()) { // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our // settings. return fontDataForGenericFamily(m_document, fontDescription, familyName); } HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >* segmentedFontFaceCache = m_fonts.get(family); if (!segmentedFontFaceCache) { segmentedFontFaceCache = new HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >; m_fonts.set(family, segmentedFontFaceCache); } FontTraitsMask traitsMask = fontDescription.traitsMask(); RefPtr<CSSSegmentedFontFace> face = segmentedFontFaceCache->get(traitsMask); if (!face) { face = CSSSegmentedFontFace::create(this); segmentedFontFaceCache->set(traitsMask, face); // Collect all matching faces and sort them in order of preference. Vector<CSSFontFace*, 32> candidateFontFaces; for (int i = familyFontFaces->size() - 1; i >= 0; --i) { CSSFontFace* candidate = familyFontFaces->at(i).get(); unsigned candidateTraitsMask = candidate->traitsMask(); if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask)) continue; if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask)) continue; candidateFontFaces.append(candidate); } if (Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) { unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size(); for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) { CSSFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get(); unsigned candidateTraitsMask = candidate->traitsMask(); if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask)) continue; if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask)) continue; candidateFontFaces.append(candidate); } } desiredTraitsMaskForComparison = traitsMask; std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), compareFontFaces); unsigned numCandidates = candidateFontFaces.size(); for (unsigned i = 0; i < numCandidates; ++i) face->appendFontFace(candidateFontFaces[i]); } // 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); }
static inline bool compareFontFaces(const CSSFontFace& first, const CSSFontFace& second) { FontTraitsMask firstTraitsMask = first.traitsMask(); FontTraitsMask secondTraitsMask = second.traitsMask(); bool firstHasDesiredVariant = firstTraitsMask & desiredTraitsMaskForComparison & FontVariantMask; bool secondHasDesiredVariant = secondTraitsMask & desiredTraitsMaskForComparison & FontVariantMask; if (firstHasDesiredVariant != secondHasDesiredVariant) return firstHasDesiredVariant; // We need to check font-variant css property for CSS2.1 compatibility. if ((desiredTraitsMaskForComparison & FontVariantSmallCapsMask) && !first.isLocalFallback() && !second.isLocalFallback()) { // Prefer a font that has indicated that it can only support small-caps to a font that claims to support // all variants. The specialized font is more likely to be true small-caps and not require synthesis. bool firstRequiresSmallCaps = (firstTraitsMask & FontVariantSmallCapsMask) && !(firstTraitsMask & FontVariantNormalMask); bool secondRequiresSmallCaps = (secondTraitsMask & FontVariantSmallCapsMask) && !(secondTraitsMask & FontVariantNormalMask); if (firstRequiresSmallCaps != secondRequiresSmallCaps) return firstRequiresSmallCaps; } bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask; bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask; if (firstHasDesiredStyle != secondHasDesiredStyle) return firstHasDesiredStyle; if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first.isLocalFallback() && !second.isLocalFallback()) { // Prefer a font that has indicated that it can only support italics to a font that claims to support // all styles. The specialized font is more likely to be the one the author wants used. bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask); bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask); if (firstRequiresItalics != secondRequiresItalics) return firstRequiresItalics; } if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) return false; if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) return true; // http://www.w3.org/TR/2011/WD-css3-fonts-20111004/#font-matching-algorithm says : // - 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. // - 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. // - If the desired weight is 400, 500 is checked first and then the rule for desired weights less than 400 is used. // - If the desired weight is 500, 400 is checked first and then the rule for desired weights less than 400 is used. static const unsigned fallbackRuleSets = 9; static const unsigned rulesPerSet = 8; static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = { { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, { FontWeight500Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, { FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask } }; unsigned ruleSetIndex = 0; unsigned w = FontWeight100Bit; while (!(desiredTraitsMaskForComparison & (1 << w))) { w++; ruleSetIndex++; } ASSERT_WITH_SECURITY_IMPLICATION(ruleSetIndex < fallbackRuleSets); const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex]; for (unsigned i = 0; i < rulesPerSet; ++i) { if (secondTraitsMask & weightFallbackRule[i]) return false; if (firstTraitsMask & weightFallbackRule[i]) return true; } return false; }