WeakPtr breaks vtables when upcasting to base classes
[WebKit-https.git] / Source / WebCore / css / CSSFontFace.cpp
1 /*
2  * Copyright (C) 2007-2019 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_fontSelector(fontSelector)
93     , m_cssConnection(cssConnection)
94     , m_wrapper(makeWeakPtr(wrapper))
95     , m_isLocalFallback(isLocalFallback)
96     , m_mayBePurged(!wrapper)
97     , m_timeoutTimer(*this, &CSSFontFace::timeoutFired)
98 {
99 }
100
101 CSSFontFace::~CSSFontFace() = default;
102
103 bool CSSFontFace::setFamilies(CSSValue& family)
104 {
105     if (!is<CSSValueList>(family))
106         return false;
107
108     CSSValueList& familyList = downcast<CSSValueList>(family);
109     if (!familyList.length())
110         return false;
111
112     RefPtr<CSSValueList> oldFamilies = m_families;
113     m_families = &familyList;
114
115     if (m_cssConnection)
116         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontFamily, &family);
117
118     iterateClients(m_clients, [&](Client& client) {
119         client.fontPropertyChanged(*this, oldFamilies.get());
120     });
121
122     return true;
123 }
124
125 FontFace* CSSFontFace::existingWrapper()
126 {
127     return m_wrapper.get();
128 }
129
130 static FontSelectionRange calculateWeightRange(CSSValue& value)
131 {
132     if (value.isValueList()) {
133         auto& valueList = downcast<CSSValueList>(value);
134         ASSERT(valueList.length() == 2);
135         if (valueList.length() != 2)
136             return { normalWeightValue(), normalWeightValue() };
137         ASSERT(valueList.item(0)->isPrimitiveValue());
138         ASSERT(valueList.item(1)->isPrimitiveValue());
139         auto& value0 = downcast<CSSPrimitiveValue>(*valueList.item(0));
140         auto& value1 = downcast<CSSPrimitiveValue>(*valueList.item(1));
141         auto result0 = StyleBuilderConverter::convertFontWeightFromValue(value0);
142         auto result1 = StyleBuilderConverter::convertFontWeightFromValue(value1);
143         return { result0, result1 };
144     }
145
146     ASSERT(is<CSSPrimitiveValue>(value));
147     auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
148     FontSelectionValue result = StyleBuilderConverter::convertFontWeightFromValue(primitiveValue);
149     return { result, result };
150 }
151
152 void CSSFontFace::setWeight(CSSValue& weight)
153 {
154     auto range = calculateWeightRange(weight);
155     if (m_fontSelectionCapabilities.weight == range)
156         return;
157
158     setWeight(range);
159
160     if (m_cssConnection)
161         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontWeight, &weight);
162
163     iterateClients(m_clients, [&](Client& client) {
164         client.fontPropertyChanged(*this);
165     });
166 }
167
168 static FontSelectionRange calculateStretchRange(CSSValue& value)
169 {
170     if (value.isValueList()) {
171         auto& valueList = downcast<CSSValueList>(value);
172         ASSERT(valueList.length() == 2);
173         if (valueList.length() != 2)
174             return { normalStretchValue(), normalStretchValue() };
175         ASSERT(valueList.item(0)->isPrimitiveValue());
176         ASSERT(valueList.item(1)->isPrimitiveValue());
177         auto& value0 = downcast<CSSPrimitiveValue>(*valueList.item(0));
178         auto& value1 = downcast<CSSPrimitiveValue>(*valueList.item(1));
179         auto result0 = StyleBuilderConverter::convertFontStretchFromValue(value0);
180         auto result1 = StyleBuilderConverter::convertFontStretchFromValue(value1);
181         return { result0, result1 };
182     }
183
184     ASSERT(is<CSSPrimitiveValue>(value));
185     const auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
186     FontSelectionValue result = StyleBuilderConverter::convertFontStretchFromValue(primitiveValue);
187     return { result, result };
188 }
189
190 void CSSFontFace::setStretch(CSSValue& style)
191 {
192     auto range = calculateStretchRange(style);
193     if (m_fontSelectionCapabilities.width == range)
194         return;
195
196     setStretch(range);
197
198     if (m_cssConnection)
199         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontStretch, &style);
200
201     iterateClients(m_clients, [&](Client& client) {
202         client.fontPropertyChanged(*this);
203     });
204 }
205
206 static FontSelectionRange calculateItalicRange(CSSValue& value)
207 {
208     if (value.isFontStyleValue()) {
209         auto result = StyleBuilderConverter::convertFontStyleFromValue(value);
210         return { result.valueOr(normalItalicValue()), result.valueOr(normalItalicValue()) };
211     }
212
213     ASSERT(value.isFontStyleRangeValue());
214     auto& rangeValue = downcast<CSSFontStyleRangeValue>(value);
215     ASSERT(rangeValue.fontStyleValue->isValueID());
216     auto valueID = rangeValue.fontStyleValue->valueID();
217     if (!rangeValue.obliqueValues) {
218         if (valueID == CSSValueNormal)
219             return { normalItalicValue(), normalItalicValue() };
220         ASSERT(valueID == CSSValueItalic || valueID == CSSValueOblique);
221         return { italicValue(), italicValue() };
222     }
223     ASSERT(valueID == CSSValueOblique);
224     auto length = rangeValue.obliqueValues->length();
225     if (length == 1) {
226         auto& primitiveValue = downcast<CSSPrimitiveValue>(*rangeValue.obliqueValues->item(0));
227         FontSelectionValue result(primitiveValue.value<float>(CSSPrimitiveValue::CSS_DEG));
228         return { result, result };
229     }
230     ASSERT(length == 2);
231     auto& primitiveValue1 = downcast<CSSPrimitiveValue>(*rangeValue.obliqueValues->item(0));
232     auto& primitiveValue2 = downcast<CSSPrimitiveValue>(*rangeValue.obliqueValues->item(1));
233     FontSelectionValue result1(primitiveValue1.value<float>(CSSPrimitiveValue::CSS_DEG));
234     FontSelectionValue result2(primitiveValue2.value<float>(CSSPrimitiveValue::CSS_DEG));
235     return { result1, result2 };
236 }
237
238 void CSSFontFace::setStyle(CSSValue& style)
239 {
240     auto range = calculateItalicRange(style);
241     if (m_fontSelectionCapabilities.slope == range)
242         return;
243
244     setStyle(range);
245
246     if (m_cssConnection)
247         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontStyle, &style);
248
249     iterateClients(m_clients, [&](Client& client) {
250         client.fontPropertyChanged(*this);
251     });
252 }
253
254 bool CSSFontFace::setUnicodeRange(CSSValue& unicodeRange)
255 {
256     if (!is<CSSValueList>(unicodeRange))
257         return false;
258
259     Vector<UnicodeRange> ranges;
260     auto& list = downcast<CSSValueList>(unicodeRange);
261     for (auto& rangeValue : list) {
262         auto& range = downcast<CSSUnicodeRangeValue>(rangeValue.get());
263         ranges.append({ range.from(), range.to() });
264     }
265
266     if (ranges == m_ranges)
267         return true;
268
269     m_ranges = WTFMove(ranges);
270
271     if (m_cssConnection)
272         m_cssConnection->mutableProperties().setProperty(CSSPropertyUnicodeRange, &unicodeRange);
273
274     iterateClients(m_clients, [&](Client& client) {
275         client.fontPropertyChanged(*this);
276     });
277
278     return true;
279 }
280
281 bool CSSFontFace::setVariantLigatures(CSSValue& variantLigatures)
282 {
283     auto ligatures = extractFontVariantLigatures(variantLigatures);
284
285     if (m_variantSettings.commonLigatures == ligatures.commonLigatures
286         && m_variantSettings.discretionaryLigatures == ligatures.discretionaryLigatures
287         && m_variantSettings.historicalLigatures == ligatures.historicalLigatures
288         && m_variantSettings.contextualAlternates == ligatures.contextualAlternates)
289         return true;
290
291     m_variantSettings.commonLigatures = ligatures.commonLigatures;
292     m_variantSettings.discretionaryLigatures = ligatures.discretionaryLigatures;
293     m_variantSettings.historicalLigatures = ligatures.historicalLigatures;
294     m_variantSettings.contextualAlternates = ligatures.contextualAlternates;
295
296     if (m_cssConnection)
297         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantLigatures, &variantLigatures);
298
299     iterateClients(m_clients, [&](Client& client) {
300         client.fontPropertyChanged(*this);
301     });
302
303     return true;
304 }
305
306 bool CSSFontFace::setVariantPosition(CSSValue& variantPosition)
307 {
308     if (!is<CSSPrimitiveValue>(variantPosition))
309         return false;
310
311     FontVariantPosition position = downcast<CSSPrimitiveValue>(variantPosition);
312
313     if (m_variantSettings.position == position)
314         return true;
315
316     m_variantSettings.position = position;
317
318     if (m_cssConnection)
319         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantPosition, &variantPosition);
320
321     iterateClients(m_clients, [&](Client& client) {
322         client.fontPropertyChanged(*this);
323     });
324
325     return true;
326 }
327
328 bool CSSFontFace::setVariantCaps(CSSValue& variantCaps)
329 {
330     if (!is<CSSPrimitiveValue>(variantCaps))
331         return false;
332
333     FontVariantCaps caps = downcast<CSSPrimitiveValue>(variantCaps);
334
335     if (m_variantSettings.caps == caps)
336         return true;
337
338     m_variantSettings.caps = caps;
339
340     if (m_cssConnection)
341         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantCaps, &variantCaps);
342
343     iterateClients(m_clients, [&](Client& client) {
344         client.fontPropertyChanged(*this);
345     });
346
347     return true;
348 }
349
350 bool CSSFontFace::setVariantNumeric(CSSValue& variantNumeric)
351 {
352     auto numeric = extractFontVariantNumeric(variantNumeric);
353
354     if (m_variantSettings.numericFigure == numeric.figure
355         && m_variantSettings.numericSpacing == numeric.spacing
356         && m_variantSettings.numericFraction == numeric.fraction
357         && m_variantSettings.numericOrdinal == numeric.ordinal
358         && m_variantSettings.numericSlashedZero == numeric.slashedZero)
359         return true;
360
361     m_variantSettings.numericFigure = numeric.figure;
362     m_variantSettings.numericSpacing = numeric.spacing;
363     m_variantSettings.numericFraction = numeric.fraction;
364     m_variantSettings.numericOrdinal = numeric.ordinal;
365     m_variantSettings.numericSlashedZero = numeric.slashedZero;
366
367     if (m_cssConnection)
368         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantNumeric, &variantNumeric);
369
370     iterateClients(m_clients, [&](Client& client) {
371         client.fontPropertyChanged(*this);
372     });
373
374     return true;
375 }
376
377 bool CSSFontFace::setVariantAlternates(CSSValue& variantAlternates)
378 {
379     if (!is<CSSPrimitiveValue>(variantAlternates))
380         return false;
381
382     FontVariantAlternates alternates = downcast<CSSPrimitiveValue>(variantAlternates);
383
384     if (m_variantSettings.alternates == alternates)
385         return true;
386
387     m_variantSettings.alternates = alternates;
388
389     if (m_cssConnection)
390         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantAlternates, &variantAlternates);
391
392     iterateClients(m_clients, [&](Client& client) {
393         client.fontPropertyChanged(*this);
394     });
395
396     return true;
397 }
398
399 bool CSSFontFace::setVariantEastAsian(CSSValue& variantEastAsian)
400 {
401     auto eastAsian = extractFontVariantEastAsian(variantEastAsian);
402
403     if (m_variantSettings.eastAsianVariant == eastAsian.variant
404         && m_variantSettings.eastAsianWidth == eastAsian.width
405         && m_variantSettings.eastAsianRuby == eastAsian.ruby)
406         return true;
407
408     m_variantSettings.eastAsianVariant = eastAsian.variant;
409     m_variantSettings.eastAsianWidth = eastAsian.width;
410     m_variantSettings.eastAsianRuby = eastAsian.ruby;
411
412     if (m_cssConnection)
413         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantEastAsian, &variantEastAsian);
414
415     iterateClients(m_clients, [&](Client& client) {
416         client.fontPropertyChanged(*this);
417     });
418
419     return true;
420 }
421
422 void CSSFontFace::setFeatureSettings(CSSValue& featureSettings)
423 {
424     // Can only call this with a primitive value of normal, or a value list containing font feature values.
425     ASSERT(is<CSSPrimitiveValue>(featureSettings) || is<CSSValueList>(featureSettings));
426
427     FontFeatureSettings settings;
428
429     if (is<CSSValueList>(featureSettings)) {
430         auto& list = downcast<CSSValueList>(featureSettings);
431         for (auto& rangeValue : list) {
432             auto& feature = downcast<CSSFontFeatureValue>(rangeValue.get());
433             settings.insert({ feature.tag(), feature.value() });
434         }
435     }
436
437     if (m_featureSettings == settings)
438         return;
439
440     m_featureSettings = WTFMove(settings);
441
442     if (m_cssConnection)
443         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontFeatureSettings, &featureSettings);
444
445     iterateClients(m_clients, [&](Client& client) {
446         client.fontPropertyChanged(*this);
447     });
448 }
449
450 void CSSFontFace::setLoadingBehavior(CSSValue& loadingBehaviorValue)
451 {
452     auto loadingBehavior = static_cast<FontLoadingBehavior>(downcast<CSSPrimitiveValue>(loadingBehaviorValue));
453
454     if (m_loadingBehavior == loadingBehavior)
455         return;
456
457     m_loadingBehavior = loadingBehavior;
458
459     if (m_cssConnection)
460         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontDisplay, &loadingBehaviorValue);
461
462     iterateClients(m_clients, [&](Client& client) {
463         client.fontPropertyChanged(*this);
464     });
465 }
466
467 bool CSSFontFace::rangesMatchCodePoint(UChar32 character) const
468 {
469     if (m_ranges.isEmpty())
470         return true;
471
472     for (auto& range : m_ranges) {
473         if (range.from <= character && character <= range.to)
474             return true;
475     }
476     return false;
477 }
478
479 void CSSFontFace::fontLoadEventOccurred()
480 {
481     // If the font is already in the cache, CSSFontFaceSource may report it's loaded before it is added here as a source.
482     // Let's not pump the state machine until we've got all our sources. font() and load() are smart enough to act correctly
483     // when a source is failed or succeeded before we have asked it to load.
484     if (m_sourcesPopulated)
485         pump(ExternalResourceDownloadPolicy::Forbid);
486
487     ASSERT(m_fontSelector);
488     m_fontSelector->fontLoaded();
489
490     iterateClients(m_clients, [&](Client& client) {
491         client.fontLoaded(*this);
492     });
493 }
494
495 void CSSFontFace::timeoutFired()
496 {
497     Ref<CSSFontFace> protectedThis(*this);
498     
499     switch (status()) {
500     case Status::Loading:
501         setStatus(Status::TimedOut);
502         break;
503     case Status::TimedOut:
504         // Cancelling the network request here could lead to a situation where a site's font never gets
505         // shown as the user navigates around to different pages on the site. This would occur if the
506         // download always takes longer than the timeout (even though the user may spend substantial time
507         // on each page). Therefore, we shouldn't cancel the network request here, but should use the
508         // loading infrastructure's timeout policies instead.
509         setStatus(Status::Failure);
510         break;
511     default:
512         ASSERT_NOT_REACHED();
513         break;
514     }
515
516     fontLoadEventOccurred();
517 }
518
519 bool CSSFontFace::computeFailureState() const
520 {
521     if (status() == Status::Failure)
522         return true;
523     for (auto& source : m_sources) {
524         if (source->status() != CSSFontFaceSource::Status::Failure)
525             return false;
526     }
527     return true;
528 }
529
530 void CSSFontFace::addClient(Client& client)
531 {
532     m_clients.add(&client);
533 }
534
535 void CSSFontFace::removeClient(Client& client)
536 {
537     ASSERT(m_clients.contains(&client));
538     m_clients.remove(&client);
539 }
540
541 void CSSFontFace::initializeWrapper()
542 {
543     switch (m_status) {
544     case Status::Pending:
545         break;
546     case Status::Loading:
547         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
548         break;
549     case Status::TimedOut:
550         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
551         m_wrapper->fontStateChanged(*this, Status::Loading, Status::TimedOut);
552         break;
553     case Status::Success:
554         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
555         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Success);
556         break;
557     case Status::Failure:
558         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
559         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Failure);
560         break;
561     }
562     m_mayBePurged = false;
563 }
564
565 Ref<FontFace> CSSFontFace::wrapper()
566 {
567     if (m_wrapper)
568         return *m_wrapper.get();
569
570     auto wrapper = FontFace::create(*this);
571     m_wrapper = makeWeakPtr(wrapper.get());
572     initializeWrapper();
573     return wrapper;
574 }
575
576 void CSSFontFace::setWrapper(FontFace& newWrapper)
577 {
578     m_wrapper = makeWeakPtr(newWrapper);
579     initializeWrapper();
580 }
581
582 void CSSFontFace::adoptSource(std::unique_ptr<CSSFontFaceSource>&& source)
583 {
584     m_sources.append(WTFMove(source));
585
586     // We should never add sources in the middle of loading.
587     ASSERT(!m_sourcesPopulated);
588 }
589
590 AllowUserInstalledFonts CSSFontFace::allowUserInstalledFonts() const
591 {
592     if (m_fontSelector && m_fontSelector->document())
593         return m_fontSelector->document()->settings().shouldAllowUserInstalledFonts() ? AllowUserInstalledFonts::Yes : AllowUserInstalledFonts::No;
594     return AllowUserInstalledFonts::Yes;
595 }
596
597 static Settings::FontLoadTimingOverride fontLoadTimingOverride(CSSFontSelector* fontSelector)
598 {
599     auto overrideValue = Settings::FontLoadTimingOverride::None;
600     if (fontSelector && fontSelector->document())
601         overrideValue = fontSelector->document()->settings().fontLoadTimingOverride();
602     return overrideValue;
603 }
604
605 auto CSSFontFace::fontLoadTiming() const -> FontLoadTiming
606 {
607     switch (fontLoadTimingOverride(m_fontSelector.get())) {
608     case Settings::FontLoadTimingOverride::None:
609         switch (m_loadingBehavior) {
610         case FontLoadingBehavior::Auto:
611         case FontLoadingBehavior::Block:
612             return { 3_s, Seconds::infinity() };
613         case FontLoadingBehavior::Swap:
614             return { 0_s, Seconds::infinity() };
615         case FontLoadingBehavior::Fallback:
616             return { 0.1_s, 3_s };
617         case FontLoadingBehavior::Optional:
618             return { 0.1_s, 0_s };
619         }
620         RELEASE_ASSERT_NOT_REACHED();
621     case Settings::FontLoadTimingOverride::Block:
622         return { Seconds::infinity(), 0_s };
623     case Settings::FontLoadTimingOverride::Swap:
624         return { 0_s, Seconds::infinity() };
625     case Settings::FontLoadTimingOverride::Failure:
626         return { 0_s, 0_s };
627     }
628     RELEASE_ASSERT_NOT_REACHED();
629 }
630
631 void CSSFontFace::setStatus(Status newStatus)
632 {
633     switch (newStatus) {
634     case Status::Pending:
635         ASSERT_NOT_REACHED();
636         break;
637     case Status::Loading:
638         ASSERT(m_status == Status::Pending);
639         break;
640     case Status::TimedOut:
641         ASSERT(m_status == Status::Loading);
642         break;
643     case Status::Success:
644         ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
645         break;
646     case Status::Failure:
647         ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
648         break;
649     }
650
651     iterateClients(m_clients, [&](Client& client) {
652         client.fontStateChanged(*this, m_status, newStatus);
653     });
654
655     m_status = newStatus;
656
657     Seconds blockPeriodTimeout;
658     Seconds swapPeriodTimeout;
659     auto timeouts = fontLoadTiming();
660     blockPeriodTimeout = timeouts.blockPeriod;
661     swapPeriodTimeout = timeouts.swapPeriod;
662
663     // Transfer across 0-delay timers synchronously. Layouts/script may
664     // take arbitrarily long time, and we shouldn't be in a 0-duration
665     // state for an arbitrarily long time. Also it's necessary for
666     // testing so we don't have a race with the font load.
667     switch (newStatus) {
668     case Status::Pending:
669         ASSERT_NOT_REACHED();
670         break;
671     case Status::Loading:
672         if (blockPeriodTimeout == 0_s)
673             setStatus(Status::TimedOut);
674         else if (std::isfinite(blockPeriodTimeout.value()))
675             m_timeoutTimer.startOneShot(blockPeriodTimeout);
676         break;
677     case Status::TimedOut:
678         if (swapPeriodTimeout == 0_s)
679             setStatus(Status::Failure);
680         else if (std::isfinite(swapPeriodTimeout.value()))
681             m_timeoutTimer.startOneShot(swapPeriodTimeout);
682         break;
683     case Status::Success:
684     case Status::Failure:
685         m_timeoutTimer.stop();
686         break;
687     }
688 }
689
690 void CSSFontFace::fontLoaded(CSSFontFaceSource&)
691 {
692     Ref<CSSFontFace> protectedThis(*this);
693     
694     fontLoadEventOccurred();
695 }
696
697 bool CSSFontFace::shouldIgnoreFontLoadCompletions() const
698 {
699     if (m_fontSelector && m_fontSelector->document())
700         return m_fontSelector->document()->settings().shouldIgnoreFontLoadCompletions();
701     return false;
702 }
703
704 void CSSFontFace::opportunisticallyStartFontDataURLLoading(CSSFontSelector& fontSelector)
705 {
706     // We don't want to go crazy here and blow the cache. Usually these data URLs are the first item in the src: list, so let's just check that one.
707     if (!m_sources.isEmpty())
708         m_sources[0]->opportunisticallyStartFontDataURLLoading(fontSelector);
709 }
710
711 size_t CSSFontFace::pump(ExternalResourceDownloadPolicy policy)
712 {
713     if (status() == Status::Failure)
714         return 0;
715
716     size_t i;
717     for (i = 0; i < m_sources.size(); ++i) {
718         auto& source = m_sources[i];
719
720         if (source->status() == CSSFontFaceSource::Status::Pending) {
721             ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut);
722             // This is a little tricky. After calling CSSFontFace::font(Forbid), a font must never fail later in
723             // this turn of the runloop because the return value of CSSFontFace::font() shouldn't get nulled out
724             // from under an existing FontRanges object. Remote fonts are all downloaded asynchronously, so this
725             // isn't a problem for them because CSSFontFace::font() will always return the interstitial font.
726             // However, local fonts may synchronously fail when you call load() on them. Therefore, we have to call
727             // load() here in order to guarantee that, if the font synchronously fails, it happens now during the
728             // first call to CSSFontFace::font() and the FontRanges object sees a consistent view of the
729             // CSSFontFace. This means we eagerly create some internal font objects when they may not be needed,
730             // but it seems that this behavior is a requirement of the design of FontRanges. FIXME: Perhaps rethink
731             // this design.
732             if (policy == ExternalResourceDownloadPolicy::Allow || !source->requiresExternalResource()) {
733                 if (m_status == Status::Pending)
734                     setStatus(Status::Loading);
735                 source->load(m_fontSelector.get());
736             }
737         }
738
739         switch (source->status()) {
740         case CSSFontFaceSource::Status::Pending:
741             ASSERT(policy == ExternalResourceDownloadPolicy::Forbid);
742             return i;
743         case CSSFontFaceSource::Status::Loading:
744             ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut || m_status == Status::Failure);
745             if (m_status == Status::Pending)
746                 setStatus(Status::Loading);
747             return i;
748         case CSSFontFaceSource::Status::Success:
749             ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut || m_status == Status::Success || m_status == Status::Failure);
750             if (m_status == Status::Pending)
751                 setStatus(Status::Loading);
752             if (m_status == Status::Loading || m_status == Status::TimedOut)
753                 setStatus(Status::Success);
754             return i;
755         case CSSFontFaceSource::Status::Failure:
756             if (m_status == Status::Pending)
757                 setStatus(Status::Loading);
758             break;
759         }
760     }
761     if (m_sources.isEmpty() && m_status == Status::Pending)
762         setStatus(Status::Loading);
763     if (m_status == Status::Loading || m_status == Status::TimedOut)
764         setStatus(Status::Failure);
765     return m_sources.size();
766 }
767
768 void CSSFontFace::load()
769 {
770     pump(ExternalResourceDownloadPolicy::Allow);
771 }
772
773 static Font::Visibility visibility(CSSFontFace::Status status, CSSFontFace::FontLoadTiming timing)
774 {
775     switch (status) {
776     case CSSFontFace::Status::Pending:
777         return timing.blockPeriod == 0_s ? Font::Visibility::Visible : Font::Visibility::Invisible;
778     case CSSFontFace::Status::Loading:
779         return Font::Visibility::Invisible;
780     case CSSFontFace::Status::TimedOut:
781     case CSSFontFace::Status::Failure:
782     case CSSFontFace::Status::Success:
783     default:
784         return Font::Visibility::Visible;
785     }
786 }
787
788 RefPtr<Font> CSSFontFace::font(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic, ExternalResourceDownloadPolicy policy)
789 {
790     if (computeFailureState())
791         return nullptr;
792
793     Ref<CSSFontFace> protectedThis(*this);
794     
795     // Our status is derived from the first non-failed source. However, this source may
796     // return null from font(), which means we need to continue looping through the remainder
797     // of the sources to try to find a font to use. These subsequent tries should not affect
798     // our own state, though.
799     size_t startIndex = pump(policy);
800
801     if (computeFailureState())
802         return nullptr;
803
804     for (size_t i = startIndex; i < m_sources.size(); ++i) {
805         auto& source = m_sources[i];
806         if (source->status() == CSSFontFaceSource::Status::Pending && (policy == ExternalResourceDownloadPolicy::Allow || !source->requiresExternalResource()))
807             source->load(m_fontSelector.get());
808
809         switch (source->status()) {
810         case CSSFontFaceSource::Status::Pending:
811         case CSSFontFaceSource::Status::Loading: {
812             Font::Visibility visibility = WebCore::visibility(status(), fontLoadTiming());
813             return Font::create(FontCache::singleton().lastResortFallbackFont(fontDescription)->platformData(), Font::Origin::Local, Font::Interstitial::Yes, visibility);
814         }
815         case CSSFontFaceSource::Status::Success:
816             if (RefPtr<Font> result = source->font(fontDescription, syntheticBold, syntheticItalic, m_featureSettings, m_variantSettings, m_fontSelectionCapabilities))
817                 return result;
818             break;
819         case CSSFontFaceSource::Status::Failure:
820             break;
821         }
822     }
823
824     return nullptr;
825 }
826
827 bool CSSFontFace::purgeable() const
828 {
829     return cssConnection() && m_mayBePurged;
830 }
831
832 void CSSFontFace::updateStyleIfNeeded()
833 {
834     if (m_fontSelector && m_fontSelector->document())
835         m_fontSelector->document()->updateStyleIfNeeded();
836 }
837
838 #if ENABLE(SVG_FONTS)
839 bool CSSFontFace::hasSVGFontFaceSource() const
840 {
841     size_t size = m_sources.size();
842     for (size_t i = 0; i < size; i++) {
843         if (m_sources[i]->isSVGFontFaceSource())
844             return true;
845     }
846     return false;
847 }
848 #endif
849
850 }