kdelibs/khtml/css/css_webfont.cpp

854 lines
31 KiB
C++
Raw Normal View History

/*
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2009 Germain Garand <germain@ebooksfrance.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "css_webfont.h"
#include "css/css_ruleimpl.h"
#include "css/cssproperties.h"
#include "css/cssvalues.h"
#include "xml/dom_docimpl.h"
#include "rendering/font.h"
#include "rendering/render_object.h"
#include "rendering/render_canvas.h"
#include <kdebug.h>
#include <QFontDatabase>
#include <QFont>
namespace DOM {
CSSFontFaceSource::CSSFontFaceSource(const DOMString& str, bool distant)
: m_string(str)
, m_font(0)
, m_face(0)
, m_refed(false)
, m_distant(distant)
#if 0
//ENABLE(SVG_FONTS)
, m_svgFontFaceElement(0)
#endif
{
m_id = -1;
}
CSSFontFaceSource::~CSSFontFaceSource()
{
if (m_font) {
if (m_refed)
m_font->deref( this );
if (m_id != -1) {
WTF::Vector<DOMString> names = m_face->familyNames();
unsigned size = names.size();
for (unsigned i = 0; i < size; i++) {
QFont::removeSubstitution( names[i].string() );
khtml::Font::invalidateCachedFontFamily( names[i].string() );
}
QFontDatabase::removeApplicationFont( m_id );
}
}
}
bool CSSFontFaceSource::isLoaded() const
{
if (m_distant)
return m_font? m_font->isLoaded() : false;
return true;
}
bool CSSFontFaceSource::isValid() const
{
if (m_font) {
return !m_font->hadError();
}
return true;
}
void CSSFontFaceSource::notifyFinished(khtml::CachedObject *finishedObj)
{
// Nothing to do if font already added from other src or failed to load
if (m_face->installed() || finishedObj->hadError()) {
return;
}
WTF::Vector<DOMString> names = m_face->familyNames();
const unsigned size = names.size();
m_id = QFontDatabase::addApplicationFontFromData( m_font->font() );
if (m_id == -1) {
kDebug(6080) << "WARNING: downloaded web font" << (size?names[0].string():QString()) << "was rejected by the font subsystem.";
return;
}
m_face->setInstalled();
QString nativeName = QFontDatabase::applicationFontFamilies( m_id )[0];
for (unsigned i = 0; i < size; i++) {
if (names[i].string() != nativeName) {
QFont::insertSubstitution( names[i].string(), nativeName );
}
khtml::Font::invalidateCachedFontFamily( names[i].string() );
}
if (m_face && m_refed) {
m_face->fontLoaded(this);
}
}
void CSSFontFaceSource::refLoader()
{
if (!m_distant)
return;
if (!m_font) {
assert(m_face);
m_font = m_face->fontSelector()->docLoader()->requestFont(m_string);
}
if (m_font) {
m_font->ref( this );
m_refed = true;
}
}
#if 0
SimpleFontData* CSSFontFaceSource::getFontData(const FontDef& fontDescription, bool syntheticBold, bool syntheticItalic, CSSFontSelector* fontSelector)
{
// If the font hasn't loaded or an error occurred, then we've got nothing.
if (!isValid())
return 0;
#if 0
// ENABLE(SVG_FONTS)
if (!m_font && !m_svgFontFaceElement) {
#else
if (!m_font) {
#endif
FontPlatformData* data = fontCache()->getCachedFontPlatformData(fontDescription, m_string);
SimpleFontData* fontData = fontCache()->getCachedFontData(data);
// We're local. Just return a SimpleFontData from the normal cache.
return fontData;
}
// See if we have a mapping in our FontData cache.
unsigned hashKey = fontDescription.computedPixelSize() << 2 | (syntheticBold ? 2 : 0) | (syntheticItalic ? 1 : 0);
if (SimpleFontData* cachedData = m_fontDataTable.get(hashKey))
return cachedData;
OwnPtr<SimpleFontData> fontData;
// If we are still loading, then we let the system pick a font.
if (isLoaded()) {
if (m_font) {
#if 0
//ENABLE(SVG_FONTS)
if (m_font->isSVGFont()) {
// For SVG fonts parse the external SVG document, and extract the <font> element.
if (!m_font->ensureSVGFontData())
return 0;
if (!m_externalSVGFontElement)
m_externalSVGFontElement = m_font->getSVGFontById(SVGURIReference::getTarget(m_string));
if (!m_externalSVGFontElement)
return 0;
SVGFontFaceElement* fontFaceElement = 0;
// Select first <font-face> child
for (Node* fontChild = m_externalSVGFontElement->firstChild(); fontChild; fontChild = fontChild->nextSibling()) {
if (fontChild->hasTagName(SVGNames::font_faceTag)) {
fontFaceElement = static_cast<SVGFontFaceElement*>(fontChild);
break;
}
}
if (fontFaceElement) {
if (!m_svgFontFaceElement) {
// We're created using a CSS @font-face rule, that means we're not associated with a SVGFontFaceElement.
// Use the imported <font-face> tag as referencing font-face element for these cases.
m_svgFontFaceElement = fontFaceElement;
}
SVGFontData* svgFontData = new SVGFontData(fontFaceElement);
fontData.set(new SimpleFontData(m_font->platformDataFromCustomData(fontDescription.computedPixelSize(), syntheticBold, syntheticItalic, fontDescription.renderingMode()), true, false, svgFontData));
}
} else
#endif
{
// Create new FontPlatformData from our CGFontRef, point size and ATSFontRef.
if (!m_font->ensureCustomFontData())
return 0;
fontData.set(new SimpleFontData(m_font->platformDataFromCustomData(fontDescription.computedPixelSize(), syntheticBold, syntheticItalic, fontDescription.renderingMode()), true, false));
}
} else {
#if 0
//ENABLE(SVG_FONTS)
// In-Document SVG Fonts
if (m_svgFontFaceElement) {
SVGFontData* svgFontData = new SVGFontData(m_svgFontFaceElement);
fontData.set(new SimpleFontData(FontPlatformData(fontDescription.computedPixelSize(), syntheticBold, syntheticItalic), true, false, svgFontData));
}
#endif
}
} else {
// Kick off the load now.
if (DocLoader* docLoader = fontSelector->docLoader())
m_font->beginLoadIfNeeded(docLoader);
// FIXME: m_string is a URL so it makes no sense to pass it as a family name.
FontPlatformData* tempData = fontCache()->getCachedFontPlatformData(fontDescription, m_string);
if (!tempData)
tempData = fontCache()->getLastResortFallbackFont(fontDescription);
fontData.set(new SimpleFontData(*tempData, true, true));
}
m_fontDataTable.set(hashKey, fontData.get());
return fontData.release();
}
#endif
CSSFontFace::~CSSFontFace()
{
deleteAllValues(m_sources);
}
bool CSSFontFace::isLoaded() const
{
unsigned size = m_sources.size();
for (unsigned i = 0; i < size; i++) {
if (!m_sources[i]->isLoaded())
return false;
}
return true;
}
bool CSSFontFace::isValid() const
{
unsigned size = m_sources.size();
if (!size)
return false;
for (unsigned i = 0; i < size; i++) {
if (m_sources[i]->isValid())
return true;
}
return false;
}
void CSSFontFace::setInstalled()
{
m_installed = true;
}
bool CSSFontFace::installed() const
{
return m_installed;
}
void CSSFontFace::refLoaders()
{
if (m_refed)
return;
unsigned size = m_sources.size();
if (!size)
return;
for (unsigned i = 0; i < size; i++) {
m_sources[i]->refLoader();
}
m_refed = true;
}
void CSSFontFace::addedToSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace)
{
(void) segmentedFontFace;
// m_segmentedFontFaces.add(segmentedFontFace);
}
void CSSFontFace::removedFromSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace)
{
(void) segmentedFontFace;
// m_segmentedFontFaces.remove(segmentedFontFace);
}
void CSSFontFace::addSource(CSSFontFaceSource* source)
{
m_sources.append(source);
source->setFontFace(this);
}
void CSSFontFace::fontLoaded(CSSFontFaceSource*)
{
/*
// FIXME: Can we assert that m_segmentedFontFaces is not empty? That may
// require stopping in-progress font loading when the last
// CSSSegmentedFontFace is removed.
if (m_segmentedFontFaces.isEmpty())
return;
HashSet<CSSSegmentedFontFace*>::iterator end = m_segmentedFontFaces.end();
for (HashSet<CSSSegmentedFontFace*>::iterator it = m_segmentedFontFaces.begin(); it != end; ++it)
(*it)->fontLoaded(this);
// Use one of the CSSSegmentedFontFaces' font selector. They all have
// the same font selector, so it's wasteful to store it in the CSSFontFace.
CSSFontSelector* fontSelector = (*m_segmentedFontFaces.begin())->fontSelector();
*/
m_fontSelector->fontLoaded();
}
#if 0
SimpleFontData* CSSFontFace::getFontData(const FontDef& fontDescription, bool syntheticBold, bool syntheticItalic)
{
if (!isValid())
return 0;
ASSERT(!m_segmentedFontFaces.isEmpty());
CSSFontSelector* fontSelector = (*m_segmentedFontFaces.begin())->fontSelector();
SimpleFontData* result = 0;
unsigned size = m_sources.size();
for (unsigned i = 0; i < size && !result; i++)
result = m_sources[i]->getFontData(fontDescription, syntheticBold, syntheticItalic, fontSelector);
return result;
}
#endif
CSSFontSelector::CSSFontSelector(DocumentImpl* document)
: m_document(document)
{
assert(m_document);
// fontCache()->addClient(this);
}
CSSFontSelector::~CSSFontSelector()
{
// fontCache()->removeClient(this);
// deleteAllValues(m_fontFaces);
// deleteAllValues(m_locallyInstalledFontFaces);
// deleteAllValues(m_fonts);
QHash<DOMString, CSSFontFace*>::const_iterator cur = m_locallyInstalledFontFaces.constBegin();
QHash<DOMString, CSSFontFace*>::const_iterator end = m_locallyInstalledFontFaces.constEnd();
for (;cur != end; cur++)
cur.value()->deref();
}
bool CSSFontSelector::isEmpty() const
{
return false;
//return m_fonts.isEmpty();
}
khtml::DocLoader* CSSFontSelector::docLoader() const
{
return m_document ? m_document->docLoader() : 0;
}
void CSSFontSelector::addFontFaceRule(const CSSFontFaceRuleImpl* fontFaceRule)
{
// Obtain the font-family property and the src property. Both must be defined.
const CSSStyleDeclarationImpl* style = fontFaceRule->style();
CSSValueImpl* fontFamily = style->getPropertyCSSValue( CSS_PROP_FONT_FAMILY );
CSSValueImpl* src = style->getPropertyCSSValue( CSS_PROP_SRC );
CSSValueImpl* unicodeRange = style->getPropertyCSSValue(CSS_PROP_UNICODE_RANGE);
if (!fontFamily || !src || !fontFamily->isValueList() || !src->isValueList() || (unicodeRange && !unicodeRange->isValueList()))
return;
CSSValueListImpl* familyList = static_cast<CSSValueListImpl*>(fontFamily);
if (!familyList->length())
return;
CSSValueListImpl* srcList = static_cast<CSSValueListImpl*>(src);
if (!srcList->length())
return;
// CSSValueListImpl* rangeList = static_cast<CSSValueListImpl*>(unicodeRange);
unsigned traitsMask = 0;
/*
if (CSSValueImpl* fontStyle = style->getPropertyCSSValue(CSS_PROP_FONT_STYLE)) {
if (fontStyle->isPrimitiveValue()) {
CSSValueListImpl* list = new CSSValueListImpl(CSSValueListImpl::Comma);
list->append(fontStyle);
fontStyle = list;
} else if (!fontStyle->isValueList())
return;
CSSValueListImpl* styleList = static_cast<CSSValueListImpl*>(fontStyle);
unsigned numStyles = styleList->length();
if (!numStyles)
return;
for (unsigned i = 0; i < numStyles; ++i) {
switch (static_cast<CSSPrimitiveValueImpl*>(styleList[i])->getIdent()) {
case CSS_ALL:
traitsMask |= FontStyleMask;
break;
case CSS_NORMAL:
traitsMask |= FontStyleNormalMask;
break;
case CSS_ITALIC:
case CSS_OBLIQUE:
traitsMask |= FontStyleItalicMask;
break;
default:
break;
}
}
} else
traitsMask |= FontStyleMask;
if (CSSValueImpl* fontWeight = style->getPropertyCSSValue(CSS_PROP_FONT_WEIGHT)) {
if (fontWeight->isPrimitiveValue()) {
CSSValueListImpl* list = new CSSValueListImpl(CSSValueListImpl::Comma);
list->append(fontWeight);
fontWeight = list;
} else if (!fontWeight->isValueList())
return;
CSSValueListImpl* weightList = static_cast<CSSValueListImpl*>(fontWeight);
unsigned numWeights = weightList->length();
if (!numWeights)
return;
for (unsigned i = 0; i < numWeights; ++i) {
switch (static_cast<CSSPrimitiveValueImpl*>(weightList[i])->getIdent()) {
case CSS_VAL_ALL:
traitsMask |= FontWeightMask;
break;
case CSS_VAL_BOLDER:
case CSS_VAL_BOLD:
case CSS_VAL_700:
traitsMask |= FontWeight700Mask;
break;
case CSS_VAL_NORMAL:
case CSS_VAL_400:
traitsMask |= FontWeight400Mask;
break;
case CSS_VAL_900:
traitsMask |= FontWeight900Mask;
break;
case CSS_VAL_800:
traitsMask |= FontWeight800Mask;
break;
case CSS_VAL_600:
traitsMask |= FontWeight600Mask;
break;
case CSS_VAL_500:
traitsMask |= FontWeight500Mask;
break;
case CSS_VAL_300:
traitsMask |= FontWeight300Mask;
break;
case CSS_VAL_LIGHTER:
case CSS_VAL_200:
traitsMask |= FontWeight200Mask;
break;
case CSS_VAL_100:
traitsMask |= FontWeight100Mask;
break;
default:
break;
}
}
} else
traitsMask |= FontWeightMask;
if (CSSValueImpl* fontVariant = style->getPropertyCSSValue(CSS_PROP_FONT_VARIANT)) {
if (fontVariant->isPrimitiveValue()) {
CSSValueListImpl* list = new CSSValueListImpl(CSSValueListImpl::Comma);
list->append(fontVariant);
fontVariant = list;
} else if (!fontVariant->isValueList())
return;
CSSValueListImpl* variantList = static_cast<CSSValueListImpl*>(fontVariant);
unsigned numVariants = variantList->length();
if (!numVariants)
return;
for (unsigned i = 0; i < numVariants; ++i) {
switch (static_cast<CSSPrimitiveValueImpl*>(variantList[i])->getIdent()) {
case CSS_VAL_ALL:
traitsMask |= FontVariantMask;
break;
case CSS_VAL_NORMAL:
traitsMask |= FontVariantNormalMask;
break;
case CSS_VAL_SMALL_CAPS:
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;
const int srcLength = srcList->length();
bool foundLocal = false;
#if 0
// ENABLE(SVG_FONTS)
bool foundSVGFont = false;
#endif
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).
CSSFontFaceSrcValueImpl* item = static_cast<CSSFontFaceSrcValueImpl*>(srcList->item(i));
CSSFontFaceSource* source = 0;
#if 0
// ENABLE(SVG_FONTS)
foundSVGFont = item->isSVGFontFaceSrc() || item->svgFontFaceElement();
#endif
if (!item->isLocal()) {
if (item->isSupportedFormat() && m_document) {
source = new CSSFontFaceSource(item->resource(), true /*distant*/);
#if 0
// ENABLE(SVG_FONTS)
if (foundSVGFont)
cachedFont->setSVGFont(true);
#endif
}
} else {
source = new CSSFontFaceSource(item->resource());
foundLocal = true;
}
if (!fontFace)
fontFace = new CSSFontFace( static_cast<FontTraitsMask>(traitsMask), this );
if (source) {
#if 0
// ENABLE(SVG_FONTS)
source->setSVGFontFaceElement(item->svgFontFaceElement());
#endif
fontFace->addSource(source);
}
}
assert(fontFace);
if (fontFace && !fontFace->isValid()) {
delete fontFace;
return;
}
/*
if (rangeList) {
unsigned numRanges = rangeList->length();
for (unsigned i = 0; i < numRanges; i++) {
CSSUnicodeRangeValueImpl* range = static_cast<CSSUnicodeRangeValueImpl*>(rangeList->item(i));
fontFace->addRange(range->from(), range->to());
}
}
*/
// Hash under every single family name.
int familyLength = familyList->length();
for (int i = 0; i < familyLength; i++) {
CSSPrimitiveValueImpl* item = static_cast<CSSPrimitiveValueImpl*>(familyList->item(i));
DOMString familyName;
if (item->primitiveType() == CSSPrimitiveValue::CSS_STRING) {
familyName = DOMString(static_cast<FontFamilyValueImpl*>(item)->fontName());
} 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.
switch (item->getIdent()) {
case CSS_VAL_SERIF:
familyName = "-khtml-serif";
break;
case CSS_VAL_SANS_SERIF:
familyName = "-khtml-sans-serif";
break;
case CSS_VAL_CURSIVE:
familyName = "-khtml-cursive";
break;
case CSS_VAL_FANTASY:
familyName = "-khtml-fantasy";
break;
case CSS_VAL_MONOSPACE:
familyName = "-khtml-monospace";
break;
default:
break;
}
}
if (familyName.isEmpty())
continue;
fontFace->addFamilyName( familyName );
m_locallyInstalledFontFaces.insertMulti( familyName.lower(), fontFace );
fontFace->ref();
#if 0
// 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 && (traitsMask & FontVariantSmallCapsMask))
familyName += "-webkit-svg-small-caps";
#endif
/*
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);
}
}
}
familyFontFaces->append(fontFace);
*/
}
}
void CSSFontSelector::requestFamilyName( const DOMString& familyName )
{
QHash<DOMString, CSSFontFace*>::const_iterator it = m_locallyInstalledFontFaces.constBegin();
QHash<DOMString, CSSFontFace*>::const_iterator end = m_locallyInstalledFontFaces.constEnd();
if (it == end) {
return;
}
const DOMString familyNameLower = familyName.lower();
do {
if (it.key() == familyNameLower) {
it.value()->refLoaders();
}
++it;
} while (it != end);
}
void CSSFontSelector::fontLoaded()
{
if (!m_document || !m_document->renderer())
return;
static_cast<khtml::RenderCanvas*>(m_document->renderer())->updateInvalidatedFonts();
khtml::Font::markAllCachedFontsAsValid();
}
void CSSFontSelector::fontCacheInvalidated()
{
if (!m_document || !m_document->renderer())
return;
m_document->recalcStyle(DocumentImpl::Force);
// m_document->renderer()->setNeedsLayoutAndMinMaxRecalc();
}
/*
static FontData* fontDataForGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName)
{
if (!document || !document->frame())
return 0;
const Settings* settings = document->frame()->settings();
if (!settings)
return 0;
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;
}
*/
static FontTraitsMask desiredTraitsMaskForComparison;
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 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, 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 }
};
unsigned ruleSetIndex = 0;
unsigned w = FontWeight100Bit;
while (!(desiredTraitsMaskForComparison & (1 << w))) {
w++;
ruleSetIndex++;
}
assert(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;
}
/*
FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
{
if (m_fontFaces.isEmpty()) {
if (familyName.startsWith("-khtml-"))
return fontDataForGenericFamily(m_document, fontDescription, familyName);
return 0;
}
String family = familyName.string();
#if 0
// ENABLE(SVG_FONTS)
if (fontDescription.smallCaps())
family += "-khtml-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);
}
*/
}