4788fbb89e3cf37d1855ea7cd40a339234af959a
[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     setWeight(range);
153
154     if (m_cssConnection)
155         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontWeight, &weight);
156
157     iterateClients(m_clients, [&](Client& client) {
158         client.fontPropertyChanged(*this);
159     });
160 }
161
162 static FontSelectionRange calculateStretchRange(CSSValue& value)
163 {
164     if (value.isValueList()) {
165         auto& valueList = downcast<CSSValueList>(value);
166         ASSERT(valueList.length() == 2);
167         if (valueList.length() != 2)
168             return { normalStretchValue(), normalStretchValue() };
169         ASSERT(valueList.item(0)->isPrimitiveValue());
170         ASSERT(valueList.item(1)->isPrimitiveValue());
171         auto& value0 = downcast<CSSPrimitiveValue>(*valueList.item(0));
172         auto& value1 = downcast<CSSPrimitiveValue>(*valueList.item(1));
173         auto result0 = StyleBuilderConverter::convertFontStretchFromValue(value0);
174         auto result1 = StyleBuilderConverter::convertFontStretchFromValue(value1);
175         return { result0, result1 };
176     }
177
178     ASSERT(is<CSSPrimitiveValue>(value));
179     const auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
180     FontSelectionValue result = StyleBuilderConverter::convertFontStretchFromValue(primitiveValue);
181     return { result, result };
182 }
183
184 void CSSFontFace::setStretch(CSSValue& style)
185 {
186     auto range = calculateStretchRange(style);
187     setStretch(range);
188
189     if (m_cssConnection)
190         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontStretch, &style);
191
192     iterateClients(m_clients, [&](Client& client) {
193         client.fontPropertyChanged(*this);
194     });
195 }
196
197 static FontSelectionRange calculateItalicRange(CSSValue& value)
198 {
199     if (value.isFontStyleValue()) {
200         auto result = StyleBuilderConverter::convertFontStyleFromValue(value);
201         return { result, result };
202     }
203
204     ASSERT(value.isFontStyleRangeValue());
205     auto& rangeValue = downcast<CSSFontStyleRangeValue>(value);
206     ASSERT(rangeValue.fontStyleValue->isValueID());
207     auto valueID = rangeValue.fontStyleValue->valueID();
208     if (!rangeValue.obliqueValues) {
209         if (valueID == CSSValueNormal)
210             return { normalItalicValue(), normalItalicValue() };
211         ASSERT(valueID == CSSValueItalic || valueID == CSSValueOblique);
212         return { italicValue(), italicValue() };
213     }
214     ASSERT(valueID == CSSValueOblique);
215     auto length = rangeValue.obliqueValues->length();
216     if (length == 1) {
217         auto& primitiveValue = downcast<CSSPrimitiveValue>(*rangeValue.obliqueValues->item(0));
218         FontSelectionValue result(primitiveValue.value<float>(CSSPrimitiveValue::CSS_DEG));
219         return { result, result };
220     }
221     ASSERT(length == 2);
222     auto& primitiveValue1 = downcast<CSSPrimitiveValue>(*rangeValue.obliqueValues->item(0));
223     auto& primitiveValue2 = downcast<CSSPrimitiveValue>(*rangeValue.obliqueValues->item(1));
224     FontSelectionValue result1(primitiveValue1.value<float>(CSSPrimitiveValue::CSS_DEG));
225     FontSelectionValue result2(primitiveValue2.value<float>(CSSPrimitiveValue::CSS_DEG));
226     return { result1, result2 };
227 }
228
229 void CSSFontFace::setStyle(CSSValue& style)
230 {
231     auto range = calculateItalicRange(style);
232     setStyle(range);
233
234     if (m_cssConnection)
235         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontStyle, &style);
236
237     iterateClients(m_clients, [&](Client& client) {
238         client.fontPropertyChanged(*this);
239     });
240 }
241
242 bool CSSFontFace::setUnicodeRange(CSSValue& unicodeRange)
243 {
244     if (!is<CSSValueList>(unicodeRange))
245         return false;
246
247     m_ranges.clear();
248     auto& list = downcast<CSSValueList>(unicodeRange);
249     for (auto& rangeValue : list) {
250         auto& range = downcast<CSSUnicodeRangeValue>(rangeValue.get());
251         m_ranges.append({ range.from(), range.to() });
252     }
253
254     if (m_cssConnection)
255         m_cssConnection->mutableProperties().setProperty(CSSPropertyUnicodeRange, &unicodeRange);
256
257     iterateClients(m_clients, [&](Client& client) {
258         client.fontPropertyChanged(*this);
259     });
260
261     return true;
262 }
263
264 bool CSSFontFace::setVariantLigatures(CSSValue& variantLigatures)
265 {
266     auto ligatures = extractFontVariantLigatures(variantLigatures);
267
268     m_variantSettings.commonLigatures = ligatures.commonLigatures;
269     m_variantSettings.discretionaryLigatures = ligatures.discretionaryLigatures;
270     m_variantSettings.historicalLigatures = ligatures.historicalLigatures;
271     m_variantSettings.contextualAlternates = ligatures.contextualAlternates;
272
273     if (m_cssConnection)
274         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantLigatures, &variantLigatures);
275
276     iterateClients(m_clients, [&](Client& client) {
277         client.fontPropertyChanged(*this);
278     });
279
280     return true;
281 }
282
283 bool CSSFontFace::setVariantPosition(CSSValue& variantPosition)
284 {
285     if (!is<CSSPrimitiveValue>(variantPosition))
286         return false;
287
288     m_variantSettings.position = downcast<CSSPrimitiveValue>(variantPosition);
289
290     if (m_cssConnection)
291         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantPosition, &variantPosition);
292
293     iterateClients(m_clients, [&](Client& client) {
294         client.fontPropertyChanged(*this);
295     });
296
297     return true;
298 }
299
300 bool CSSFontFace::setVariantCaps(CSSValue& variantCaps)
301 {
302     if (!is<CSSPrimitiveValue>(variantCaps))
303         return false;
304
305     m_variantSettings.caps = downcast<CSSPrimitiveValue>(variantCaps);
306
307     if (m_cssConnection)
308         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantCaps, &variantCaps);
309
310     iterateClients(m_clients, [&](Client& client) {
311         client.fontPropertyChanged(*this);
312     });
313
314     return true;
315 }
316
317 bool CSSFontFace::setVariantNumeric(CSSValue& variantNumeric)
318 {
319     auto numeric = extractFontVariantNumeric(variantNumeric);
320
321     m_variantSettings.numericFigure = numeric.figure;
322     m_variantSettings.numericSpacing = numeric.spacing;
323     m_variantSettings.numericFraction = numeric.fraction;
324     m_variantSettings.numericOrdinal = numeric.ordinal;
325     m_variantSettings.numericSlashedZero = numeric.slashedZero;
326
327     if (m_cssConnection)
328         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantNumeric, &variantNumeric);
329
330     iterateClients(m_clients, [&](Client& client) {
331         client.fontPropertyChanged(*this);
332     });
333
334     return true;
335 }
336
337 bool CSSFontFace::setVariantAlternates(CSSValue& variantAlternates)
338 {
339     if (!is<CSSPrimitiveValue>(variantAlternates))
340         return false;
341
342     m_variantSettings.alternates = downcast<CSSPrimitiveValue>(variantAlternates);
343
344     if (m_cssConnection)
345         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantAlternates, &variantAlternates);
346
347     iterateClients(m_clients, [&](Client& client) {
348         client.fontPropertyChanged(*this);
349     });
350
351     return true;
352 }
353
354 bool CSSFontFace::setVariantEastAsian(CSSValue& variantEastAsian)
355 {
356     auto eastAsian = extractFontVariantEastAsian(variantEastAsian);
357
358     m_variantSettings.eastAsianVariant = eastAsian.variant;
359     m_variantSettings.eastAsianWidth = eastAsian.width;
360     m_variantSettings.eastAsianRuby = eastAsian.ruby;
361
362     if (m_cssConnection)
363         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantEastAsian, &variantEastAsian);
364
365     iterateClients(m_clients, [&](Client& client) {
366         client.fontPropertyChanged(*this);
367     });
368
369     return true;
370 }
371
372 void CSSFontFace::setFeatureSettings(CSSValue& featureSettings)
373 {
374     // Can only call this with a primitive value of normal, or a value list containing font feature values.
375     ASSERT(is<CSSPrimitiveValue>(featureSettings) || is<CSSValueList>(featureSettings));
376
377     FontFeatureSettings settings;
378
379     if (is<CSSValueList>(featureSettings)) {
380         auto& list = downcast<CSSValueList>(featureSettings);
381         for (auto& rangeValue : list) {
382             auto& feature = downcast<CSSFontFeatureValue>(rangeValue.get());
383             settings.insert({ feature.tag(), feature.value() });
384         }
385     }
386
387     if (m_featureSettings == settings)
388         return;
389
390     m_featureSettings = WTFMove(settings);
391
392     if (m_cssConnection)
393         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontFeatureSettings, &featureSettings);
394
395     iterateClients(m_clients, [&](Client& client) {
396         client.fontPropertyChanged(*this);
397     });
398 }
399
400 bool CSSFontFace::rangesMatchCodePoint(UChar32 character) const
401 {
402     if (m_ranges.isEmpty())
403         return true;
404
405     for (auto& range : m_ranges) {
406         if (range.from <= character && character <= range.to)
407             return true;
408     }
409     return false;
410 }
411
412 void CSSFontFace::fontLoadEventOccurred()
413 {
414     Ref<CSSFontFace> protectedThis(*this);
415
416     // If the font is already in the cache, CSSFontFaceSource may report it's loaded before it is added here as a source.
417     // Let's not pump the state machine until we've got all our sources. font() and load() are smart enough to act correctly
418     // when a source is failed or succeeded before we have asked it to load.
419     if (m_sourcesPopulated && !webFontsShouldAlwaysFallBack())
420         pump(ExternalResourceDownloadPolicy::Forbid);
421
422     ASSERT(m_fontSelector);
423     m_fontSelector->fontLoaded();
424
425     iterateClients(m_clients, [&](Client& client) {
426         client.fontLoaded(*this);
427     });
428 }
429
430 void CSSFontFace::timeoutFired()
431 {
432     setStatus(Status::TimedOut);
433
434     fontLoadEventOccurred();
435 }
436
437 bool CSSFontFace::allSourcesFailed() const
438 {
439     for (auto& source : m_sources) {
440         if (source->status() != CSSFontFaceSource::Status::Failure)
441             return false;
442     }
443     return true;
444 }
445
446 void CSSFontFace::addClient(Client& client)
447 {
448     m_clients.add(&client);
449 }
450
451 void CSSFontFace::removeClient(Client& client)
452 {
453     ASSERT(m_clients.contains(&client));
454     m_clients.remove(&client);
455 }
456
457 void CSSFontFace::initializeWrapper()
458 {
459     switch (m_status) {
460     case Status::Pending:
461         break;
462     case Status::Loading:
463         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
464         break;
465     case Status::TimedOut:
466         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
467         m_wrapper->fontStateChanged(*this, Status::Loading, Status::TimedOut);
468         break;
469     case Status::Success:
470         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
471         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Success);
472         break;
473     case Status::Failure:
474         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Loading);
475         m_wrapper->fontStateChanged(*this, Status::Pending, Status::Failure);
476         break;
477     }
478     m_mayBePurged = false;
479 }
480
481 Ref<FontFace> CSSFontFace::wrapper()
482 {
483     if (m_wrapper)
484         return *m_wrapper.get();
485
486     auto wrapper = FontFace::create(*this);
487     m_wrapper = wrapper->createWeakPtr();
488     initializeWrapper();
489     return wrapper;
490 }
491
492 void CSSFontFace::setWrapper(FontFace& newWrapper)
493 {
494     m_wrapper = newWrapper.createWeakPtr();
495     initializeWrapper();
496 }
497
498 void CSSFontFace::adoptSource(std::unique_ptr<CSSFontFaceSource>&& source)
499 {
500     m_sources.append(WTFMove(source));
501
502     // We should never add sources in the middle of loading.
503     ASSERT(!m_sourcesPopulated);
504 }
505
506 void CSSFontFace::setStatus(Status newStatus)
507 {
508     switch (newStatus) {
509     case Status::Pending:
510         ASSERT_NOT_REACHED();
511         break;
512     case Status::Loading:
513         ASSERT(m_status == Status::Pending);
514         break;
515     case Status::TimedOut:
516         ASSERT(m_status == Status::Loading);
517         break;
518     case Status::Success:
519         ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
520         break;
521     case Status::Failure:
522         ASSERT(m_status == Status::Loading || m_status == Status::TimedOut);
523         break;
524     }
525
526     bool webFontsShouldAlwaysFallBack = this->webFontsShouldAlwaysFallBack();
527     if (!webFontsShouldAlwaysFallBack) {
528         if (newStatus == Status::Loading) {
529             Seconds timeUntilInterstitialFontIsDrawnVisibly = 3_s;
530             m_timeoutTimer.startOneShot(timeUntilInterstitialFontIsDrawnVisibly);
531         } else if (newStatus == Status::Success || newStatus == Status::Failure)
532             m_timeoutTimer.stop();
533     }
534
535     iterateClients(m_clients, [&](Client& client) {
536         client.fontStateChanged(*this, m_status, newStatus);
537     });
538
539     m_status = newStatus;
540
541     if (newStatus == Status::Loading && webFontsShouldAlwaysFallBack)
542         timeoutFired();
543 }
544
545 void CSSFontFace::fontLoaded(CSSFontFaceSource&)
546 {
547     ASSERT(!webFontsShouldAlwaysFallBack());
548
549     fontLoadEventOccurred();
550 }
551
552 bool CSSFontFace::webFontsShouldAlwaysFallBack() const
553 {
554     return m_fontSelector && m_fontSelector->document() && m_fontSelector->document()->settings().webFontsAlwaysFallBack();
555 }
556
557 size_t CSSFontFace::pump(ExternalResourceDownloadPolicy policy)
558 {
559     size_t i;
560     for (i = 0; i < m_sources.size(); ++i) {
561         auto& source = m_sources[i];
562
563         if (source->status() == CSSFontFaceSource::Status::Pending) {
564             ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut);
565             if (policy == ExternalResourceDownloadPolicy::Allow || !source->requiresExternalResource()) {
566                 if (m_status == Status::Pending)
567                     setStatus(Status::Loading);
568                 source->load(m_fontSelector.get());
569             }
570         }
571
572         switch (source->status()) {
573         case CSSFontFaceSource::Status::Pending:
574             ASSERT(policy == ExternalResourceDownloadPolicy::Forbid);
575             return i;
576         case CSSFontFaceSource::Status::Loading:
577             ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut);
578             if (m_status == Status::Pending)
579                 setStatus(Status::Loading);
580             return i;
581         case CSSFontFaceSource::Status::Success:
582             ASSERT(m_status == Status::Pending || m_status == Status::Loading || m_status == Status::TimedOut || m_status == Status::Success);
583             if (m_status == Status::Pending)
584                 setStatus(Status::Loading);
585             if (m_status == Status::Loading || m_status == Status::TimedOut)
586                 setStatus(Status::Success);
587             return i;
588         case CSSFontFaceSource::Status::Failure:
589             if (m_status == Status::Pending)
590                 setStatus(Status::Loading);
591             break;
592         }
593     }
594     if (m_sources.isEmpty() && m_status == Status::Pending)
595         setStatus(Status::Loading);
596     if (m_status == Status::Loading || m_status == Status::TimedOut)
597         setStatus(Status::Failure);
598     return m_sources.size();
599 }
600
601 void CSSFontFace::load()
602 {
603     pump(ExternalResourceDownloadPolicy::Allow);
604 }
605
606 RefPtr<Font> CSSFontFace::font(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic, ExternalResourceDownloadPolicy policy)
607 {
608     if (allSourcesFailed())
609         return nullptr;
610
611     // Our status is derived from the first non-failed source. However, this source may
612     // return null from font(), which means we need to continue looping through the remainder
613     // of the sources to try to find a font to use. These subsequent tries should not affect
614     // our own state, though.
615     size_t startIndex = pump(policy);
616     for (size_t i = startIndex; i < m_sources.size(); ++i) {
617         auto& source = m_sources[i];
618         if (source->status() == CSSFontFaceSource::Status::Pending && (policy == ExternalResourceDownloadPolicy::Allow || !source->requiresExternalResource()))
619             source->load(m_fontSelector.get());
620
621         switch (source->status()) {
622         case CSSFontFaceSource::Status::Pending:
623         case CSSFontFaceSource::Status::Loading: {
624             Font::Visibility visibility = status() == Status::TimedOut ? Font::Visibility::Visible : Font::Visibility::Invisible;
625             return Font::create(FontCache::singleton().lastResortFallbackFont(fontDescription)->platformData(), Font::Origin::Remote, Font::Interstitial::Yes, visibility);
626         }
627         case CSSFontFaceSource::Status::Success:
628             if (RefPtr<Font> result = source->font(fontDescription, syntheticBold, syntheticItalic, m_featureSettings, m_variantSettings, m_fontSelectionCapabilities))
629                 return result;
630             break;
631         case CSSFontFaceSource::Status::Failure:
632             break;
633         }
634     }
635
636     return nullptr;
637 }
638
639 bool CSSFontFace::purgeable() const
640 {
641     return cssConnection() && m_mayBePurged;
642 }
643
644 void CSSFontFace::updateStyleIfNeeded()
645 {
646     if (m_fontSelector && m_fontSelector->document())
647         m_fontSelector->document()->updateStyleIfNeeded();
648 }
649
650 #if ENABLE(SVG_FONTS)
651 bool CSSFontFace::hasSVGFontFaceSource() const
652 {
653     size_t size = m_sources.size();
654     for (size_t i = 0; i < size; i++) {
655         if (m_sources[i]->isSVGFontFaceSource())
656             return true;
657     }
658     return false;
659 }
660 #endif
661
662 }