cc053ea234cfc68734f14d23d8c0aa92c29759d5
[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 "CSSFontFaceSrcValue.h"
31 #include "CSSFontFeatureValue.h"
32 #include "CSSFontSelector.h"
33 #include "CSSFontStyleRangeValue.h"
34 #include "CSSPrimitiveValueMappings.h"
35 #include "CSSUnicodeRangeValue.h"
36 #include "CSSValue.h"
37 #include "CSSValueList.h"
38 #include "Document.h"
39 #include "Font.h"
40 #include "FontCache.h"
41 #include "FontDescription.h"
42 #include "FontFace.h"
43 #include "FontVariantBuilder.h"
44 #include "Settings.h"
45 #include "StyleBuilderConverter.h"
46 #include "StyleProperties.h"
47 #include "StyleRule.h"
48
49 namespace WebCore {
50
51 template<typename T> void iterateClients(HashSet<CSSFontFace::Client*>& clients, T callback)
52 {
53     Vector<Ref<CSSFontFace::Client>> clientsCopy;
54     clientsCopy.reserveInitialCapacity(clients.size());
55     for (auto* client : clients)
56         clientsCopy.uncheckedAppend(*client);
57
58     for (auto* client : clients)
59         callback(*client);
60 }
61
62 void CSSFontFace::appendSources(CSSFontFace& fontFace, CSSValueList& srcList, Document* document, bool isInitiatingElementInUserAgentShadowTree)
63 {
64     for (auto& src : srcList) {
65         // An item in the list either specifies a string (local font name) or a URL (remote font to download).
66         CSSFontFaceSrcValue& item = downcast<CSSFontFaceSrcValue>(src.get());
67         std::unique_ptr<CSSFontFaceSource> source;
68         SVGFontFaceElement* fontFaceElement = nullptr;
69         bool foundSVGFont = false;
70
71 #if ENABLE(SVG_FONTS)
72         foundSVGFont = item.isSVGFontFaceSrc() || item.svgFontFaceElement();
73         fontFaceElement = item.svgFontFaceElement();
74 #endif
75         if (!item.isLocal()) {
76             const Settings* settings = document ? &document->settings() : nullptr;
77             bool allowDownloading = foundSVGFont || (settings && settings->downloadableBinaryFontsEnabled());
78             if (allowDownloading && item.isSupportedFormat() && document) {
79                 if (CachedFont* cachedFont = item.cachedFont(document, foundSVGFont, isInitiatingElementInUserAgentShadowTree))
80                     source = std::make_unique<CSSFontFaceSource>(fontFace, item.resource(), cachedFont);
81             }
82         } else
83             source = std::make_unique<CSSFontFaceSource>(fontFace, item.resource(), nullptr, fontFaceElement);
84
85         if (source)
86             fontFace.adoptSource(WTFMove(source));
87     }
88     fontFace.sourcesPopulated();
89 }
90
91 CSSFontFace::CSSFontFace(CSSFontSelector* fontSelector, StyleRuleFontFace* cssConnection, FontFace* wrapper, bool isLocalFallback)
92     : m_timeoutTimer(*this, &CSSFontFace::timeoutFired)
93     , m_fontSelector(fontSelector)
94     , m_cssConnection(cssConnection)
95     , m_wrapper(wrapper ? wrapper->createWeakPtr() : WeakPtr<FontFace>())
96     , m_isLocalFallback(isLocalFallback)
97     , m_mayBePurged(!wrapper)
98 {
99 }
100
101 CSSFontFace::~CSSFontFace()
102 {
103 }
104
105 bool CSSFontFace::setFamilies(CSSValue& family)
106 {
107     if (!is<CSSValueList>(family))
108         return false;
109
110     CSSValueList& familyList = downcast<CSSValueList>(family);
111     if (!familyList.length())
112         return false;
113
114     RefPtr<CSSValueList> oldFamilies = m_families;
115     m_families = &familyList;
116
117     if (m_cssConnection)
118         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontFamily, &family);
119
120     iterateClients(m_clients, [&](Client& client) {
121         client.fontPropertyChanged(*this, oldFamilies.get());
122     });
123
124     return true;
125 }
126
127 static FontSelectionRange calculateWeightRange(CSSValue& value)
128 {
129     if (value.isValueList()) {
130         auto& valueList = downcast<CSSValueList>(value);
131         ASSERT(valueList.length() == 2);
132         if (valueList.length() != 2)
133             return { normalWeightValue(), normalWeightValue() };
134         ASSERT(valueList.item(0)->isPrimitiveValue());
135         ASSERT(valueList.item(1)->isPrimitiveValue());
136         auto& value0 = downcast<CSSPrimitiveValue>(*valueList.item(0));
137         auto& value1 = downcast<CSSPrimitiveValue>(*valueList.item(1));
138         auto result0 = StyleBuilderConverter::convertFontWeightFromValue(value0);
139         auto result1 = StyleBuilderConverter::convertFontWeightFromValue(value1);
140         return { result0, result1 };
141     }
142
143     ASSERT(is<CSSPrimitiveValue>(value));
144     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
145     FontSelectionValue result = StyleBuilderConverter::convertFontWeightFromValue(primitiveValue);
146     return { result, result };
147 }
148
149 void CSSFontFace::setWeight(CSSValue& weight)
150 {
151     auto range = calculateWeightRange(weight);
152     if (m_fontSelectionCapabilities.weight == range)
153         return;
154
155     setWeight(range);
156
157     if (m_cssConnection)
158         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontWeight, &weight);
159
160     iterateClients(m_clients, [&](Client& client) {
161         client.fontPropertyChanged(*this);
162     });
163 }
164
165 static FontSelectionRange calculateStretchRange(CSSValue& value)
166 {
167     if (value.isValueList()) {
168         auto& valueList = downcast<CSSValueList>(value);
169         ASSERT(valueList.length() == 2);
170         if (valueList.length() != 2)
171             return { normalStretchValue(), normalStretchValue() };
172         ASSERT(valueList.item(0)->isPrimitiveValue());
173         ASSERT(valueList.item(1)->isPrimitiveValue());
174         auto& value0 = downcast<CSSPrimitiveValue>(*valueList.item(0));
175         auto& value1 = downcast<CSSPrimitiveValue>(*valueList.item(1));
176         auto result0 = StyleBuilderConverter::convertFontStretchFromValue(value0);
177         auto result1 = StyleBuilderConverter::convertFontStretchFromValue(value1);
178         return { result0, result1 };
179     }
180
181     ASSERT(is<CSSPrimitiveValue>(value));
182     const auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
183     FontSelectionValue result = StyleBuilderConverter::convertFontStretchFromValue(primitiveValue);
184     return { result, result };
185 }
186
187 void CSSFontFace::setStretch(CSSValue& style)
188 {
189     auto range = calculateStretchRange(style);
190     if (m_fontSelectionCapabilities.width == range)
191         return;
192
193     setStretch(range);
194
195     if (m_cssConnection)
196         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontStretch, &style);
197
198     iterateClients(m_clients, [&](Client& client) {
199         client.fontPropertyChanged(*this);
200     });
201 }
202
203 static FontSelectionRange calculateItalicRange(CSSValue& value)
204 {
205     if (value.isFontStyleValue()) {
206         auto result = StyleBuilderConverter::convertFontStyleFromValue(value);
207         return { result, result };
208     }
209
210     ASSERT(value.isFontStyleRangeValue());
211     auto& rangeValue = downcast<CSSFontStyleRangeValue>(value);
212     ASSERT(rangeValue.fontStyleValue->isValueID());
213     auto valueID = rangeValue.fontStyleValue->valueID();
214     if (!rangeValue.obliqueValues) {
215         if (valueID == CSSValueNormal)
216             return { normalItalicValue(), normalItalicValue() };
217         ASSERT(valueID == CSSValueItalic || valueID == CSSValueOblique);
218         return { italicValue(), italicValue() };
219     }
220     ASSERT(valueID == CSSValueOblique);
221     auto length = rangeValue.obliqueValues->length();
222     if (length == 1) {
223         auto& primitiveValue = downcast<CSSPrimitiveValue>(*rangeValue.obliqueValues->item(0));
224         FontSelectionValue result(primitiveValue.value<float>(CSSPrimitiveValue::CSS_DEG));
225         return { result, result };
226     }
227     ASSERT(length == 2);
228     auto& primitiveValue1 = downcast<CSSPrimitiveValue>(*rangeValue.obliqueValues->item(0));
229     auto& primitiveValue2 = downcast<CSSPrimitiveValue>(*rangeValue.obliqueValues->item(1));
230     FontSelectionValue result1(primitiveValue1.value<float>(CSSPrimitiveValue::CSS_DEG));
231     FontSelectionValue result2(primitiveValue2.value<float>(CSSPrimitiveValue::CSS_DEG));
232     return { result1, result2 };
233 }
234
235 void CSSFontFace::setStyle(CSSValue& style)
236 {
237     auto range = calculateItalicRange(style);
238     if (m_fontSelectionCapabilities.slope == range)
239         return;
240
241     setStyle(range);
242
243     if (m_cssConnection)
244         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontStyle, &style);
245
246     iterateClients(m_clients, [&](Client& client) {
247         client.fontPropertyChanged(*this);
248     });
249 }
250
251 bool CSSFontFace::setUnicodeRange(CSSValue& unicodeRange)
252 {
253     if (!is<CSSValueList>(unicodeRange))
254         return false;
255
256     Vector<UnicodeRange> ranges;
257     auto& list = downcast<CSSValueList>(unicodeRange);
258     for (auto& rangeValue : list) {
259         auto& range = downcast<CSSUnicodeRangeValue>(rangeValue.get());
260         ranges.append({ range.from(), range.to() });
261     }
262
263     if (ranges == m_ranges)
264         return true;
265
266     m_ranges = WTFMove(ranges);
267
268     if (m_cssConnection)
269         m_cssConnection->mutableProperties().setProperty(CSSPropertyUnicodeRange, &unicodeRange);
270
271     iterateClients(m_clients, [&](Client& client) {
272         client.fontPropertyChanged(*this);
273     });
274
275     return true;
276 }
277
278 bool CSSFontFace::setVariantLigatures(CSSValue& variantLigatures)
279 {
280     auto ligatures = extractFontVariantLigatures(variantLigatures);
281
282     if (m_variantSettings.commonLigatures == ligatures.commonLigatures
283         && m_variantSettings.discretionaryLigatures == ligatures.discretionaryLigatures
284         && m_variantSettings.historicalLigatures == ligatures.historicalLigatures
285         && m_variantSettings.contextualAlternates == ligatures.contextualAlternates)
286         return true;
287
288     m_variantSettings.commonLigatures = ligatures.commonLigatures;
289     m_variantSettings.discretionaryLigatures = ligatures.discretionaryLigatures;
290     m_variantSettings.historicalLigatures = ligatures.historicalLigatures;
291     m_variantSettings.contextualAlternates = ligatures.contextualAlternates;
292
293     if (m_cssConnection)
294         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantLigatures, &variantLigatures);
295
296     iterateClients(m_clients, [&](Client& client) {
297         client.fontPropertyChanged(*this);
298     });
299
300     return true;
301 }
302
303 bool CSSFontFace::setVariantPosition(CSSValue& variantPosition)
304 {
305     if (!is<CSSPrimitiveValue>(variantPosition))
306         return false;
307
308     FontVariantPosition position = downcast<CSSPrimitiveValue>(variantPosition);
309
310     if (m_variantSettings.position == position)
311         return true;
312
313     m_variantSettings.position = position;
314
315     if (m_cssConnection)
316         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantPosition, &variantPosition);
317
318     iterateClients(m_clients, [&](Client& client) {
319         client.fontPropertyChanged(*this);
320     });
321
322     return true;
323 }
324
325 bool CSSFontFace::setVariantCaps(CSSValue& variantCaps)
326 {
327     if (!is<CSSPrimitiveValue>(variantCaps))
328         return false;
329
330     FontVariantCaps caps = downcast<CSSPrimitiveValue>(variantCaps);
331
332     if (m_variantSettings.caps == caps)
333         return true;
334
335     m_variantSettings.caps = caps;
336
337     if (m_cssConnection)
338         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantCaps, &variantCaps);
339
340     iterateClients(m_clients, [&](Client& client) {
341         client.fontPropertyChanged(*this);
342     });
343
344     return true;
345 }
346
347 bool CSSFontFace::setVariantNumeric(CSSValue& variantNumeric)
348 {
349     auto numeric = extractFontVariantNumeric(variantNumeric);
350
351     if (m_variantSettings.numericFigure == numeric.figure
352         && m_variantSettings.numericSpacing == numeric.spacing
353         && m_variantSettings.numericFraction == numeric.fraction
354         && m_variantSettings.numericOrdinal == numeric.ordinal
355         && m_variantSettings.numericSlashedZero == numeric.slashedZero)
356         return true;
357
358     m_variantSettings.numericFigure = numeric.figure;
359     m_variantSettings.numericSpacing = numeric.spacing;
360     m_variantSettings.numericFraction = numeric.fraction;
361     m_variantSettings.numericOrdinal = numeric.ordinal;
362     m_variantSettings.numericSlashedZero = numeric.slashedZero;
363
364     if (m_cssConnection)
365         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantNumeric, &variantNumeric);
366
367     iterateClients(m_clients, [&](Client& client) {
368         client.fontPropertyChanged(*this);
369     });
370
371     return true;
372 }
373
374 bool CSSFontFace::setVariantAlternates(CSSValue& variantAlternates)
375 {
376     if (!is<CSSPrimitiveValue>(variantAlternates))
377         return false;
378
379     FontVariantAlternates alternates = downcast<CSSPrimitiveValue>(variantAlternates);
380
381     if (m_variantSettings.alternates == alternates)
382         return true;
383
384     m_variantSettings.alternates = alternates;
385
386     if (m_cssConnection)
387         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantAlternates, &variantAlternates);
388
389     iterateClients(m_clients, [&](Client& client) {
390         client.fontPropertyChanged(*this);
391     });
392
393     return true;
394 }
395
396 bool CSSFontFace::setVariantEastAsian(CSSValue& variantEastAsian)
397 {
398     auto eastAsian = extractFontVariantEastAsian(variantEastAsian);
399
400     if (m_variantSettings.eastAsianVariant == eastAsian.variant
401         && m_variantSettings.eastAsianWidth == eastAsian.width
402         && m_variantSettings.eastAsianRuby == eastAsian.ruby)
403         return true;
404
405     m_variantSettings.eastAsianVariant = eastAsian.variant;
406     m_variantSettings.eastAsianWidth = eastAsian.width;
407     m_variantSettings.eastAsianRuby = eastAsian.ruby;
408
409     if (m_cssConnection)
410         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantEastAsian, &variantEastAsian);
411
412     iterateClients(m_clients, [&](Client& client) {
413         client.fontPropertyChanged(*this);
414     });
415
416     return true;
417 }
418
419 void CSSFontFace::setFeatureSettings(CSSValue& featureSettings)
420 {
421     // Can only call this with a primitive value of normal, or a value list containing font feature values.
422     ASSERT(is<CSSPrimitiveValue>(featureSettings) || is<CSSValueList>(featureSettings));
423
424     FontFeatureSettings settings;
425
426     if (is<CSSValueList>(featureSettings)) {
427         auto& list = downcast<CSSValueList>(featureSettings);
428         for (auto& rangeValue : list) {
429             auto& feature = downcast<CSSFontFeatureValue>(rangeValue.get());
430             settings.insert({ feature.tag(), feature.value() });
431         }
432     }
433
434     if (m_featureSettings == settings)
435         return;
436
437     m_featureSettings = WTFMove(settings);
438
439     if (m_cssConnection)
440         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontFeatureSettings, &featureSettings);
441
442     iterateClients(m_clients, [&](Client& client) {
443         client.fontPropertyChanged(*this);
444     });
445 }
446
447 void CSSFontFace::setLoadingBehavior(CSSValue& loadingBehaviorValue)
448 {
449     auto loadingBehavior = static_cast<FontLoadingBehavior>(downcast<CSSPrimitiveValue>(loadingBehaviorValue).valueID());
450
451     if (m_loadingBehavior == loadingBehavior)
452         return;
453
454     m_loadingBehavior = loadingBehavior;
455
456     if (m_cssConnection)
457         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontDisplay, &loadingBehaviorValue);
458
459     iterateClients(m_clients, [&](Client& client) {
460         client.fontPropertyChanged(*this);
461     });
462 }
463
464 bool CSSFontFace::rangesMatchCodePoint(UChar32 character) const
465 {
466     if (m_ranges.isEmpty())
467         return true;
468
469     for (auto& range : m_ranges) {
470         if (range.from <= character && character <= range.to)
471             return true;
472     }
473     return false;
474 }
475
476 void CSSFontFace::fontLoadEventOccurred()
477 {
478     Ref<CSSFontFace> protectedThis(*this);
479
480     // If the font is already in the cache, CSSFontFaceSource may report it's loaded before it is added here as a source.
481     // Let's not pump the state machine until we've got all our sources. font() and load() are smart enough to act correctly
482     // when a source is failed or succeeded before we have asked it to load.
483     if (m_sourcesPopulated && !webFontsShouldAlwaysFallBack())
484         pump(ExternalResourceDownloadPolicy::Forbid);
485
486     ASSERT(m_fontSelector);
487     m_fontSelector->fontLoaded();
488
489     iterateClients(m_clients, [&](Client& client) {
490         client.fontLoaded(*this);
491     });
492 }
493
494 void CSSFontFace::timeoutFired()
495 {
496     setStatus(Status::TimedOut);
497
498     fontLoadEventOccurred();
499 }
500
501 bool CSSFontFace::allSourcesFailed() const
502 {
503     for (auto& source : m_sources) {
504         if (source->status() != CSSFontFaceSource::Status::Failure)
505             return false;
506     }
507     return true;
508 }
509
510 void CSSFontFace::addClient(Client& client)
511 {
512     m_clients.add(&client);
513 }
514
515 void CSSFontFace::removeClient(Client& client)
516 {
517     ASSERT(m_clients.contains(&client));
518     m_clients.remove(&client);
519 }
520
521 void CSSFontFace::initializeWrapper()
522 {
523     switch (m_status) {
524     case Status::Pending:
525         break;
526     case Status::Loading:
527         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
528         break;
529     case Status::TimedOut:
530         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
531         m_wrapper->fontStateChanged(*this, Status::Loading, Status::TimedOut);
532         break;
533     case Status::Success:
534         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
535         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Success);
536         break;
537     case Status::Failure:
538         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
539         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Failure);
540         break;
541     }
542     m_mayBePurged = false;
543 }
544
545 Ref<FontFace> CSSFontFace::wrapper()
546 {
547     if (m_wrapper)
548         return *m_wrapper.get();
549
550     auto wrapper = FontFace::create(*this);
551     m_wrapper = wrapper->createWeakPtr();
552     initializeWrapper();
553     return wrapper;
554 }
555
556 void CSSFontFace::setWrapper(FontFace& newWrapper)
557 {
558     m_wrapper = newWrapper.createWeakPtr();
559     initializeWrapper();
560 }
561
562 void CSSFontFace::adoptSource(std::unique_ptr<CSSFontFaceSource>&& source)
563 {
564     m_sources.append(WTFMove(source));
565
566     // We should never add sources in the middle of loading.
567     ASSERT(!m_sourcesPopulated);
568 }
569
570 void CSSFontFace::setStatus(Status newStatus)
571 {
572     switch (newStatus) {
573     case Status::Pending:
574         ASSERT_NOT_REACHED();
575         break;
576     case Status::Loading:
577         ASSERT(m_status == Status::Pending);
578         break;
579     case Status::TimedOut:
580         ASSERT(m_status == Status::Loading);
581         break;
582     case Status::Success:
583         ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
584         break;
585     case Status::Failure:
586         ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
587         break;
588     }
589
590     bool webFontsShouldAlwaysFallBack = this->webFontsShouldAlwaysFallBack();
591     if (!webFontsShouldAlwaysFallBack) {
592         if (newStatus == Status::Loading) {
593             Seconds timeUntilInterstitialFontIsDrawnVisibly = 3_s;
594             m_timeoutTimer.startOneShot(timeUntilInterstitialFontIsDrawnVisibly);
595         } else if (newStatus == Status::Success || newStatus == Status::Failure)
596             m_timeoutTimer.stop();
597     }
598
599     iterateClients(m_clients, [&](Client& client) {
600         client.fontStateChanged(*this, m_status, newStatus);
601     });
602
603     m_status = newStatus;
604
605     if (newStatus == Status::Loading && webFontsShouldAlwaysFallBack)
606         timeoutFired();
607 }
608
609 void CSSFontFace::fontLoaded(CSSFontFaceSource&)
610 {
611     ASSERT(!webFontsShouldAlwaysFallBack());
612
613     fontLoadEventOccurred();
614 }
615
616 bool CSSFontFace::webFontsShouldAlwaysFallBack() const
617 {
618     return m_fontSelector && m_fontSelector->document() && m_fontSelector->document()->settings().webFontsAlwaysFallBack();
619 }
620
621 size_t CSSFontFace::pump(ExternalResourceDownloadPolicy policy)
622 {
623     size_t i;
624     for (i = 0; i < m_sources.size(); ++i) {
625         auto& source = m_sources[i];
626
627         if (source->status() == CSSFontFaceSource::Status::Pending) {
628             ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut);
629             if (policy == ExternalResourceDownloadPolicy::Allow || !source->requiresExternalResource()) {
630                 if (m_status == Status::Pending)
631                     setStatus(Status::Loading);
632                 source->load(m_fontSelector.get());
633             }
634         }
635
636         switch (source->status()) {
637         case CSSFontFaceSource::Status::Pending:
638             ASSERT(policy == ExternalResourceDownloadPolicy::Forbid);
639             return i;
640         case CSSFontFaceSource::Status::Loading:
641             ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut);
642             if (m_status == Status::Pending)
643                 setStatus(Status::Loading);
644             return i;
645         case CSSFontFaceSource::Status::Success:
646             ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut || m_status == Status::Success);
647             if (m_status == Status::Pending)
648                 setStatus(Status::Loading);
649             if (m_status == Status::Loading || m_status == Status::TimedOut)
650                 setStatus(Status::Success);
651             return i;
652         case CSSFontFaceSource::Status::Failure:
653             if (m_status == Status::Pending)
654                 setStatus(Status::Loading);
655             break;
656         }
657     }
658     if (m_sources.isEmpty() && m_status == Status::Pending)
659         setStatus(Status::Loading);
660     if (m_status == Status::Loading || m_status == Status::TimedOut)
661         setStatus(Status::Failure);
662     return m_sources.size();
663 }
664
665 void CSSFontFace::load()
666 {
667     pump(ExternalResourceDownloadPolicy::Allow);
668 }
669
670 RefPtr<Font> CSSFontFace::font(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic, ExternalResourceDownloadPolicy policy)
671 {
672     if (allSourcesFailed())
673         return nullptr;
674
675     // Our status is derived from the first non-failed source. However, this source may
676     // return null from font(), which means we need to continue looping through the remainder
677     // of the sources to try to find a font to use. These subsequent tries should not affect
678     // our own state, though.
679     size_t startIndex = pump(policy);
680     for (size_t i = startIndex; i < m_sources.size(); ++i) {
681         auto& source = m_sources[i];
682         if (source->status() == CSSFontFaceSource::Status::Pending && (policy == ExternalResourceDownloadPolicy::Allow || !source->requiresExternalResource()))
683             source->load(m_fontSelector.get());
684
685         switch (source->status()) {
686         case CSSFontFaceSource::Status::Pending:
687         case CSSFontFaceSource::Status::Loading: {
688             Font::Visibility visibility = status() == Status::TimedOut ? Font::Visibility::Visible : Font::Visibility::Invisible;
689             return Font::create(FontCache::singleton().lastResortFallbackFont(fontDescription)->platformData(), Font::Origin::Remote, Font::Interstitial::Yes, visibility);
690         }
691         case CSSFontFaceSource::Status::Success:
692             if (RefPtr<Font> result = source->font(fontDescription, syntheticBold, syntheticItalic, m_featureSettings, m_variantSettings, m_fontSelectionCapabilities))
693                 return result;
694             break;
695         case CSSFontFaceSource::Status::Failure:
696             break;
697         }
698     }
699
700     return nullptr;
701 }
702
703 bool CSSFontFace::purgeable() const
704 {
705     return cssConnection() && m_mayBePurged;
706 }
707
708 void CSSFontFace::updateStyleIfNeeded()
709 {
710     if (m_fontSelector && m_fontSelector->document())
711         m_fontSelector->document()->updateStyleIfNeeded();
712 }
713
714 #if ENABLE(SVG_FONTS)
715 bool CSSFontFace::hasSVGFontFaceSource() const
716 {
717     size_t size = m_sources.size();
718     for (size_t i = 0; i < size; i++) {
719         if (m_sources[i]->isSVGFontFaceSource())
720             return true;
721     }
722     return false;
723 }
724 #endif
725
726 }