2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 * (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "CSSFontSelector.h"
30 #include "CachedFont.h"
31 #include "CSSFontFace.h"
32 #include "CSSFontFaceRule.h"
33 #include "CSSFontFaceSource.h"
34 #include "CSSFontFaceSrcValue.h"
35 #include "CSSMutableStyleDeclaration.h"
36 #include "CSSPrimitiveValue.h"
37 #include "CSSPropertyNames.h"
38 #include "CSSSegmentedFontFace.h"
39 #include "CSSUnicodeRangeValue.h"
40 #include "CSSValueKeywords.h"
41 #include "CSSValueList.h"
42 #include "CachedResourceLoader.h"
44 #include "FontCache.h"
45 #include "FontFamilyValue.h"
47 #include "RenderObject.h"
49 #include "SimpleFontData.h"
50 #include "WebKitFontFamilyNames.h"
51 #include <wtf/text/AtomicString.h>
54 #include "SVGFontFaceElement.h"
60 CSSFontSelector::CSSFontSelector(Document* document)
61 : m_document(document)
63 // FIXME: An old comment used to say there was no need to hold a reference to m_document
64 // because "we are guaranteed to be destroyed before the document". But there does not
65 // seem to be any such guarantee.
68 fontCache()->addClient(this);
71 CSSFontSelector::~CSSFontSelector()
73 fontCache()->removeClient(this);
74 deleteAllValues(m_fontFaces);
75 deleteAllValues(m_locallyInstalledFontFaces);
76 deleteAllValues(m_fonts);
79 bool CSSFontSelector::isEmpty() const
81 return m_fonts.isEmpty();
84 CachedResourceLoader* CSSFontSelector::cachedResourceLoader() const
86 return m_document ? m_document->cachedResourceLoader() : 0;
89 void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
91 // Obtain the font-family property and the src property. Both must be defined.
92 const CSSMutableStyleDeclaration* style = fontFaceRule->style();
93 RefPtr<CSSValue> fontFamily = style->getPropertyCSSValue(CSSPropertyFontFamily);
94 RefPtr<CSSValue> src = style->getPropertyCSSValue(CSSPropertySrc);
95 RefPtr<CSSValue> unicodeRange = style->getPropertyCSSValue(CSSPropertyUnicodeRange);
96 if (!fontFamily || !src || !fontFamily->isValueList() || !src->isValueList() || (unicodeRange && !unicodeRange->isValueList()))
99 CSSValueList* familyList = static_cast<CSSValueList*>(fontFamily.get());
100 if (!familyList->length())
103 CSSValueList* srcList = static_cast<CSSValueList*>(src.get());
104 if (!srcList->length())
107 CSSValueList* rangeList = static_cast<CSSValueList*>(unicodeRange.get());
109 unsigned traitsMask = 0;
111 if (RefPtr<CSSValue> fontStyle = style->getPropertyCSSValue(CSSPropertyFontStyle)) {
112 if (fontStyle->isPrimitiveValue()) {
113 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
114 list->append(fontStyle);
116 } else if (!fontStyle->isValueList())
119 CSSValueList* styleList = static_cast<CSSValueList*>(fontStyle.get());
120 unsigned numStyles = styleList->length();
124 for (unsigned i = 0; i < numStyles; ++i) {
125 switch (static_cast<CSSPrimitiveValue*>(styleList->itemWithoutBoundsCheck(i))->getIdent()) {
127 traitsMask |= FontStyleMask;
130 traitsMask |= FontStyleNormalMask;
133 case CSSValueOblique:
134 traitsMask |= FontStyleItalicMask;
141 traitsMask |= FontStyleMask;
143 if (RefPtr<CSSValue> fontWeight = style->getPropertyCSSValue(CSSPropertyFontWeight)) {
144 if (fontWeight->isPrimitiveValue()) {
145 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
146 list->append(fontWeight);
148 } else if (!fontWeight->isValueList())
151 CSSValueList* weightList = static_cast<CSSValueList*>(fontWeight.get());
152 unsigned numWeights = weightList->length();
156 for (unsigned i = 0; i < numWeights; ++i) {
157 switch (static_cast<CSSPrimitiveValue*>(weightList->itemWithoutBoundsCheck(i))->getIdent()) {
159 traitsMask |= FontWeightMask;
164 traitsMask |= FontWeight700Mask;
168 traitsMask |= FontWeight400Mask;
171 traitsMask |= FontWeight900Mask;
174 traitsMask |= FontWeight800Mask;
177 traitsMask |= FontWeight600Mask;
180 traitsMask |= FontWeight500Mask;
183 traitsMask |= FontWeight300Mask;
185 case CSSValueLighter:
187 traitsMask |= FontWeight200Mask;
190 traitsMask |= FontWeight100Mask;
197 traitsMask |= FontWeightMask;
199 if (RefPtr<CSSValue> fontVariant = style->getPropertyCSSValue(CSSPropertyFontVariant)) {
200 if (fontVariant->isPrimitiveValue()) {
201 RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
202 list->append(fontVariant);
204 } else if (!fontVariant->isValueList())
207 CSSValueList* variantList = static_cast<CSSValueList*>(fontVariant.get());
208 unsigned numVariants = variantList->length();
212 for (unsigned i = 0; i < numVariants; ++i) {
213 switch (static_cast<CSSPrimitiveValue*>(variantList->itemWithoutBoundsCheck(i))->getIdent()) {
215 traitsMask |= FontVariantMask;
218 traitsMask |= FontVariantNormalMask;
220 case CSSValueSmallCaps:
221 traitsMask |= FontVariantSmallCapsMask;
228 traitsMask |= FontVariantMask;
230 // Each item in the src property's list is a single CSSFontFaceSource. Put them all into a CSSFontFace.
231 RefPtr<CSSFontFace> fontFace;
233 int srcLength = srcList->length();
235 bool foundSVGFont = false;
237 for (int i = 0; i < srcLength; i++) {
238 // An item in the list either specifies a string (local font name) or a URL (remote font to download).
239 CSSFontFaceSrcValue* item = static_cast<CSSFontFaceSrcValue*>(srcList->itemWithoutBoundsCheck(i));
240 CSSFontFaceSource* source = 0;
242 #if ENABLE(SVG_FONTS)
243 foundSVGFont = item->isSVGFontFaceSrc() || item->svgFontFaceElement();
245 if (!item->isLocal()) {
246 Settings* settings = m_document ? m_document->frame() ? m_document->frame()->settings() : 0 : 0;
247 bool allowDownloading = foundSVGFont || (settings && settings->downloadableBinaryFontsEnabled());
248 if (allowDownloading && item->isSupportedFormat() && m_document) {
249 ResourceRequest request(m_document->completeURL(item->resource()));
250 CachedFont* cachedFont = m_document->cachedResourceLoader()->requestFont(request);
252 source = new CSSFontFaceSource(item->resource(), cachedFont);
253 #if ENABLE(SVG_FONTS)
255 source->setHasExternalSVGFont(true);
260 source = new CSSFontFaceSource(item->resource());
264 fontFace = CSSFontFace::create(static_cast<FontTraitsMask>(traitsMask));
267 #if ENABLE(SVG_FONTS)
268 source->setSVGFontFaceElement(item->svgFontFaceElement());
270 fontFace->addSource(source);
276 if (fontFace && !fontFace->isValid())
280 unsigned numRanges = rangeList->length();
281 for (unsigned i = 0; i < numRanges; i++) {
282 CSSUnicodeRangeValue* range = static_cast<CSSUnicodeRangeValue*>(rangeList->itemWithoutBoundsCheck(i));
283 fontFace->addRange(range->from(), range->to());
287 // Hash under every single family name.
288 int familyLength = familyList->length();
289 for (int i = 0; i < familyLength; i++) {
290 CSSPrimitiveValue* item = static_cast<CSSPrimitiveValue*>(familyList->itemWithoutBoundsCheck(i));
292 if (item->primitiveType() == CSSPrimitiveValue::CSS_STRING)
293 familyName = static_cast<FontFamilyValue*>(item)->familyName();
294 else if (item->primitiveType() == CSSPrimitiveValue::CSS_IDENT) {
295 // We need to use the raw text for all the generic family types, since @font-face is a way of actually
296 // defining what font to use for those types.
298 switch (item->getIdent()) {
300 familyName = serifFamily;
302 case CSSValueSansSerif:
303 familyName = sansSerifFamily;
305 case CSSValueCursive:
306 familyName = cursiveFamily;
308 case CSSValueFantasy:
309 familyName = fantasyFamily;
311 case CSSValueMonospace:
312 familyName = monospaceFamily;
314 case CSSValueWebkitPictograph:
315 familyName = pictographFamily;
322 if (familyName.isEmpty())
325 Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(familyName);
326 if (!familyFontFaces) {
327 familyFontFaces = new Vector<RefPtr<CSSFontFace> >;
328 m_fontFaces.set(familyName, familyFontFaces);
330 ASSERT(!m_locallyInstalledFontFaces.contains(familyName));
331 Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFaces;
333 Vector<unsigned> locallyInstalledFontsTraitsMasks;
334 fontCache()->getTraitsInFamily(familyName, locallyInstalledFontsTraitsMasks);
335 unsigned numLocallyInstalledFaces = locallyInstalledFontsTraitsMasks.size();
336 if (numLocallyInstalledFaces) {
337 familyLocallyInstalledFaces = new Vector<RefPtr<CSSFontFace> >;
338 m_locallyInstalledFontFaces.set(familyName, familyLocallyInstalledFaces);
340 for (unsigned i = 0; i < numLocallyInstalledFaces; ++i) {
341 RefPtr<CSSFontFace> locallyInstalledFontFace = CSSFontFace::create(static_cast<FontTraitsMask>(locallyInstalledFontsTraitsMasks[i]), true);
342 locallyInstalledFontFace->addSource(new CSSFontFaceSource(familyName));
343 ASSERT(locallyInstalledFontFace->isValid());
344 familyLocallyInstalledFaces->append(locallyInstalledFontFace);
349 familyFontFaces->append(fontFace);
353 void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient* client)
355 m_clients.add(client);
358 void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient* client)
360 m_clients.remove(client);
363 void CSSFontSelector::dispatchInvalidationCallbacks()
365 Vector<FontSelectorClient*> clients;
366 copyToVector(m_clients, clients);
367 for (size_t i = 0; i < clients.size(); ++i)
368 clients[i]->fontsNeedUpdate(this);
370 // FIXME: Make Document a FontSelectorClient so that it can simply register for invalidation callbacks.
371 if (!m_document || m_document->inPageCache() || !m_document->renderer())
373 m_document->scheduleForcedStyleRecalc();
376 void CSSFontSelector::fontLoaded()
378 dispatchInvalidationCallbacks();
381 void CSSFontSelector::fontCacheInvalidated()
383 dispatchInvalidationCallbacks();
386 void CSSFontSelector::retireCustomFont(FontData* fontData)
389 m_document->retireCustomFont(fontData);
391 GlyphPageTreeNode::pruneTreeCustomFontData(fontData);
396 static FontData* fontDataForGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName)
398 if (!document || !document->frame())
401 const Settings* settings = document->frame()->settings();
405 AtomicString genericFamily;
406 UScriptCode script = fontDescription.script();
408 if (familyName == serifFamily)
409 genericFamily = settings->serifFontFamily(script);
410 else if (familyName == sansSerifFamily)
411 genericFamily = settings->sansSerifFontFamily(script);
412 else if (familyName == cursiveFamily)
413 genericFamily = settings->cursiveFontFamily(script);
414 else if (familyName == fantasyFamily)
415 genericFamily = settings->fantasyFontFamily(script);
416 else if (familyName == monospaceFamily)
417 genericFamily = settings->fixedFontFamily(script);
418 else if (familyName == pictographFamily)
419 genericFamily = settings->pictographFontFamily(script);
420 else if (familyName == standardFamily)
421 genericFamily = settings->standardFontFamily(script);
423 if (!genericFamily.isEmpty())
424 return fontCache()->getCachedFontData(fontDescription, genericFamily);
429 static FontTraitsMask desiredTraitsMaskForComparison;
431 static inline bool compareFontFaces(CSSFontFace* first, CSSFontFace* second)
433 FontTraitsMask firstTraitsMask = first->traitsMask();
434 FontTraitsMask secondTraitsMask = second->traitsMask();
436 bool firstHasDesiredVariant = firstTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
437 bool secondHasDesiredVariant = secondTraitsMask & desiredTraitsMaskForComparison & FontVariantMask;
439 if (firstHasDesiredVariant != secondHasDesiredVariant)
440 return firstHasDesiredVariant;
442 if ((desiredTraitsMaskForComparison & FontVariantSmallCapsMask) && !first->isLocalFallback() && !second->isLocalFallback()) {
443 // Prefer a font that has indicated that it can only support small-caps to a font that claims to support
444 // all variants. The specialized font is more likely to be true small-caps and not require synthesis.
445 bool firstRequiresSmallCaps = (firstTraitsMask & FontVariantSmallCapsMask) && !(firstTraitsMask & FontVariantNormalMask);
446 bool secondRequiresSmallCaps = (secondTraitsMask & FontVariantSmallCapsMask) && !(secondTraitsMask & FontVariantNormalMask);
447 if (firstRequiresSmallCaps != secondRequiresSmallCaps)
448 return firstRequiresSmallCaps;
451 bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
452 bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask;
454 if (firstHasDesiredStyle != secondHasDesiredStyle)
455 return firstHasDesiredStyle;
457 if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first->isLocalFallback() && !second->isLocalFallback()) {
458 // Prefer a font that has indicated that it can only support italics to a font that claims to support
459 // all styles. The specialized font is more likely to be the one the author wants used.
460 bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask);
461 bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask);
462 if (firstRequiresItalics != secondRequiresItalics)
463 return firstRequiresItalics;
466 if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
468 if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask)
471 // 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
472 // 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',
473 // '700', '800', or '900' remains unassigned, they are assigned to the same face as the next darker assigned keyword, if any, or the next
474 // lighter one otherwise. If any of '300', '200', or '100' remains unassigned, it is assigned to the next lighter assigned keyword, if any,
475 // or the next darker otherwise."
476 // For '400', we made up our own rule (which then '500' follows).
478 static const unsigned fallbackRuleSets = 9;
479 static const unsigned rulesPerSet = 8;
480 static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = {
481 { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
482 { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
483 { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask },
484 { FontWeight500Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask },
485 { FontWeight400Mask, FontWeight300Mask, FontWeight600Mask, FontWeight200Mask, FontWeight700Mask, FontWeight100Mask, FontWeight800Mask, FontWeight900Mask },
486 { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
487 { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
488 { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask },
489 { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }
492 unsigned ruleSetIndex = 0;
493 unsigned w = FontWeight100Bit;
494 while (!(desiredTraitsMaskForComparison & (1 << w))) {
499 ASSERT(ruleSetIndex < fallbackRuleSets);
500 const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex];
501 for (unsigned i = 0; i < rulesPerSet; ++i) {
502 if (secondTraitsMask & weightFallbackRule[i])
504 if (firstTraitsMask & weightFallbackRule[i])
511 FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
513 if (m_fontFaces.isEmpty()) {
514 if (familyName.startsWith("-webkit-"))
515 return fontDataForGenericFamily(m_document, fontDescription, familyName);
516 if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont())
517 return fontDataForGenericFamily(m_document, fontDescription, "-webkit-standard");
521 String family = familyName.string();
523 Vector<RefPtr<CSSFontFace> >* familyFontFaces = m_fontFaces.get(family);
524 // If no face was found, then return 0 and let the OS come up with its best match for the name.
525 if (!familyFontFaces || familyFontFaces->isEmpty()) {
526 // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our
528 if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont())
529 return fontDataForGenericFamily(m_document, fontDescription, "-webkit-standard");
530 return fontDataForGenericFamily(m_document, fontDescription, familyName);
533 HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >* segmentedFontFaceCache = m_fonts.get(family);
534 if (!segmentedFontFaceCache) {
535 segmentedFontFaceCache = new HashMap<unsigned, RefPtr<CSSSegmentedFontFace> >;
536 m_fonts.set(family, segmentedFontFaceCache);
539 FontTraitsMask traitsMask = fontDescription.traitsMask();
541 RefPtr<CSSSegmentedFontFace> face = segmentedFontFaceCache->get(traitsMask);
544 face = CSSSegmentedFontFace::create(this);
545 segmentedFontFaceCache->set(traitsMask, face);
546 // Collect all matching faces and sort them in order of preference.
547 Vector<CSSFontFace*, 32> candidateFontFaces;
548 for (int i = familyFontFaces->size() - 1; i >= 0; --i) {
549 CSSFontFace* candidate = familyFontFaces->at(i).get();
550 unsigned candidateTraitsMask = candidate->traitsMask();
551 if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
553 if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
555 #if ENABLE(SVG_FONTS)
556 // For SVG Fonts that specify that they only support the "normal" variant, we will assume they are incapable
557 // of small-caps synthesis and just ignore the font face as a candidate.
558 if (candidate->hasSVGFontFaceSource() && (traitsMask & FontVariantSmallCapsMask) && !(candidateTraitsMask & FontVariantSmallCapsMask))
561 candidateFontFaces.append(candidate);
564 if (Vector<RefPtr<CSSFontFace> >* familyLocallyInstalledFontFaces = m_locallyInstalledFontFaces.get(family)) {
565 unsigned numLocallyInstalledFontFaces = familyLocallyInstalledFontFaces->size();
566 for (unsigned i = 0; i < numLocallyInstalledFontFaces; ++i) {
567 CSSFontFace* candidate = familyLocallyInstalledFontFaces->at(i).get();
568 unsigned candidateTraitsMask = candidate->traitsMask();
569 if ((traitsMask & FontStyleNormalMask) && !(candidateTraitsMask & FontStyleNormalMask))
571 if ((traitsMask & FontVariantNormalMask) && !(candidateTraitsMask & FontVariantNormalMask))
573 candidateFontFaces.append(candidate);
577 desiredTraitsMaskForComparison = traitsMask;
578 std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), compareFontFaces);
579 unsigned numCandidates = candidateFontFaces.size();
580 for (unsigned i = 0; i < numCandidates; ++i)
581 face->appendFontFace(candidateFontFaces[i]);
584 // We have a face. Ask it for a font data. If it cannot produce one, it will fail, and the OS will take over.
585 return face->getFontData(fontDescription);