3df89b481cd3a06c2b5fd2cf853aa0a0f74b15e9
[WebKit-https.git] / WebCore / css / CSSFontSelector.cpp
1 /*
2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3  *           (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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. 
25  */
26
27 #include "config.h"
28
29 #include "CSSFontSelector.h"
30 #include "AtomicString.h"
31 #include "CString.h"
32 #include "CSSFontFace.h"
33 #include "CSSFontFaceRule.h"
34 #include "CSSFontFaceSource.h"
35 #include "CSSFontFaceSrcValue.h"
36 #include "CSSMutableStyleDeclaration.h"
37 #include "CSSPrimitiveValue.h"
38 #include "CSSPropertyNames.h"
39 #include "CSSSegmentedFontFace.h"
40 #include "CSSUnicodeRangeValue.h"
41 #include "CSSValueKeywords.h"
42 #include "CSSValueList.h"
43 #include "DocLoader.h"
44 #include "Document.h"
45 #include "FontCache.h"
46 #include "FontFamilyValue.h"
47 #include "Frame.h"
48 #include "NodeList.h"
49 #include "RenderObject.h"
50 #include "Settings.h"
51 #include "SimpleFontData.h"
52 #include "SVGFontFaceElement.h"
53
54 // Ports which don't use SVG, don't generate SVGNames.h
55 #if ENABLE(SVG)
56 #include "SVGNames.h"
57 #endif
58
59 namespace WebCore {
60
61 CSSFontSelector::CSSFontSelector(Document* document)
62 : m_document(document)
63 {
64     ASSERT(m_document);
65 }
66
67 CSSFontSelector::~CSSFontSelector()
68 {}
69
70 bool CSSFontSelector::isEmpty() const
71 {
72     return m_fonts.isEmpty();
73 }
74
75 DocLoader* CSSFontSelector::docLoader() const
76 {
77     return m_document->docLoader();
78 }
79
80 static String hashForFont(const String& familyName, bool bold, bool italic)
81 {
82     String familyHash(familyName);
83     if (bold)
84         familyHash += "-webkit-bold";
85     if (italic)
86         familyHash += "-webkit-italic";
87     return AtomicString(familyHash);
88 }
89
90 void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
91 {
92     // Obtain the font-family property and the src property.  Both must be defined.
93     const CSSMutableStyleDeclaration* style = fontFaceRule->style();
94     RefPtr<CSSValue> fontFamily = style->getPropertyCSSValue(CSS_PROP_FONT_FAMILY);
95     RefPtr<CSSValue> src = style->getPropertyCSSValue(CSS_PROP_SRC);
96     RefPtr<CSSValue> unicodeRange = style->getPropertyCSSValue(CSS_PROP_UNICODE_RANGE);
97     if (!fontFamily || !src || !fontFamily->isValueList() || !src->isValueList() || unicodeRange && !unicodeRange->isValueList())
98         return;
99
100     CSSValueList* familyList = static_cast<CSSValueList*>(fontFamily.get());
101     if (!familyList->length())
102         return;
103         
104     CSSValueList* srcList = static_cast<CSSValueList*>(src.get());
105     if (!srcList->length())
106         return;
107
108     CSSValueList* rangeList = static_cast<CSSValueList*>(unicodeRange.get());
109
110     // Create a FontDescription for this font and set up bold/italic info properly.
111     FontDescription fontDescription;
112
113     if (RefPtr<CSSValue> fontStyle = style->getPropertyCSSValue(CSS_PROP_FONT_STYLE))
114         fontDescription.setItalic(static_cast<CSSPrimitiveValue*>(fontStyle.get())->getIdent() != CSS_VAL_NORMAL);
115
116     if (RefPtr<CSSValue> fontWeight = style->getPropertyCSSValue(CSS_PROP_FONT_WEIGHT)) {
117         // FIXME: Need to support weights for real, since we're effectively limiting the number of supported weights to two.
118         // This behavior could also result in the "last kinda bold variant" described winning even if it isn't the best match for bold.
119         switch (static_cast<CSSPrimitiveValue*>(fontWeight.get())->getIdent()) {
120             case CSS_VAL_BOLD:
121             case CSS_VAL_BOLDER:
122             case CSS_VAL_600:
123             case CSS_VAL_700:
124             case CSS_VAL_800:
125             case CSS_VAL_900:
126                 fontDescription.setWeight(cBoldWeight);
127             default:
128                 break;
129         }
130     }
131
132     if (RefPtr<CSSValue> fontVariant = style->getPropertyCSSValue(CSS_PROP_FONT_VARIANT))
133         fontDescription.setSmallCaps(static_cast<CSSPrimitiveValue*>(fontVariant.get())->getIdent() == CSS_VAL_SMALL_CAPS);
134
135     // Each item in the src property's list is a single CSSFontFaceSource. Put them all into a CSSFontFace.
136     CSSFontFace* fontFace = 0;
137
138     int i;
139     int srcLength = srcList->length();
140
141     bool foundLocal = false;
142
143 #if ENABLE(SVG_FONTS)
144     bool foundInDocumentSVGFont = false;
145 #endif
146
147     for (i = 0; i < srcLength; i++) {
148         // An item in the list either specifies a string (local font name) or a URL (remote font to download).
149         CSSFontFaceSrcValue* item = static_cast<CSSFontFaceSrcValue*>(srcList->item(i));
150         CSSFontFaceSource* source = 0;
151
152         if (!item->isLocal()) {
153             if (item->isSupportedFormat()) {
154                 CachedFont* cachedFont = m_document->docLoader()->requestFont(item->resource());
155                 if (cachedFont)
156                     source = new CSSFontFaceSource(item->resource(), cachedFont);
157             }
158         } else {
159             String family = item->resource();
160
161 #if ENABLE(SVG_FONTS)
162             foundInDocumentSVGFont = item->svgFontFaceElement() != 0;
163 #endif
164
165             // Test the validity of the local font now.  We don't want to include this font if it does not exist
166             // on the system.  If it *does* exist on the system, then we don't need to look any further.
167             if (FontCache::fontExists(fontDescription, family)
168 #if ENABLE(SVG_FONTS)    
169                 || foundInDocumentSVGFont
170 #endif
171                ) {
172                 source = new CSSFontFaceSource(family);
173 #if ENABLE(SVG_FONTS)
174                 source->setSVGFontFaceElement(item->svgFontFaceElement());
175 #endif
176                 foundLocal = true;
177             }
178         }
179
180         if (!fontFace)
181             fontFace = new CSSFontFace();
182
183         if (source)
184             fontFace->addSource(source);
185
186         // We can just break if we see a local font that is valid.
187         if (foundLocal)
188             break;
189     }
190
191     ASSERT(fontFace);
192
193     if (fontFace && !fontFace->isValid()) {
194         delete fontFace;
195         return;
196     }
197
198     // Hash under every single family name.
199     int familyLength = familyList->length();
200     for (i = 0; i < familyLength; i++) {
201         CSSPrimitiveValue* item = static_cast<CSSPrimitiveValue*>(familyList->item(i));
202         String familyName;
203         if (item->primitiveType() == CSSPrimitiveValue::CSS_STRING)
204             familyName = static_cast<FontFamilyValue*>(item)->fontName();
205         else if (item->primitiveType() == CSSPrimitiveValue::CSS_IDENT) {
206             // We need to use the raw text for all the generic family types, since @font-face is a way of actually
207             // defining what font to use for those types.
208             String familyName;
209             switch (item->getIdent()) {
210                 case CSS_VAL_SERIF:
211                     familyName = "-webkit-serif";
212                     break;
213                 case CSS_VAL_SANS_SERIF:
214                     familyName = "-webkit-sans-serif";
215                     break;
216                 case CSS_VAL_CURSIVE:
217                     familyName = "-webkit-cursive";
218                     break;
219                 case CSS_VAL_FANTASY:
220                     familyName = "-webkit-fantasy";
221                     break;
222                 case CSS_VAL_MONOSPACE:
223                     familyName = "-webkit-monospace";
224                     break;
225                 default:
226                     break;
227             }
228         }
229
230         if (familyName.isEmpty())
231             continue;
232
233 #if ENABLE(SVG_FONTS)
234         // SVG allows several <font> elements with the same font-family, differing only
235         // in ie. font-variant. Be sure to pick up the right one - in getFontData below.
236         if (foundInDocumentSVGFont && fontDescription.smallCaps())
237             familyName += "-webkit-svg-small-caps";
238 #endif
239         String hash = hashForFont(familyName.lower(), fontDescription.bold(), fontDescription.italic());
240         CSSSegmentedFontFace* segmentedFontFace = m_fonts.get(hash).get();
241         if (!segmentedFontFace) {
242             segmentedFontFace = new CSSSegmentedFontFace(this);
243             m_fonts.set(hash, segmentedFontFace);
244         }
245         if (rangeList) {
246             // A local font matching the font description should come first, so that it gets used for
247             // any character not overlaid by explicit @font-face rules for the family.
248             if (!segmentedFontFace->numRanges() && FontCache::fontExists(fontDescription, familyName)) {
249                 CSSFontFace* implicitFontFace = new CSSFontFace();
250                 implicitFontFace->addSource(new CSSFontFaceSource(familyName));
251                 ASSERT(implicitFontFace->isValid());
252                 segmentedFontFace->overlayRange(0, 0x7FFFFFFF, implicitFontFace);
253             }
254
255             unsigned numRanges = rangeList->length();
256             for (unsigned i = 0; i < numRanges; i++) {
257                 CSSUnicodeRangeValue* range = static_cast<CSSUnicodeRangeValue*>(rangeList->item(i));
258                 segmentedFontFace->overlayRange(range->from(), range->to(), fontFace);
259             }
260         } else
261             segmentedFontFace->overlayRange(0, 0x7FFFFFFF, fontFace);
262     }
263 }
264
265 void CSSFontSelector::fontLoaded(CSSSegmentedFontFace*)
266 {
267     if (m_document->inPageCache())
268         return;
269     m_document->recalcStyle(Document::Force);
270     m_document->renderer()->setNeedsLayoutAndPrefWidthsRecalc();
271 }
272
273 FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
274 {
275     if (m_fonts.isEmpty() && !familyName.startsWith("-webkit-"))
276         return 0;
277     
278     bool bold = fontDescription.bold();
279     bool italic = fontDescription.italic();
280     
281     bool syntheticBold = false;
282     bool syntheticItalic = false;
283
284     String family = familyName.domString().lower();
285
286 #if ENABLE(SVG_FONTS)
287     RefPtr<CSSSegmentedFontFace> face;
288
289     if (fontDescription.smallCaps()) {
290         String testFamily = family + "-webkit-svg-small-caps";
291         face = m_fonts.get(hashForFont(testFamily, bold, italic));
292     } else
293         face = m_fonts.get(hashForFont(family, bold, italic));
294 #else
295     RefPtr<CSSSegmentedFontFace> face = m_fonts.get(hashForFont(family, bold, italic));
296 #endif
297
298     // If we don't find a face, and if bold/italic are set, we should try other variants.
299     // Bold/italic should try bold first, then italic, then normal (on the assumption that we are better at synthesizing italic than we are
300     // at synthesizing bold).
301     if (!face) {
302         if (bold && italic) {
303             syntheticItalic = true;
304             face = m_fonts.get(hashForFont(family, bold, false));
305             if (!face) {
306                 syntheticBold = true;
307                 face = m_fonts.get(hashForFont(family, false, italic));
308             }
309         }
310         
311         // Bold should try normal.
312         // Italic should try normal.
313         if (!face && (bold || italic)) {
314             syntheticBold = bold;
315             syntheticItalic = italic;
316             face = m_fonts.get(hashForFont(family, false, false));
317         }
318     }
319
320 #if ENABLE(SVG_FONTS)
321     // If no face was found, and if we're a SVG Font we may have hit following case:
322     // <font-face> specified font-weight and/or font-style to be ie. bold and italic.
323     // And the font-family requested is non-bold & non-italic. For SVG Fonts we still
324     // have to return the defined font, and not fallback to the system default.
325     if (!face && !bold)
326         face = m_fonts.get(hashForFont(family, true, italic));
327
328     if (!face && !italic)
329         face = m_fonts.get(hashForFont(family, bold, true));
330
331     if (!face && !bold && !italic)
332         face = m_fonts.get(hashForFont(family, true, true));
333 #endif
334
335     // If no face was found, then return 0 and let the OS come up with its best match for the name.
336     if (!face) {
337         // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our
338         // settings.
339         const Settings* settings = m_document->frame()->settings();
340         AtomicString genericFamily;
341         if (familyName == "-webkit-serif")
342             genericFamily = settings->serifFontFamily();
343         else if (familyName == "-webkit-sans-serif")
344             genericFamily = settings->sansSerifFontFamily();
345         else if (familyName == "-webkit-cursive")
346             genericFamily = settings->cursiveFontFamily();
347         else if (familyName == "-webkit-fantasy")
348             genericFamily = settings->fantasyFontFamily();
349         else if (familyName == "-webkit-monospace")
350             genericFamily = settings->fixedFontFamily();
351         else if (familyName == "-webkit-standard")
352             genericFamily = settings->standardFontFamily();
353         
354         if (!genericFamily.isEmpty())
355             return FontCache::getCachedFontData(FontCache::getCachedFontPlatformData(fontDescription, genericFamily));
356         return 0;
357     }
358
359     // We have a face.  Ask it for a font data.  If it cannot produce one, it will fail, and the OS will take over.
360     return face->getFontData(fontDescription, syntheticBold, syntheticItalic);
361 }
362
363 }