CSSFontSelector.cpp [plain text]
#include "config.h"
#include "CSSFontSelector.h"
#include "AtomicString.h"
#include "CachedFont.h"
#include "CSSFontFace.h"
#include "CSSFontFaceRule.h"
#include "CSSFontFaceSource.h"
#include "CSSFontFaceSrcValue.h"
#include "CSSMutableStyleDeclaration.h"
#include "CSSPrimitiveValue.h"
#include "CSSPropertyNames.h"
#include "CSSSegmentedFontFace.h"
#include "CSSUnicodeRangeValue.h"
#include "CSSValueKeywords.h"
#include "CSSValueList.h"
#include "DocLoader.h"
#include "Document.h"
#include "FontCache.h"
#include "FontFamilyValue.h"
#include "Frame.h"
#include "NodeList.h"
#include "RenderObject.h"
#include "Settings.h"
#include "SimpleFontData.h"
#if ENABLE(SVG)
#include "SVGFontFaceElement.h"
#include "SVGNames.h"
#endif
namespace WebCore {
CSSFontSelector::CSSFontSelector(Document* document)
: m_document(document)
{
ASSERT(m_document);
}
CSSFontSelector::~CSSFontSelector()
{}
bool CSSFontSelector::isEmpty() const
{
return m_fonts.isEmpty();
}
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);
}
void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
{
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);
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());
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)) {
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;
}
}
if (RefPtr<CSSValue> fontVariant = style->getPropertyCSSValue(CSS_PROP_FONT_VARIANT))
fontDescription.setSmallCaps(static_cast<CSSPrimitiveValue*>(fontVariant.get())->getIdent() == CSS_VAL_SMALL_CAPS);
CSSFontFace* fontFace = 0;
int i;
int srcLength = srcList->length();
bool foundLocal = false;
#if ENABLE(SVG_FONTS)
bool foundSVGFont = false;
#endif
for (i = 0; i < srcLength; i++) {
CSSFontFaceSrcValue* item = static_cast<CSSFontFaceSrcValue*>(srcList->item(i));
CSSFontFaceSource* source = 0;
#if ENABLE(SVG_FONTS)
foundSVGFont = item->isSVGFontFaceSrc() || item->svgFontFaceElement();
#endif
if (!item->isLocal()) {
if (item->isSupportedFormat()) {
CachedFont* cachedFont = m_document->docLoader()->requestFont(item->resource());
if (cachedFont) {
#if ENABLE(SVG_FONTS)
if (foundSVGFont)
cachedFont->setSVGFont(true);
#endif
source = new CSSFontFaceSource(item->resource(), cachedFont);
}
}
} else {
String family = item->resource();
if (FontCache::fontExists(fontDescription, family)
#if ENABLE(SVG_FONTS)
|| foundSVGFont
#endif
) {
source = new CSSFontFaceSource(family);
foundLocal = true;
}
}
if (!fontFace)
fontFace = new CSSFontFace();
if (source) {
#if ENABLE(SVG_FONTS)
source->setSVGFontFaceElement(item->svgFontFaceElement());
#endif
fontFace->addSource(source);
}
if (foundLocal)
break;
}
ASSERT(fontFace);
if (fontFace && !fontFace->isValid()) {
delete fontFace;
return;
}
int familyLength = familyList->length();
for (i = 0; i < familyLength; i++) {
CSSPrimitiveValue* item = static_cast<CSSPrimitiveValue*>(familyList->item(i));
String familyName;
if (item->primitiveType() == CSSPrimitiveValue::CSS_STRING)
familyName = static_cast<FontFamilyValue*>(item)->fontName();
else if (item->primitiveType() == CSSPrimitiveValue::CSS_IDENT) {
String familyName;
switch (item->getIdent()) {
case CSS_VAL_SERIF:
familyName = "-webkit-serif";
break;
case CSS_VAL_SANS_SERIF:
familyName = "-webkit-sans-serif";
break;
case CSS_VAL_CURSIVE:
familyName = "-webkit-cursive";
break;
case CSS_VAL_FANTASY:
familyName = "-webkit-fantasy";
break;
case CSS_VAL_MONOSPACE:
familyName = "-webkit-monospace";
break;
default:
break;
}
}
if (familyName.isEmpty())
continue;
#if ENABLE(SVG_FONTS)
if (foundSVGFont && fontDescription.smallCaps())
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) {
if (!segmentedFontFace->numRanges() && FontCache::fontExists(fontDescription, familyName)) {
CSSFontFace* implicitFontFace = new CSSFontFace();
implicitFontFace->addSource(new CSSFontFaceSource(familyName));
ASSERT(implicitFontFace->isValid());
segmentedFontFace->overlayRange(0, 0x7FFFFFFF, implicitFontFace);
}
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);
}
}
void CSSFontSelector::fontLoaded(CSSSegmentedFontFace*)
{
if (m_document->inPageCache())
return;
m_document->recalcStyle(Document::Force);
m_document->renderer()->setNeedsLayoutAndPrefWidthsRecalc();
}
FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
{
if (m_fonts.isEmpty() && !familyName.startsWith("-webkit-"))
return 0;
bool bold = fontDescription.bold();
bool italic = fontDescription.italic();
bool syntheticBold = false;
bool syntheticItalic = false;
String family = familyName.domString().lower();
#if ENABLE(SVG_FONTS)
RefPtr<CSSSegmentedFontFace> face;
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
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));
}
}
if (!face && (bold || italic)) {
syntheticBold = bold;
syntheticItalic = italic;
face = m_fonts.get(hashForFont(family, false, false));
}
}
#if ENABLE(SVG_FONTS)
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));
#endif
if (!face) {
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 face->getFontData(fontDescription, syntheticBold, syntheticItalic);
}
}