summaryrefslogtreecommitdiffstats
path: root/WebCore/css/CSSFontSelector.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:15 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:15 -0800
commit1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (patch)
tree4457a7306ea5acb43fe05bfe0973b1f7faf97ba2 /WebCore/css/CSSFontSelector.cpp
parent9364f22aed35e1a1e9d07c121510f80be3ab0502 (diff)
downloadexternal_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.zip
external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.gz
external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'WebCore/css/CSSFontSelector.cpp')
-rw-r--r--WebCore/css/CSSFontSelector.cpp500
1 files changed, 334 insertions, 166 deletions
diff --git a/WebCore/css/CSSFontSelector.cpp b/WebCore/css/CSSFontSelector.cpp
index eae3a4f..0c8cf74 100644
--- a/WebCore/css/CSSFontSelector.cpp
+++ b/WebCore/css/CSSFontSelector.cpp
@@ -25,8 +25,8 @@
*/
#include "config.h"
-
#include "CSSFontSelector.h"
+
#include "AtomicString.h"
#include "CachedFont.h"
#include "CSSFontFace.h"
@@ -58,13 +58,23 @@
namespace WebCore {
CSSFontSelector::CSSFontSelector(Document* document)
-: m_document(document)
+ : m_document(document)
{
+ // FIXME: An old comment used to say there was no need to hold a reference to m_document
+ // because "we are guaranteed to be destroyed before the document". But there does not
+ // seem to be any such guarantee.
+
ASSERT(m_document);
+ FontCache::addClient(this);
}
CSSFontSelector::~CSSFontSelector()
-{}
+{
+ FontCache::removeClient(this);
+ deleteAllValues(m_fontFaces);
+ deleteAllValues(m_locallyInstalledFontFaces);
+ deleteAllValues(m_fonts);
+}
bool CSSFontSelector::isEmpty() const
{
@@ -73,68 +83,153 @@ bool CSSFontSelector::isEmpty() const
DocLoader* CSSFontSelector::docLoader() const
{
- return m_document->docLoader();
-}
-
-static String hashForFont(const String& familyName, bool bold, bool italic)
-{
- String familyHash(familyName);
- if (bold)
- familyHash += "-webkit-bold";
- if (italic)
- familyHash += "-webkit-italic";
- return AtomicString(familyHash);
+ return m_document ? m_document->docLoader() : 0;
}
void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
{
// Obtain the font-family property and the src property. Both must be defined.
const CSSMutableStyleDeclaration* style = fontFaceRule->style();
- RefPtr<CSSValue> fontFamily = style->getPropertyCSSValue(CSS_PROP_FONT_FAMILY);
- RefPtr<CSSValue> src = style->getPropertyCSSValue(CSS_PROP_SRC);
- RefPtr<CSSValue> unicodeRange = style->getPropertyCSSValue(CSS_PROP_UNICODE_RANGE);
+ RefPtr<CSSValue> fontFamily = style->getPropertyCSSValue(CSSPropertyFontFamily);
+ RefPtr<CSSValue> src = style->getPropertyCSSValue(CSSPropertySrc);
+ RefPtr<CSSValue> unicodeRange = style->getPropertyCSSValue(CSSPropertyUnicodeRange);
if (!fontFamily || !src || !fontFamily->isValueList() || !src->isValueList() || unicodeRange && !unicodeRange->isValueList())
return;
CSSValueList* familyList = static_cast<CSSValueList*>(fontFamily.get());
if (!familyList->length())
return;
-
+
CSSValueList* srcList = static_cast<CSSValueList*>(src.get());
if (!srcList->length())
return;
CSSValueList* rangeList = static_cast<CSSValueList*>(unicodeRange.get());
- // Create a FontDescription for this font and set up bold/italic info properly.
- FontDescription fontDescription;
-
- if (RefPtr<CSSValue> fontStyle = style->getPropertyCSSValue(CSS_PROP_FONT_STYLE))
- fontDescription.setItalic(static_cast<CSSPrimitiveValue*>(fontStyle.get())->getIdent() != CSS_VAL_NORMAL);
-
- if (RefPtr<CSSValue> fontWeight = style->getPropertyCSSValue(CSS_PROP_FONT_WEIGHT)) {
- // FIXME: Need to support weights for real, since we're effectively limiting the number of supported weights to two.
- // This behavior could also result in the "last kinda bold variant" described winning even if it isn't the best match for bold.
- switch (static_cast<CSSPrimitiveValue*>(fontWeight.get())->getIdent()) {
- case CSS_VAL_BOLD:
- case CSS_VAL_BOLDER:
- case CSS_VAL_600:
- case CSS_VAL_700:
- case CSS_VAL_800:
- case CSS_VAL_900:
- fontDescription.setWeight(cBoldWeight);
- default:
- break;
+ unsigned traitsMask = 0;
+
+ if (RefPtr<CSSValue> fontStyle = style->getPropertyCSSValue(CSSPropertyFontStyle)) {
+ if (fontStyle->isPrimitiveValue()) {
+ RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
+ list->append(fontStyle);
+ fontStyle = list;
+ } else if (!fontStyle->isValueList())
+ return;
+
+ CSSValueList* styleList = static_cast<CSSValueList*>(fontStyle.get());
+ unsigned numStyles = styleList->length();
+ if (!numStyles)
+ return;
+
+ for (unsigned i = 0; i < numStyles; ++i) {
+ switch (static_cast<CSSPrimitiveValue*>(styleList->itemWithoutBoundsCheck(i))->getIdent()) {
+ case CSSValueAll:
+ traitsMask |= FontStyleMask;
+ break;
+ case CSSValueNormal:
+ traitsMask |= FontStyleNormalMask;
+ break;
+ case CSSValueItalic:
+ case CSSValueOblique:
+ traitsMask |= FontStyleItalicMask;
+ break;
+ default:
+ break;
+ }
}
- }
-
- if (RefPtr<CSSValue> fontVariant = style->getPropertyCSSValue(CSS_PROP_FONT_VARIANT))
- fontDescription.setSmallCaps(static_cast<CSSPrimitiveValue*>(fontVariant.get())->getIdent() == CSS_VAL_SMALL_CAPS);
+ } else
+ traitsMask |= FontStyleMask;
+
+ if (RefPtr<CSSValue> fontWeight = style->getPropertyCSSValue(CSSPropertyFontWeight)) {
+ if (fontWeight->isPrimitiveValue()) {
+ RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
+ list->append(fontWeight);
+ fontWeight = list;
+ } else if (!fontWeight->isValueList())
+ return;
+
+ CSSValueList* weightList = static_cast<CSSValueList*>(fontWeight.get());
+ unsigned numWeights = weightList->length();
+ if (!numWeights)
+ return;
+
+ for (unsigned i = 0; i < numWeights; ++i) {
+ switch (static_cast<CSSPrimitiveValue*>(weightList->itemWithoutBoundsCheck(i))->getIdent()) {
+ case CSSValueAll:
+ traitsMask |= FontWeightMask;
+ break;
+ case CSSValueBolder:
+ case CSSValueBold:
+ case CSSValue700:
+ traitsMask |= FontWeight700Mask;
+ break;
+ case CSSValueNormal:
+ case CSSValue400:
+ traitsMask |= FontWeight400Mask;
+ break;
+ case CSSValue900:
+ traitsMask |= FontWeight900Mask;
+ break;
+ case CSSValue800:
+ traitsMask |= FontWeight800Mask;
+ break;
+ case CSSValue600:
+ traitsMask |= FontWeight600Mask;
+ break;
+ case CSSValue500:
+ traitsMask |= FontWeight500Mask;
+ break;
+ case CSSValue300:
+ traitsMask |= FontWeight300Mask;
+ break;
+ case CSSValueLighter:
+ case CSSValue200:
+ traitsMask |= FontWeight200Mask;
+ break;
+ case CSSValue100:
+ traitsMask |= FontWeight100Mask;
+ break;
+ default:
+ break;
+ }
+ }
+ } else
+ traitsMask |= FontWeightMask;
+
+ if (RefPtr<CSSValue> fontVariant = style->getPropertyCSSValue(CSSPropertyFontVariant)) {
+ if (fontVariant->isPrimitiveValue()) {
+ RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
+ list->append(fontVariant);
+ fontVariant = list;
+ } else if (!fontVariant->isValueList())
+ return;
+
+ CSSValueList* variantList = static_cast<CSSValueList*>(fontVariant.get());
+ unsigned numVariants = variantList->length();
+ if (!numVariants)
+ return;
+
+ for (unsigned i = 0; i < numVariants; ++i) {
+ switch (static_cast<CSSPrimitiveValue*>(variantList->itemWithoutBoundsCheck(i))->getIdent()) {
+ case CSSValueAll:
+ traitsMask |= FontVariantMask;
+ break;
+ case CSSValueNormal:
+ traitsMask |= FontVariantNormalMask;
+ break;
+ case CSSValueSmallCaps:
+ traitsMask |= FontVariantSmallCapsMask;
+ break;
+ default:
+ break;
+ }
+ }
+ } else
+ traitsMask |= FontVariantNormalMask;
// Each item in the src property's list is a single CSSFontFaceSource. Put them all into a CSSFontFace.
- CSSFontFace* fontFace = 0;
+ RefPtr<CSSFontFace> fontFace;
- int i;
int srcLength = srcList->length();
bool foundLocal = false;
@@ -143,9 +238,9 @@ void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
bool foundSVGFont = false;
#endif
- for (i = 0; i < srcLength; i++) {
+ for (int i = 0; i < srcLength; i++) {
// An item in the list either specifies a string (local font name) or a URL (remote font to download).
- CSSFontFaceSrcValue* item = static_cast<CSSFontFaceSrcValue*>(srcList->item(i));
+ CSSFontFaceSrcValue* item = static_cast<CSSFontFaceSrcValue*>(srcList->itemWithoutBoundsCheck(i));
CSSFontFaceSource* source = 0;
#if ENABLE(SVG_FONTS)
@@ -153,7 +248,7 @@ void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
#endif
if (!item->isLocal()) {
- if (item->isSupportedFormat()) {
+ if (item->isSupportedFormat() && m_document) {
CachedFont* cachedFont = m_document->docLoader()->requestFont(item->resource());
if (cachedFont) {
#if ENABLE(SVG_FONTS)
@@ -164,22 +259,12 @@ void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
}
}
} else {
- String family = item->resource();
-
- // Test the validity of the local font now. We don't want to include this font if it does not exist
- // on the system. If it *does* exist on the system, then we don't need to look any further.
- if (FontCache::fontExists(fontDescription, family)
-#if ENABLE(SVG_FONTS)
- || foundSVGFont
-#endif
- ) {
- source = new CSSFontFaceSource(family);
- foundLocal = true;
- }
+ source = new CSSFontFaceSource(item->resource());
+ foundLocal = true;
}
if (!fontFace)
- fontFace = new CSSFontFace();
+ fontFace = CSSFontFace::create(static_cast<FontTraitsMask>(traitsMask));
if (source) {
#if ENABLE(SVG_FONTS)
@@ -187,44 +272,46 @@ void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
#endif
fontFace->addSource(source);
}
-
- // We can just break if we see a local font that is valid.
- if (foundLocal)
- break;
}
ASSERT(fontFace);
- if (fontFace && !fontFace->isValid()) {
- delete fontFace;
+ if (fontFace && !fontFace->isValid())
return;
+
+ if (rangeList) {
+ unsigned numRanges = rangeList->length();
+ for (unsigned i = 0; i < numRanges; i++) {
+ CSSUnicodeRangeValue* range = static_cast<CSSUnicodeRangeValue*>(rangeList->itemWithoutBoundsCheck(i));
+ fontFace->addRange(range->from(), range->to());
+ }
}
// Hash under every single family name.
int familyLength = familyList->length();
- for (i = 0; i < familyLength; i++) {
- CSSPrimitiveValue* item = static_cast<CSSPrimitiveValue*>(familyList->item(i));
+ for (int i = 0; i < familyLength; i++) {
+ CSSPrimitiveValue* item = static_cast<CSSPrimitiveValue*>(familyList->itemWithoutBoundsCheck(i));
String familyName;
if (item->primitiveType() == CSSPrimitiveValue::CSS_STRING)
- familyName = static_cast<FontFamilyValue*>(item)->fontName();
+ familyName = static_cast<FontFamilyValue*>(item)->familyName();
else if (item->primitiveType() == CSSPrimitiveValue::CSS_IDENT) {
// We need to use the raw text for all the generic family types, since @font-face is a way of actually
// defining what font to use for those types.
String familyName;
switch (item->getIdent()) {
- case CSS_VAL_SERIF:
+ case CSSValueSerif:
familyName = "-webkit-serif";
break;
- case CSS_VAL_SANS_SERIF:
+ case CSSValueSansSerif:
familyName = "-webkit-sans-serif";
break;
- case CSS_VAL_CURSIVE:
+ case CSSValueCursive:
familyName = "-webkit-cursive";
break;
- case CSS_VAL_FANTASY:
+ case CSSValueFantasy:
familyName = "-webkit-fantasy";
break;
- case CSS_VAL_MONOSPACE:
+ case CSSValueMonospace:
familyName = "-webkit-monospace";
break;
default:
@@ -238,132 +325,213 @@ void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
#if ENABLE(SVG_FONTS)
// SVG allows several <font> elements with the same font-family, differing only
// in ie. font-variant. Be sure to pick up the right one - in getFontData below.
- if (foundSVGFont && fontDescription.smallCaps())
+ if (foundSVGFont && (traitsMask & FontVariantSmallCapsMask))
familyName += "-webkit-svg-small-caps";
#endif
- String hash = hashForFont(familyName.lower(), fontDescription.bold(), fontDescription.italic());
- CSSSegmentedFontFace* segmentedFontFace = m_fonts.get(hash).get();
- if (!segmentedFontFace) {
- segmentedFontFace = new CSSSegmentedFontFace(this);
- m_fonts.set(hash, segmentedFontFace);
- }
- if (rangeList) {
- // A local font matching the font description should come first, so that it gets used for
- // any character not overlaid by explicit @font-face rules for the family.
- if (!segmentedFontFace->numRanges() && FontCache::fontExists(fontDescription, familyName)) {
- CSSFontFace* implicitFontFace = new CSSFontFace();
- implicitFontFace->addSource(new CSSFontFaceSource(familyName));
- ASSERT(implicitFontFace->isValid());
- segmentedFontFace->overlayRange(0, 0x7FFFFFFF, implicitFontFace);
+ Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(familyName);
+ if (!familyFontFaces) {
+ familyFontFaces = new Vector<RefPtr<CSSFontFace> >;
+ m_fontFaces.set(familyName, familyFontFaces);
+
+ ASSERT(!m_locallyInstalledFontFaces.contains(familyName));
+ Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFaces;
+
+ Vector<unsigned> locallyInstalledFontsTraitsMasks;
+ FontCache::getTraitsInFamily(familyName, locallyInstalledFontsTraitsMasks);
+ unsigned numLocallyInstalledFaces = locallyInstalledFontsTraitsMasks.size();
+ if (numLocallyInstalledFaces) {
+ familyLocallyInstalledFaces = new Vector<RefPtr<CSSFontFace> >;
+ m_locallyInstalledFontFaces.set(familyName, familyLocallyInstalledFaces);
+
+ for (unsigned i = 0; i < numLocallyInstalledFaces; ++i) {
+ RefPtr<CSSFontFace> locallyInstalledFontFace = CSSFontFace::create(static_cast<FontTraitsMask>(locallyInstalledFontsTraitsMasks[i]));
+ locallyInstalledFontFace->addSource(new CSSFontFaceSource(familyName));
+ ASSERT(locallyInstalledFontFace->isValid());
+ familyLocallyInstalledFaces->append(locallyInstalledFontFace);
+ }
}
+ }
- unsigned numRanges = rangeList->length();
- for (unsigned i = 0; i < numRanges; i++) {
- CSSUnicodeRangeValue* range = static_cast<CSSUnicodeRangeValue*>(rangeList->item(i));
- segmentedFontFace->overlayRange(range->from(), range->to(), fontFace);
- }
- } else
- segmentedFontFace->overlayRange(0, 0x7FFFFFFF, fontFace);
+ familyFontFaces->append(fontFace);
}
}
void CSSFontSelector::fontLoaded(CSSSegmentedFontFace*)
{
- if (m_document->inPageCache())
+ if (!m_document || m_document->inPageCache() || !m_document->renderer())
return;
m_document->recalcStyle(Document::Force);
m_document->renderer()->setNeedsLayoutAndPrefWidthsRecalc();
}
-FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
+void CSSFontSelector::fontCacheInvalidated()
+{
+ if (!m_document || m_document->inPageCache() || !m_document->renderer())
+ return;
+ m_document->recalcStyle(Document::Force);
+ m_document->renderer()->setNeedsLayoutAndPrefWidthsRecalc();
+}
+
+static FontData* fontDataForGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName)
{
- if (m_fonts.isEmpty() && !familyName.startsWith("-webkit-"))
+ if (!document || !document->frame())
+ return 0;
+
+ const Settings* settings = document->frame()->settings();
+ if (!settings)
return 0;
- bool bold = fontDescription.bold();
- bool italic = fontDescription.italic();
-
- bool syntheticBold = false;
- bool syntheticItalic = false;
+ AtomicString genericFamily;
+ if (familyName == "-webkit-serif")
+ genericFamily = settings->serifFontFamily();
+ else if (familyName == "-webkit-sans-serif")
+ genericFamily = settings->sansSerifFontFamily();
+ else if (familyName == "-webkit-cursive")
+ genericFamily = settings->cursiveFontFamily();
+ else if (familyName == "-webkit-fantasy")
+ genericFamily = settings->fantasyFontFamily();
+ else if (familyName == "-webkit-monospace")
+ genericFamily = settings->fixedFontFamily();
+ else if (familyName == "-webkit-standard")
+ genericFamily = settings->standardFontFamily();
+
+ if (!genericFamily.isEmpty())
+ return FontCache::getCachedFontData(FontCache::getCachedFontPlatformData(fontDescription, genericFamily));
+
+ return 0;
+}
- String family = familyName.domString().lower();
+static FontTraitsMask desiredTraitsMaskForComparison;
-#if ENABLE(SVG_FONTS)
- RefPtr<CSSSegmentedFontFace> face;
+static inline bool compareFontFaces(CSSFontFace* first, 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;
+
+ bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
+ bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
+
+ if (firstHasDesiredStyle != secondHasDesiredStyle)
+ return firstHasDesiredStyle;
+
+ if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
+ return false;
+ if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
+ return true;
+
+ // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#q46 says: "If there are fewer then 9 weights in the family, the default algorithm
+ // for filling the "holes" is as follows. If '500' is unassigned, it will be assigned the same font as '400'. If any of the values '600',
+ // '700', '800', or '900' remains unassigned, they are assigned to the same face as the next darker assigned keyword, if any, or the next
+ // lighter one otherwise. If any of '300', '200', or '100' remains unassigned, it is assigned to the next lighter assigned keyword, if any,
+ // or the next darker otherwise."
+ // For '400', we made up our own rule (which then '500' follows).
+
+ static const FontTraitsMask weightFallbackRules[9][8] = {
+ { 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, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask },
+ { FontWeight400Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, 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 }
+ };
+
+ const FontTraitsMask* weightFallbackRule = weightFallbackRules[0];
+ unsigned w = FontWeight100Bit;
+ while (!(desiredTraitsMaskForComparison & (1 << w))) {
+ w++;
+ weightFallbackRule += 8;
+ }
- if (fontDescription.smallCaps()) {
- String testFamily = family + "-webkit-svg-small-caps";
- face = m_fonts.get(hashForFont(testFamily, bold, italic));
- } else
- face = m_fonts.get(hashForFont(family, bold, italic));
-#else
- RefPtr<CSSSegmentedFontFace> face = m_fonts.get(hashForFont(family, bold, italic));
-#endif
+ for (unsigned i = 0; i < 8; ++i) {
+ if (secondTraitsMask & weightFallbackRule[i])
+ return false;
+ if (firstTraitsMask & weightFallbackRule[i])
+ return true;
+ }
- // If we don't find a face, and if bold/italic are set, we should try other variants.
- // Bold/italic should try bold first, then italic, then normal (on the assumption that we are better at synthesizing italic than we are
- // at synthesizing bold).
- if (!face) {
- if (bold && italic) {
- syntheticItalic = true;
- face = m_fonts.get(hashForFont(family, bold, false));
- if (!face) {
- syntheticBold = true;
- face = m_fonts.get(hashForFont(family, false, italic));
- }
- }
-
- // Bold should try normal.
- // Italic should try normal.
- if (!face && (bold || italic)) {
- syntheticBold = bold;
- syntheticItalic = italic;
- face = m_fonts.get(hashForFont(family, false, false));
- }
+ return false;
+}
+
+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 no face was found, and if we're a SVG Font we may have hit following case:
- // <font-face> specified font-weight and/or font-style to be ie. bold and italic.
- // And the font-family requested is non-bold & non-italic. For SVG Fonts we still
- // have to return the defined font, and not fallback to the system default.
- if (!face && !bold)
- face = m_fonts.get(hashForFont(family, true, italic));
-
- if (!face && !italic)
- face = m_fonts.get(hashForFont(family, bold, true));
-
- if (!face && !bold && !italic)
- face = m_fonts.get(hashForFont(family, true, true));
+ 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 (!face) {
+ 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.
- const Settings* settings = m_document->frame()->settings();
- AtomicString genericFamily;
- if (familyName == "-webkit-serif")
- genericFamily = settings->serifFontFamily();
- else if (familyName == "-webkit-sans-serif")
- genericFamily = settings->sansSerifFontFamily();
- else if (familyName == "-webkit-cursive")
- genericFamily = settings->cursiveFontFamily();
- else if (familyName == "-webkit-fantasy")
- genericFamily = settings->fantasyFontFamily();
- else if (familyName == "-webkit-monospace")
- genericFamily = settings->fixedFontFamily();
- else if (familyName == "-webkit-standard")
- genericFamily = settings->standardFontFamily();
-
- if (!genericFamily.isEmpty())
- return FontCache::getCachedFontData(FontCache::getCachedFontPlatformData(fontDescription, genericFamily));
- return 0;
+ 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, syntheticBold, syntheticItalic);
+ return face->getFontData(fontDescription);
}
}