Make svn-apply/svn-unapply work with patches from git-format-patch.
[WebKit-https.git] / WebCore / css / CSSFontSelector.cpp
1 /*
2  * Copyright (C) 2007 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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. 
24  */
25
26 #include "config.h"
27 #include "CSSFontSelector.h"
28
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"
40 #include "Document.h"
41 #include "FontCache.h"
42 #include "FontFamilyValue.h"
43 #include "Frame.h"
44 #include "RenderObject.h"
45 #include "Settings.h"
46
47 namespace WebCore {
48
49 CSSFontSelector::CSSFontSelector(Document* document)
50 : m_document(document)
51 {
52     ASSERT(m_document);
53 }
54
55 CSSFontSelector::~CSSFontSelector()
56 {}
57
58 bool CSSFontSelector::isEmpty() const
59 {
60     return m_fonts.isEmpty();
61 }
62
63 DocLoader* CSSFontSelector::docLoader() const
64 {
65     return m_document->docLoader();
66 }
67
68 static String hashForFont(const String& familyName, bool bold, bool italic)
69 {
70     String familyHash(familyName);
71     if (bold)
72         familyHash += "-webkit-bold";
73     if (italic)
74         familyHash += "-webkit-italic";
75     return AtomicString(familyHash);
76 }
77
78 void CSSFontSelector::addFontFaceRule(const CSSFontFaceRule* fontFaceRule)
79 {
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())
85         return;
86
87     CSSValueList* familyList = static_cast<CSSValueList*>(fontFamily.get());
88     if (!familyList->length())
89         return;
90         
91     CSSValueList* srcList = static_cast<CSSValueList*>(src.get());
92     if (!srcList->length())
93         return;
94
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);
100     if (fontWeight) {
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()) {
104             case CSS_VAL_BOLD:
105             case CSS_VAL_BOLDER:
106             case CSS_VAL_600:
107             case CSS_VAL_700:
108             case CSS_VAL_800:
109             case CSS_VAL_900:
110                 fontDescription.setWeight(cBoldWeight);
111             default:
112                 break;
113         }
114     }
115     
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);
118     
119     int i;
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());
129                 if (cachedFont)
130                     source = new CSSFontFaceSource(item->resource(), cachedFont);
131             }
132         } else {
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);
138                 foundLocal = true;
139             }
140         }
141
142         if (source)
143             fontFace->addSource(source);
144         
145         // We can just break if we see a local font that is valid.
146         if (foundLocal)
147             break;
148     }
149     
150     if (!fontFace->isValid()) {
151         delete fontFace;
152         return;
153     }
154
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));
159         String familyName;
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.
165             String familyName;
166             switch (item->getIdent()) {
167                 case CSS_VAL_SERIF:
168                     familyName = "-webkit-serif";
169                     break;
170                 case CSS_VAL_SANS_SERIF:
171                     familyName = "-webkit-sans-serif";
172                     break;
173                 case CSS_VAL_CURSIVE:
174                     familyName = "-webkit-cursive";
175                     break;
176                 case CSS_VAL_FANTASY:
177                     familyName = "-webkit-fantasy";
178                     break;
179                 case CSS_VAL_MONOSPACE:
180                     familyName = "-webkit-monospace";
181                     break;
182                 default:
183                     break;
184             }
185         }
186         
187         if (!familyName.isEmpty())
188             m_fonts.set(hashForFont(familyName.lower(), fontDescription.bold(), fontDescription.italic()), fontFace);
189     }
190 }
191
192 void CSSFontSelector::fontLoaded(CSSFontFace*)
193 {
194     if (m_document->inPageCache())
195         return;
196     m_document->recalcStyle(Document::Force);
197     m_document->renderer()->setNeedsLayoutAndPrefWidthsRecalc();
198 }
199
200 FontData* CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName)
201 {
202     if (m_fonts.isEmpty())
203         return 0;
204     
205     bool bold = fontDescription.bold();
206     bool italic = fontDescription.italic();
207     
208     bool syntheticBold = false;
209     bool syntheticItalic = false;
210
211     String family = familyName.domString().lower();
212     
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).
217     if (!face) {
218         if (bold && italic) {
219             syntheticItalic = true;
220             face = m_fonts.get(hashForFont(family, bold, false));
221             if (!face) {
222                 syntheticBold = true;
223                 face = m_fonts.get(hashForFont(family, false, italic));
224             }
225         }
226         
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));
233         }
234     }
235     
236     // If no face was found, then return 0 and let the OS come up with its best match for the name.
237     if (!face) {
238         // If we were handed a generic family, but there was no match, go ahead and return the correct font based off our
239         // settings.
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->cursiveFontFamily();
250         else if (familyName == "-webkit-monospace")
251             genericFamily = settings->fixedFontFamily();
252         
253         if (!genericFamily.isEmpty())
254             return FontCache::getCachedFontData(FontCache::getCachedFontPlatformData(fontDescription, genericFamily));
255         return 0;
256     }
257
258     // We have a face.  Ask it for a font data.  If it cannot produce one, it will fail, and the OS will take over.
259     return face->getFontData(fontDescription, syntheticBold, syntheticItalic);
260 }
261
262 }