2 * Copyright (C) 2007 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "CSSFontSelector.h"
29 #include "AtomicString.h"
30 #include "CSSFontFace.h"
31 #include "CSSFontFaceRule.h"
32 #include "CSSFontFaceSource.h"
33 #include "CSSFontFaceSrcValue.h"
34 #include "CSSMutableStyleDeclaration.h"
35 #include "CSSPrimitiveValue.h"
36 #include "CSSPropertyNames.h"
37 #include "CSSValueKeywords.h"
38 #include "CSSValueList.h"
39 #include "DocLoader.h"
41 #include "FontCache.h"
42 #include "FontFamilyValue.h"
44 #include "RenderObject.h"
49 CSSFontSelector::CSSFontSelector(Document* document)
50 : m_document(document)
55 CSSFontSelector::~CSSFontSelector()
58 bool CSSFontSelector::isEmpty() const
60 return m_fonts.isEmpty();
63 DocLoader* CSSFontSelector::docLoader() const
65 return m_document->docLoader();
68 static String hashForFont(const String& familyName, bool bold, bool italic)
70 String familyHash(familyName);
72 familyHash += "-webkit-bold";
74 familyHash += "-webkit-italic";
75 return AtomicString(familyHash);
78 void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
80 // Obtain the font-family property and the src property. Both must be defined.
81 const CSSMutableStyleDeclaration* style = fontFaceRule->style();
82 RefPtr<CSSValue> fontFamily = style->getPropertyCSSValue(CSS_PROP_FONT_FAMILY);
83 RefPtr<CSSValue> src = style->getPropertyCSSValue(CSS_PROP_SRC);
84 if (!fontFamily || !src || !fontFamily->isValueList() || !src->isValueList())
87 CSSValueList* familyList = static_cast<CSSValueList*>(fontFamily.get());
88 if (!familyList->length())
91 CSSValueList* srcList = static_cast<CSSValueList*>(src.get());
92 if (!srcList->length())
95 // Create a FontDescription for this font and set up bold/italic info properly.
96 FontDescription fontDescription;
97 RefPtr<CSSValue> fontWeight = style->getPropertyCSSValue(CSS_PROP_FONT_WEIGHT);
98 RefPtr<CSSValue> fontStyle = style->getPropertyCSSValue(CSS_PROP_FONT_STYLE);
99 fontDescription.setItalic(fontStyle.get() && static_cast<CSSPrimitiveValue*>(fontStyle.get())->getIdent() != CSS_VAL_NORMAL);
101 // FIXME: Need to support weights for real, since we're effectively limiting the number of supported weights to two.
102 // This behavior could also result in the "last kinda bold variant" described winning even if it isn't the best match for bold.
103 switch (static_cast<CSSPrimitiveValue*>(fontWeight.get())->getIdent()) {
110 fontDescription.setWeight(cBoldWeight);
116 // Each item in the src property's list is a single CSSFontFaceSource. Put them all into a CSSFontFace.
117 CSSFontFace* fontFace = new CSSFontFace(this);
120 int srcLength = srcList->length();
121 bool foundLocal = false;
122 for (i = 0; i < srcLength; i++) {
123 // An item in the list either specifies a string (local font name) or a URL (remote font to download).
124 CSSFontFaceSrcValue* item = static_cast<CSSFontFaceSrcValue*>(srcList->item(i));
125 CSSFontFaceSource* source = 0;
126 if (!item->isLocal()) {
127 if (item->isSupportedFormat()) {
128 CachedFont* cachedFont = m_document->docLoader()->requestFont(item->resource());
130 source = new CSSFontFaceSource(item->resource(), cachedFont);
133 // Test the validity of the local font now. We don't want to include this font if it does not exist
134 // on the system. If it *does* exist on the system, then we don't need to look any further.
135 String family = item->resource();
136 if (FontCache::fontExists(fontDescription, family)) {
137 source = new CSSFontFaceSource(family);
143 fontFace->addSource(source);
145 // We can just break if we see a local font that is valid.
150 if (!fontFace->isValid()) {
155 // Hash under every single family name.
156 int familyLength = familyList->length();
157 for (i = 0; i < familyLength; i++) {
158 CSSPrimitiveValue* item = static_cast<CSSPrimitiveValue*>(familyList->item(i));
160 if (item->primitiveType() == CSSPrimitiveValue::CSS_STRING)
161 familyName = static_cast<FontFamilyValue*>(item)->fontName();
162 else if (item->primitiveType() == CSSPrimitiveValue::CSS_IDENT) {
163 // We need to use the raw text for all the generic family types, since @font-face is a way of actually
164 // defining what font to use for those types.
166 switch (item->getIdent()) {
168 familyName = "-webkit-serif";
170 case CSS_VAL_SANS_SERIF:
171 familyName = "-webkit-sans-serif";
173 case CSS_VAL_CURSIVE:
174 familyName = "-webkit-cursive";
176 case CSS_VAL_FANTASY:
177 familyName = "-webkit-fantasy";
179 case CSS_VAL_MONOSPACE:
180 familyName = "-webkit-monospace";
187 if (!familyName.isEmpty())
188 m_fonts.set(hashForFont(familyName.lower(), fontDescription.bold(), fontDescription.italic()), fontFace);
192 void CSSFontSelector::fontLoaded(CSSFontFace*)
194 if (m_document->inPageCache())
196 m_document->recalcStyle(Document::Force);
197 m_document->renderer()->setNeedsLayoutAndPrefWidthsRecalc();
200 FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
202 if (m_fonts.isEmpty() && !familyName.startsWith("-webkit-"))
205 bool bold = fontDescription.bold();
206 bool italic = fontDescription.italic();
208 bool syntheticBold = false;
209 bool syntheticItalic = false;
211 String family = familyName.domString().lower();
213 RefPtr<CSSFontFace> face = m_fonts.get(hashForFont(family, bold, italic));
214 // If we don't find a face, and if bold/italic are set, we should try other variants.
215 // Bold/italic should try bold first, then italic, then normal (on the assumption that we are better at synthesizing italic than we are
216 // at synthesizing bold).
218 if (bold && italic) {
219 syntheticItalic = true;
220 face = m_fonts.get(hashForFont(family, bold, false));
222 syntheticBold = true;
223 face = m_fonts.get(hashForFont(family, false, italic));
227 // Bold should try normal.
228 // Italic should try normal.
229 if (!face && (bold || italic)) {
230 syntheticBold = bold;
231 syntheticItalic = italic;
232 face = m_fonts.get(hashForFont(family, false, false));
236 // If no face was found, then return 0 and let the OS come up with its best match for the name.
238 // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our
240 const Settings* settings = m_document->frame()->settings();
241 AtomicString genericFamily;
242 if (familyName == "-webkit-serif")
243 genericFamily = settings->serifFontFamily();
244 else if (familyName == "-webkit-sans-serif")
245 genericFamily = settings->sansSerifFontFamily();
246 else if (familyName == "-webkit-cursive")
247 genericFamily = settings->cursiveFontFamily();
248 else if (familyName == "-webkit-fantasy")
249 genericFamily = settings->fantasyFontFamily();
250 else if (familyName == "-webkit-monospace")
251 genericFamily = settings->fixedFontFamily();
252 else if (familyName == "-webkit-standard")
253 genericFamily = settings->standardFontFamily();
255 if (!genericFamily.isEmpty())
256 return FontCache::getCachedFontData(FontCache::getCachedFontPlatformData(fontDescription, genericFamily));
260 // We have a face. Ask it for a font data. If it cannot produce one, it will fail, and the OS will take over.
261 return face->getFontData(fontDescription, syntheticBold, syntheticItalic);