REGRESSION(r244635): [GTK] Wrong background color used in non-dark mode
[WebKit-https.git] / Source / WebCore / css / FontFace.cpp
1 /*
2  * Copyright (C) 2016 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 "FontFace.h"
28
29 #include "CSSComputedStyleDeclaration.h"
30 #include "CSSFontFaceSource.h"
31 #include "CSSFontFeatureValue.h"
32 #include "CSSFontStyleValue.h"
33 #include "CSSParser.h"
34 #include "CSSPrimitiveValueMappings.h"
35 #include "CSSUnicodeRangeValue.h"
36 #include "CSSValueList.h"
37 #include "CSSValuePool.h"
38 #include "Document.h"
39 #include "FontVariantBuilder.h"
40 #include "JSFontFace.h"
41 #include "StyleProperties.h"
42 #include <JavaScriptCore/ArrayBuffer.h>
43 #include <JavaScriptCore/ArrayBufferView.h>
44 #include <JavaScriptCore/JSCInlines.h>
45 #include <wtf/text/StringBuilder.h>
46
47 namespace WebCore {
48
49 static bool populateFontFaceWithArrayBuffer(CSSFontFace& fontFace, Ref<JSC::ArrayBufferView>&& arrayBufferView)
50 {
51     auto source = std::make_unique<CSSFontFaceSource>(fontFace, String(), nullptr, nullptr, WTFMove(arrayBufferView));
52     fontFace.adoptSource(WTFMove(source));
53     return false;
54 }
55
56 ExceptionOr<Ref<FontFace>> FontFace::create(Document& document, const String& family, Source&& source, const Descriptors& descriptors)
57 {
58     auto result = adoptRef(*new FontFace(document.fontSelector()));
59
60     bool dataRequiresAsynchronousLoading = true;
61
62     auto setFamilyResult = result->setFamily(family);
63     if (setFamilyResult.hasException())
64         return setFamilyResult.releaseException();
65
66     auto sourceConversionResult = WTF::switchOn(source,
67         [&] (String& string) -> ExceptionOr<void> {
68             auto value = FontFace::parseString(string, CSSPropertySrc);
69             if (!is<CSSValueList>(value))
70                 return Exception { SyntaxError };
71             CSSFontFace::appendSources(result->backing(), downcast<CSSValueList>(*value), &document, false);
72             return { };
73         },
74         [&] (RefPtr<ArrayBufferView>& arrayBufferView) -> ExceptionOr<void> {
75             dataRequiresAsynchronousLoading = populateFontFaceWithArrayBuffer(result->backing(), arrayBufferView.releaseNonNull());
76             return { };
77         },
78         [&] (RefPtr<ArrayBuffer>& arrayBuffer) -> ExceptionOr<void> {
79             unsigned byteLength = arrayBuffer->byteLength();
80             auto arrayBufferView = JSC::Uint8Array::create(WTFMove(arrayBuffer), 0, byteLength);
81             dataRequiresAsynchronousLoading = populateFontFaceWithArrayBuffer(result->backing(), WTFMove(arrayBufferView));
82             return { };
83         }
84     );
85
86     if (sourceConversionResult.hasException())
87         return sourceConversionResult.releaseException();
88
89     // These ternaries match the default strings inside the FontFaceDescriptors dictionary inside FontFace.idl.
90     auto setStyleResult = result->setStyle(descriptors.style.isEmpty() ? "normal"_s : descriptors.style);
91     if (setStyleResult.hasException())
92         return setStyleResult.releaseException();
93     auto setWeightResult = result->setWeight(descriptors.weight.isEmpty() ? "normal"_s : descriptors.weight);
94     if (setWeightResult.hasException())
95         return setWeightResult.releaseException();
96     auto setStretchResult = result->setStretch(descriptors.stretch.isEmpty() ? "normal"_s : descriptors.stretch);
97     if (setStretchResult.hasException())
98         return setStretchResult.releaseException();
99     auto setUnicodeRangeResult = result->setUnicodeRange(descriptors.unicodeRange.isEmpty() ? "U+0-10FFFF"_s : descriptors.unicodeRange);
100     if (setUnicodeRangeResult.hasException())
101         return setUnicodeRangeResult.releaseException();
102     auto setVariantResult = result->setVariant(descriptors.variant.isEmpty() ? "normal"_s : descriptors.variant);
103     if (setVariantResult.hasException())
104         return setVariantResult.releaseException();
105     auto setFeatureSettingsResult = result->setFeatureSettings(descriptors.featureSettings.isEmpty() ? "normal"_s : descriptors.featureSettings);
106     if (setFeatureSettingsResult.hasException())
107         return setFeatureSettingsResult.releaseException();
108     auto setDisplayResult = result->setDisplay(descriptors.display.isEmpty() ? "auto"_s : descriptors.display);
109     if (setDisplayResult.hasException())
110         return setDisplayResult.releaseException();
111
112     if (!dataRequiresAsynchronousLoading) {
113         result->backing().load();
114         auto status = result->backing().status();
115         ASSERT_UNUSED(status, status == CSSFontFace::Status::Success || status == CSSFontFace::Status::Failure);
116     }
117
118     return result;
119 }
120
121 Ref<FontFace> FontFace::create(CSSFontFace& face)
122 {
123     return adoptRef(*new FontFace(face));
124 }
125
126 FontFace::FontFace(CSSFontSelector& fontSelector)
127     : m_backing(CSSFontFace::create(&fontSelector, nullptr, this))
128     , m_loadedPromise(*this, &FontFace::loadedPromiseResolve)
129 {
130     m_backing->addClient(*this);
131 }
132
133 FontFace::FontFace(CSSFontFace& face)
134     : m_backing(face)
135     , m_loadedPromise(*this, &FontFace::loadedPromiseResolve)
136 {
137     m_backing->addClient(*this);
138 }
139
140 FontFace::~FontFace()
141 {
142     m_backing->removeClient(*this);
143 }
144
145 RefPtr<CSSValue> FontFace::parseString(const String& string, CSSPropertyID propertyID)
146 {
147     // FIXME: Should use the Document to get the right parsing mode.
148     return CSSParser::parseFontFaceDescriptor(propertyID, string, HTMLStandardMode);
149 }
150
151 ExceptionOr<void> FontFace::setFamily(const String& family)
152 {
153     if (family.isEmpty())
154         return Exception { SyntaxError };
155
156     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=196381 Don't use a list here.
157     // See consumeFontFamilyDescriptor() in CSSPropertyParser.cpp for why we're using it.
158     auto list = CSSValueList::createCommaSeparated();
159     list->append(CSSValuePool::singleton().createFontFamilyValue(family));
160     bool success = m_backing->setFamilies(list);
161     if (!success)
162         return Exception { SyntaxError };
163     return { };
164 }
165
166 ExceptionOr<void> FontFace::setStyle(const String& style)
167 {
168     if (style.isEmpty())
169         return Exception { SyntaxError };
170
171     if (auto value = parseString(style, CSSPropertyFontStyle)) {
172         m_backing->setStyle(*value);
173         return { };
174     }
175     return Exception { SyntaxError };
176 }
177
178 ExceptionOr<void> FontFace::setWeight(const String& weight)
179 {
180     if (weight.isEmpty())
181         return Exception { SyntaxError };
182
183     if (auto value = parseString(weight, CSSPropertyFontWeight)) {
184         m_backing->setWeight(*value);
185         return { };
186     }
187     return Exception { SyntaxError };
188 }
189
190 ExceptionOr<void> FontFace::setStretch(const String& stretch)
191 {
192     if (stretch.isEmpty())
193         return Exception { SyntaxError };
194
195     if (auto value = parseString(stretch, CSSPropertyFontStretch)) {
196         m_backing->setStretch(*value);
197         return { };
198     }
199     return Exception { SyntaxError };
200 }
201
202 ExceptionOr<void> FontFace::setUnicodeRange(const String& unicodeRange)
203 {
204     if (unicodeRange.isEmpty())
205         return Exception { SyntaxError };
206
207     bool success = false;
208     if (auto value = parseString(unicodeRange, CSSPropertyUnicodeRange))
209         success = m_backing->setUnicodeRange(*value);
210     if (!success)
211         return Exception { SyntaxError };
212     return { };
213 }
214
215 ExceptionOr<void> FontFace::setVariant(const String& variant)
216 {
217     if (variant.isEmpty())
218         return Exception { SyntaxError };
219
220     auto style = MutableStyleProperties::create();
221     auto result = CSSParser::parseValue(style, CSSPropertyFontVariant, variant, true, HTMLStandardMode);
222     if (result == CSSParser::ParseResult::Error)
223         return Exception { SyntaxError };
224
225     // FIXME: Would be much better to stage the new settings and set them all at once
226     // instead of this dance where we make a backup and revert to it if something fails.
227     FontVariantSettings backup = m_backing->variantSettings();
228
229     auto normal = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal);
230     bool success = true;
231
232     if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantLigatures))
233         success &= m_backing->setVariantLigatures(*value);
234     else
235         m_backing->setVariantLigatures(normal);
236
237     if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantPosition))
238         success &= m_backing->setVariantPosition(*value);
239     else
240         m_backing->setVariantPosition(normal);
241
242     if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantCaps))
243         success &= m_backing->setVariantCaps(*value);
244     else
245         m_backing->setVariantCaps(normal);
246
247     if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantNumeric))
248         success &= m_backing->setVariantNumeric(*value);
249     else
250         m_backing->setVariantNumeric(normal);
251
252     if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantAlternates))
253         success &= m_backing->setVariantAlternates(*value);
254     else
255         m_backing->setVariantAlternates(normal);
256
257     if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantEastAsian))
258         success &= m_backing->setVariantEastAsian(*value);
259     else
260         m_backing->setVariantEastAsian(normal);
261
262     if (!success) {
263         m_backing->setVariantSettings(backup);
264         return Exception { SyntaxError };
265     }
266
267     return { };
268 }
269
270 ExceptionOr<void> FontFace::setFeatureSettings(const String& featureSettings)
271 {
272     if (featureSettings.isEmpty())
273         return Exception { SyntaxError };
274
275     auto value = parseString(featureSettings, CSSPropertyFontFeatureSettings);
276     if (!value)
277         return Exception { SyntaxError };
278     m_backing->setFeatureSettings(*value);
279     return { };
280 }
281
282 ExceptionOr<void> FontFace::setDisplay(const String& display)
283 {
284     if (display.isEmpty())
285         return Exception { SyntaxError };
286
287     if (auto value = parseString(display, CSSPropertyFontDisplay)) {
288         m_backing->setLoadingBehavior(*value);
289         return { };
290     }
291
292     return Exception { SyntaxError };
293 }
294
295 String FontFace::family() const
296 {
297     m_backing->updateStyleIfNeeded();
298
299     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=196381 This is only here because CSSFontFace erroneously uses a list of values instead of a single value.
300     // See consumeFontFamilyDescriptor() in CSSPropertyParser.cpp.
301     if (m_backing->families()->length() == 1) {
302         if (m_backing->families()->item(0)) {
303             auto& item = *m_backing->families()->item(0);
304             if (item.isPrimitiveValue()) {
305                 auto& primitiveValue = downcast<CSSPrimitiveValue>(item);
306                 if (primitiveValue.isFontFamily()) {
307                     auto& fontFamily = primitiveValue.fontFamily();
308                     return fontFamily.familyName;
309                 }
310             }
311         }
312     }
313     return m_backing->families()->cssText();
314 }
315
316 String FontFace::style() const
317 {
318     m_backing->updateStyleIfNeeded();
319     auto style = m_backing->italic();
320
321     auto minimum = ComputedStyleExtractor::fontStyleFromStyleValue(style.minimum, FontStyleAxis::ital);
322     auto maximum = ComputedStyleExtractor::fontStyleFromStyleValue(style.maximum, FontStyleAxis::ital);
323
324     if (minimum.get().equals(maximum.get()))
325         return minimum->cssText();
326
327     auto minimumNonKeyword = ComputedStyleExtractor::fontNonKeywordStyleFromStyleValue(style.minimum);
328     auto maximumNonKeyword = ComputedStyleExtractor::fontNonKeywordStyleFromStyleValue(style.maximum);
329
330     ASSERT(minimumNonKeyword->fontStyleValue->valueID() == CSSValueOblique);
331     ASSERT(maximumNonKeyword->fontStyleValue->valueID() == CSSValueOblique);
332
333     StringBuilder builder;
334     builder.append(minimumNonKeyword->fontStyleValue->cssText());
335     builder.append(' ');
336     if (minimum->obliqueValue.get() == maximum->obliqueValue.get())
337         builder.append(minimumNonKeyword->obliqueValue->cssText());
338     else {
339         builder.append(minimumNonKeyword->obliqueValue->cssText());
340         builder.append(' ');
341         builder.append(maximumNonKeyword->obliqueValue->cssText());
342     }
343     return builder.toString();
344 }
345
346 String FontFace::weight() const
347 {
348     m_backing->updateStyleIfNeeded();
349     auto weight = m_backing->weight();
350
351     auto minimum = ComputedStyleExtractor::fontWeightFromStyleValue(weight.minimum);
352     auto maximum = ComputedStyleExtractor::fontWeightFromStyleValue(weight.maximum);
353
354     if (minimum.get().equals(maximum.get()))
355         return minimum->cssText();
356
357     auto minimumNonKeyword = ComputedStyleExtractor::fontNonKeywordWeightFromStyleValue(weight.minimum);
358     auto maximumNonKeyword = ComputedStyleExtractor::fontNonKeywordWeightFromStyleValue(weight.maximum);
359
360     StringBuilder builder;
361     builder.append(minimumNonKeyword->cssText());
362     builder.append(' ');
363     builder.append(maximumNonKeyword->cssText());
364     return builder.toString();
365 }
366
367 String FontFace::stretch() const
368 {
369     m_backing->updateStyleIfNeeded();
370     auto stretch = m_backing->stretch();
371
372     auto minimum = ComputedStyleExtractor::fontStretchFromStyleValue(stretch.minimum);
373     auto maximum = ComputedStyleExtractor::fontStretchFromStyleValue(stretch.maximum);
374
375     if (minimum.get().equals(maximum.get()))
376         return minimum->cssText();
377
378     auto minimumNonKeyword = ComputedStyleExtractor::fontNonKeywordStretchFromStyleValue(stretch.minimum);
379     auto maximumNonKeyword = ComputedStyleExtractor::fontNonKeywordStretchFromStyleValue(stretch.maximum);
380
381     StringBuilder builder;
382     builder.append(minimumNonKeyword->cssText());
383     builder.append(' ');
384     builder.append(maximumNonKeyword->cssText());
385     return builder.toString();
386 }
387
388 String FontFace::unicodeRange() const
389 {
390     m_backing->updateStyleIfNeeded();
391     if (!m_backing->ranges().size())
392         return "U+0-10FFFF"_s;
393     auto values = CSSValueList::createCommaSeparated();
394     for (auto& range : m_backing->ranges())
395         values->append(CSSUnicodeRangeValue::create(range.from, range.to));
396     return values->cssText();
397 }
398
399 String FontFace::variant() const
400 {
401     m_backing->updateStyleIfNeeded();
402     return computeFontVariant(m_backing->variantSettings())->cssText();
403 }
404
405 String FontFace::featureSettings() const
406 {
407     m_backing->updateStyleIfNeeded();
408     if (!m_backing->featureSettings().size())
409         return "normal"_s;
410     auto list = CSSValueList::createCommaSeparated();
411     for (auto& feature : m_backing->featureSettings())
412         list->append(CSSFontFeatureValue::create(FontTag(feature.tag()), feature.value()));
413     return list->cssText();
414 }
415
416 String FontFace::display() const
417 {
418     m_backing->updateStyleIfNeeded();
419     return CSSValuePool::singleton().createValue(m_backing->loadingBehavior())->cssText();
420 }
421
422 auto FontFace::status() const -> LoadStatus
423 {
424     switch (m_backing->status()) {
425     case CSSFontFace::Status::Pending:
426         return LoadStatus::Unloaded;
427     case CSSFontFace::Status::Loading:
428         return LoadStatus::Loading;
429     case CSSFontFace::Status::TimedOut:
430         return LoadStatus::Error;
431     case CSSFontFace::Status::Success:
432         return LoadStatus::Loaded;
433     case CSSFontFace::Status::Failure:
434         return LoadStatus::Error;
435     }
436     ASSERT_NOT_REACHED();
437     return LoadStatus::Error;
438 }
439
440 void FontFace::adopt(CSSFontFace& newFace)
441 {
442     m_backing->removeClient(*this);
443     m_backing = newFace;
444     m_backing->addClient(*this);
445     newFace.setWrapper(*this);
446 }
447
448 void FontFace::fontStateChanged(CSSFontFace& face, CSSFontFace::Status, CSSFontFace::Status newState)
449 {
450     ASSERT_UNUSED(face, &face == m_backing.ptr());
451     switch (newState) {
452     case CSSFontFace::Status::Loading:
453         // We still need to resolve promises when loading completes, even if all references to use have fallen out of scope.
454         ref();
455         break;
456     case CSSFontFace::Status::TimedOut:
457         break;
458     case CSSFontFace::Status::Success:
459         // FIXME: This check should not be needed, but because FontFace's are sometimes adopted after they have already
460         // gone through a load cycle, we can sometimes come back through here and try to resolve the promise again.  
461         if (!m_loadedPromise.isFulfilled())
462             m_loadedPromise.resolve(*this);
463         deref();
464         return;
465     case CSSFontFace::Status::Failure:
466         // FIXME: This check should not be needed, but because FontFace's are sometimes adopted after they have already
467         // gone through a load cycle, we can sometimes come back through here and try to resolve the promise again.  
468         if (!m_loadedPromise.isFulfilled())
469             m_loadedPromise.reject(Exception { NetworkError });
470         deref();
471         return;
472     case CSSFontFace::Status::Pending:
473         ASSERT_NOT_REACHED();
474         return;
475     }
476 }
477
478 auto FontFace::load() -> LoadedPromise&
479 {
480     m_backing->load();
481     return m_loadedPromise;
482 }
483
484 FontFace& FontFace::loadedPromiseResolve()
485 {
486     return *this;
487 }
488
489 }