552e99cfa1e1eaaa4aa3269590038daaa5a02017
[WebKit-https.git] / Source / WebCore / css / CSSFontFace.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2011, 2013 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 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 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 "CSSFontFace.h"
28
29 #include "CSSFontFaceSource.h"
30 #include "CSSFontFamily.h"
31 #include "CSSFontFeatureValue.h"
32 #include "CSSFontSelector.h"
33 #include "CSSPrimitiveValueMappings.h"
34 #include "CSSSegmentedFontFace.h"
35 #include "CSSUnicodeRangeValue.h"
36 #include "CSSValue.h"
37 #include "CSSValueList.h"
38 #include "Document.h"
39 #include "Font.h"
40 #include "FontDescription.h"
41 #include "FontLoader.h"
42 #include "FontVariantBuilder.h"
43 #include "RuntimeEnabledFeatures.h"
44 #include "StyleProperties.h"
45
46 namespace WebCore {
47
48 CSSFontFace::CSSFontFace(CSSFontSelector& fontSelector, FontFace* wrapper, bool isLocalFallback)
49     : m_fontSelector(fontSelector)
50     , m_wrapper(wrapper)
51     , m_isLocalFallback(isLocalFallback)
52 {
53 }
54
55 CSSFontFace::~CSSFontFace()
56 {
57 }
58
59 bool CSSFontFace::setFamilies(CSSValue& family)
60 {
61     if (!is<CSSValueList>(family))
62         return false;
63
64     CSSValueList& familyList = downcast<CSSValueList>(family);
65     if (!familyList.length())
66         return false;
67
68     m_families = &familyList;
69     return true;
70 }
71
72 bool CSSFontFace::setStyle(CSSValue& style)
73 {
74     if (!is<CSSPrimitiveValue>(style))
75         return false;
76
77     unsigned styleMask = 0;
78     switch (downcast<CSSPrimitiveValue>(style).getValueID()) {
79     case CSSValueNormal:
80         styleMask = FontStyleNormalMask;
81         break;
82     case CSSValueItalic:
83     case CSSValueOblique:
84         styleMask = FontStyleItalicMask;
85         break;
86     default:
87         styleMask = FontStyleNormalMask;
88         break;
89     }
90
91     m_traitsMask = static_cast<FontTraitsMask>((static_cast<unsigned>(m_traitsMask) & (~FontStyleMask)) | styleMask);
92     return true;
93 }
94
95 bool CSSFontFace::setWeight(CSSValue& weight)
96 {
97     if (!is<CSSPrimitiveValue>(weight))
98         return false;
99
100     unsigned weightMask = 0;
101     switch (downcast<CSSPrimitiveValue>(weight).getValueID()) {
102     case CSSValueBold:
103     case CSSValueBolder:
104     case CSSValue700:
105         weightMask = FontWeight700Mask;
106         break;
107     case CSSValueNormal:
108     case CSSValue400:
109         weightMask = FontWeight400Mask;
110         break;
111     case CSSValue900:
112         weightMask = FontWeight900Mask;
113         break;
114     case CSSValue800:
115         weightMask = FontWeight800Mask;
116         break;
117     case CSSValue600:
118         weightMask = FontWeight600Mask;
119         break;
120     case CSSValue500:
121         weightMask = FontWeight500Mask;
122         break;
123     case CSSValue300:
124         weightMask = FontWeight300Mask;
125         break;
126     case CSSValueLighter:
127     case CSSValue200:
128         weightMask = FontWeight200Mask;
129         break;
130     case CSSValue100:
131         weightMask = FontWeight100Mask;
132         break;
133     default:
134         weightMask = FontWeight400Mask;
135         break;
136     }
137
138     m_traitsMask = static_cast<FontTraitsMask>((static_cast<unsigned>(m_traitsMask) & (~FontWeightMask)) | weightMask);
139     return true;
140 }
141
142 bool CSSFontFace::setUnicodeRange(CSSValue& unicodeRange)
143 {
144     if (!is<CSSValueList>(unicodeRange))
145         return false;
146
147     m_ranges.clear();
148     auto& list = downcast<CSSValueList>(unicodeRange);
149     for (auto& rangeValue : list) {
150         CSSUnicodeRangeValue& range = downcast<CSSUnicodeRangeValue>(rangeValue.get());
151         m_ranges.append(UnicodeRange(range.from(), range.to()));
152     }
153     return true;
154 }
155
156 bool CSSFontFace::setVariantLigatures(CSSValue& variantLigatures)
157 {
158     auto ligatures = extractFontVariantLigatures(variantLigatures);
159     m_variantSettings.commonLigatures = ligatures.commonLigatures;
160     m_variantSettings.discretionaryLigatures = ligatures.discretionaryLigatures;
161     m_variantSettings.historicalLigatures = ligatures.historicalLigatures;
162     m_variantSettings.contextualAlternates = ligatures.contextualAlternates;
163     return true;
164 }
165
166 bool CSSFontFace::setVariantPosition(CSSValue& variantPosition)
167 {
168     if (!is<CSSPrimitiveValue>(variantPosition))
169         return false;
170     m_variantSettings.position = downcast<CSSPrimitiveValue>(variantPosition);
171     return true;
172 }
173
174 bool CSSFontFace::setVariantCaps(CSSValue& variantCaps)
175 {
176     if (!is<CSSPrimitiveValue>(variantCaps))
177         return false;
178     m_variantSettings.caps = downcast<CSSPrimitiveValue>(variantCaps);
179     return true;
180 }
181
182 bool CSSFontFace::setVariantNumeric(CSSValue& variantNumeric)
183 {
184     auto numeric = extractFontVariantNumeric(variantNumeric);
185     m_variantSettings.numericFigure = numeric.figure;
186     m_variantSettings.numericSpacing = numeric.spacing;
187     m_variantSettings.numericFraction = numeric.fraction;
188     m_variantSettings.numericOrdinal = numeric.ordinal;
189     m_variantSettings.numericSlashedZero = numeric.slashedZero;
190     return true;
191 }
192
193 bool CSSFontFace::setVariantAlternates(CSSValue& variantAlternates)
194 {
195     if (!is<CSSPrimitiveValue>(variantAlternates))
196         return false;
197     m_variantSettings.alternates = downcast<CSSPrimitiveValue>(variantAlternates);
198     return true;
199 }
200
201 bool CSSFontFace::setVariantEastAsian(CSSValue& variantEastAsian)
202 {
203     auto eastAsian = extractFontVariantEastAsian(variantEastAsian);
204     m_variantSettings.eastAsianVariant = eastAsian.variant;
205     m_variantSettings.eastAsianWidth = eastAsian.width;
206     m_variantSettings.eastAsianRuby = eastAsian.ruby;
207     return true;
208 }
209
210 bool CSSFontFace::setFeatureSettings(CSSValue& featureSettings)
211 {
212     if (!is<CSSValueList>(featureSettings))
213         return false;
214
215     m_featureSettings = FontFeatureSettings();
216     auto& list = downcast<CSSValueList>(featureSettings);
217     for (auto& rangeValue : list) {
218         CSSFontFeatureValue& feature = downcast<CSSFontFeatureValue>(rangeValue.get());
219         m_featureSettings.insert(FontFeature(feature.tag(), feature.value()));
220     }
221     return true;
222 }
223
224 bool CSSFontFace::allSourcesFailed() const
225 {
226     for (auto& source : m_sources) {
227         if (source->status() != CSSFontFaceSource::Status::Failure)
228             return false;
229     }
230     return true;
231 }
232
233 void CSSFontFace::addClient(Client& client)
234 {
235     m_clients.add(&client);
236 }
237
238 void CSSFontFace::removeClient(Client& client)
239 {
240     m_clients.remove(&client);
241 }
242
243 void CSSFontFace::adoptSource(std::unique_ptr<CSSFontFaceSource>&& source)
244 {
245     m_sources.append(WTFMove(source));
246
247     // We should never add sources in the middle of loading.
248     ASSERT(!m_sourcesPopulated);
249 }
250
251 void CSSFontFace::setStatus(Status newStatus)
252 {
253     switch (newStatus) {
254     case Status::Pending:
255         ASSERT_NOT_REACHED();
256         break;
257     case Status::Loading:
258         ASSERT(m_status == Status::Pending);
259         break;
260     case Status::TimedOut:
261         ASSERT(m_status == Status::Loading);
262         break;
263     case Status::Success:
264         ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
265         break;
266     case Status::Failure:
267         ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
268         break;
269     }
270
271     for (auto& client : m_clients)
272         client->stateChanged(*this, m_status, newStatus);
273
274     m_status = newStatus;
275 }
276
277 void CSSFontFace::fontLoaded(CSSFontFaceSource&)
278 {
279     // If the font is already in the cache, CSSFontFaceSource may report it's loaded before it is added here as a source.
280     // Let's not pump the state machine until we've got all our sources. font() and load() are smart enough to act correctly
281     // when a source is failed or succeeded before we have asked it to load.
282     if (m_sourcesPopulated)
283         pump();
284
285     m_fontSelector->fontLoaded();
286
287     for (auto& client : m_clients)
288         client->fontLoaded(*this);
289 }
290
291 size_t CSSFontFace::pump()
292 {
293     size_t i;
294     for (i = 0; i < m_sources.size(); ++i) {
295         auto& source = m_sources[i];
296
297         if (source->status() == CSSFontFaceSource::Status::Pending) {
298             ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut);
299             if (m_status == Status::Pending)
300                 setStatus(Status::Loading);
301             source->load(m_fontSelector.get());
302         }
303
304         switch (source->status()) {
305         case CSSFontFaceSource::Status::Pending:
306             ASSERT_NOT_REACHED();
307             break;
308         case CSSFontFaceSource::Status::Loading:
309             ASSERT(m_status == Status::Pending || m_status == Status::Loading);
310             if (m_status == Status::Pending)
311                 setStatus(Status::Loading);
312             return i;
313         case CSSFontFaceSource::Status::Success:
314             ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut || m_status == Status::Success);
315             if (m_status == Status::Pending)
316                 setStatus(Status::Loading);
317             if (m_status == Status::Loading || m_status == Status::TimedOut)
318                 setStatus(Status::Success);
319             return i;
320         case CSSFontFaceSource::Status::Failure:
321             if (m_status == Status::Pending)
322                 setStatus(Status::Loading);
323             break;
324         }
325     }
326     if (m_status == Status::Loading || m_status == Status::TimedOut)
327         setStatus(Status::Failure);
328     return m_sources.size();
329 }
330
331 void CSSFontFace::load()
332 {
333     pump();
334 }
335
336 RefPtr<Font> CSSFontFace::font(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic)
337 {
338     if (allSourcesFailed())
339         return nullptr;
340
341     // Our status is derived from the first non-failed source. However, this source may
342     // return null from font(), which means we need to continue looping through the remainder
343     // of the sources to try to find a font to use. These subsequent tries should not affect
344     // our own state, though.
345     size_t startIndex = pump();
346     for (size_t i = startIndex; i < m_sources.size(); ++i) {
347         auto& source = m_sources[i];
348         if (source->status() == CSSFontFaceSource::Status::Pending)
349             source->load(m_fontSelector.get());
350
351         switch (source->status()) {
352         case CSSFontFaceSource::Status::Pending:
353             ASSERT_NOT_REACHED();
354             break;
355         case CSSFontFaceSource::Status::Loading:
356             return Font::create(FontCache::singleton().lastResortFallbackFont(fontDescription)->platformData(), true, true);
357         case CSSFontFaceSource::Status::Success:
358             if (RefPtr<Font> result = source->font(fontDescription, syntheticBold, syntheticItalic, m_featureSettings, m_variantSettings))
359                 return result;
360             break;
361         case CSSFontFaceSource::Status::Failure:
362             break;
363         }
364     }
365
366     return nullptr;
367 }
368
369 #if ENABLE(SVG_FONTS)
370 bool CSSFontFace::hasSVGFontFaceSource() const
371 {
372     size_t size = m_sources.size();
373     for (size_t i = 0; i < size; i++) {
374         if (m_sources[i]->isSVGFontFaceSource())
375             return true;
376     }
377     return false;
378 }
379 #endif
380
381 }