[WTF] Import std::optional reference implementation as WTF::Optional
[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 "CSSFontFaceSource.h"
30 #include "CSSFontFeatureValue.h"
31 #include "CSSParser.h"
32 #include "CSSUnicodeRangeValue.h"
33 #include "CSSValuePool.h"
34 #include "Document.h"
35 #include "FontVariantBuilder.h"
36 #include "JSFontFace.h"
37 #include "StyleProperties.h"
38
39 namespace WebCore {
40
41 static bool populateFontFaceWithArrayBuffer(CSSFontFace& fontFace, Ref<JSC::ArrayBufferView>&& arrayBufferView)
42 {
43     auto source = std::make_unique<CSSFontFaceSource>(fontFace, String(), nullptr, nullptr, WTFMove(arrayBufferView));
44     fontFace.adoptSource(WTFMove(source));
45     return false;
46 }
47
48 ExceptionOr<Ref<FontFace>> FontFace::create(JSC::ExecState& state, Document& document, const String& family, JSC::JSValue source, const Descriptors& descriptors)
49 {
50     auto result = adoptRef(*new FontFace(document.fontSelector()));
51
52     bool dataRequiresAsynchronousLoading = true;
53
54     auto setFamilyResult = result->setFamily(family);
55     if (setFamilyResult.hasException())
56         return setFamilyResult.releaseException();
57
58     if (source.isString()) {
59         auto value = FontFace::parseString(source.getString(&state), CSSPropertySrc);
60         if (!is<CSSValueList>(value.get()))
61             return Exception { SYNTAX_ERR };
62         CSSFontFace::appendSources(result->backing(), downcast<CSSValueList>(*value), &document, false);
63     } else if (auto arrayBufferView = toUnsharedArrayBufferView(source))
64         dataRequiresAsynchronousLoading = populateFontFaceWithArrayBuffer(result->backing(), arrayBufferView.releaseNonNull());
65     else if (auto arrayBuffer = toUnsharedArrayBuffer(source)) {
66         auto arrayBufferView = JSC::Uint8Array::create(arrayBuffer, 0, arrayBuffer->byteLength());
67         dataRequiresAsynchronousLoading = populateFontFaceWithArrayBuffer(result->backing(), arrayBufferView.releaseNonNull());
68     }
69
70     // These ternaries match the default strings inside the FontFaceDescriptors dictionary inside FontFace.idl.
71     auto setStyleResult = result->setStyle(descriptors.style.isEmpty() ? ASCIILiteral("normal") : descriptors.style);
72     if (setStyleResult.hasException())
73         return setStyleResult.releaseException();
74     auto setWeightResult = result->setWeight(descriptors.weight.isEmpty() ? ASCIILiteral("normal") : descriptors.weight);
75     if (setWeightResult.hasException())
76         return setWeightResult.releaseException();
77     auto setStretchResult = result->setStretch(descriptors.stretch.isEmpty() ? ASCIILiteral("normal") : descriptors.stretch);
78     if (setStretchResult.hasException())
79         return setStretchResult.releaseException();
80     auto setUnicodeRangeResult = result->setUnicodeRange(descriptors.unicodeRange.isEmpty() ? ASCIILiteral("U+0-10FFFF") : descriptors.unicodeRange);
81     if (setUnicodeRangeResult.hasException())
82         return setUnicodeRangeResult.releaseException();
83     auto setVariantResult = result->setVariant(descriptors.variant.isEmpty() ? ASCIILiteral("normal") : descriptors.variant);
84     if (setVariantResult.hasException())
85         return setVariantResult.releaseException();
86     auto setFeatureSettingsResult = result->setFeatureSettings(descriptors.featureSettings.isEmpty() ? ASCIILiteral("normal") : descriptors.featureSettings);
87     if (setFeatureSettingsResult.hasException())
88         return setFeatureSettingsResult.releaseException();
89
90     if (!dataRequiresAsynchronousLoading) {
91         result->backing().load();
92         ASSERT(result->backing().status() == CSSFontFace::Status::Success);
93     }
94
95     return WTFMove(result);
96 }
97
98 Ref<FontFace> FontFace::create(CSSFontFace& face)
99 {
100     return adoptRef(*new FontFace(face));
101 }
102
103 FontFace::FontFace(CSSFontSelector& fontSelector)
104     : m_weakPtrFactory(this)
105     , m_backing(CSSFontFace::create(&fontSelector, nullptr, this))
106 {
107     m_backing->addClient(*this);
108 }
109
110 FontFace::FontFace(CSSFontFace& face)
111     : m_weakPtrFactory(this)
112     , m_backing(face)
113 {
114     m_backing->addClient(*this);
115 }
116
117 FontFace::~FontFace()
118 {
119     m_backing->removeClient(*this);
120 }
121
122 WeakPtr<FontFace> FontFace::createWeakPtr() const
123 {
124     return m_weakPtrFactory.createWeakPtr();
125 }
126
127 RefPtr<CSSValue> FontFace::parseString(const String& string, CSSPropertyID propertyID)
128 {
129     auto style = MutableStyleProperties::create();
130     if (CSSParser::parseValue(style, propertyID, string, true, HTMLStandardMode, nullptr) == CSSParser::ParseResult::Error)
131         return nullptr;
132     return style->getPropertyCSSValue(propertyID);
133 }
134
135 ExceptionOr<void> FontFace::setFamily(const String& family)
136 {
137     if (family.isEmpty())
138         return Exception { SYNTAX_ERR };
139
140     bool success = false;
141     if (auto value = parseString(family, CSSPropertyFontFamily))
142         success = m_backing->setFamilies(*value);
143     if (!success)
144         return Exception { SYNTAX_ERR };
145     return { };
146 }
147
148 ExceptionOr<void> FontFace::setStyle(const String& style)
149 {
150     if (style.isEmpty())
151         return Exception { SYNTAX_ERR };
152
153     bool success = false;
154     if (auto value = parseString(style, CSSPropertyFontStyle))
155         success = m_backing->setStyle(*value);
156     if (!success)
157         return Exception { SYNTAX_ERR };
158     return { };
159 }
160
161 ExceptionOr<void> FontFace::setWeight(const String& weight)
162 {
163     if (weight.isEmpty())
164         return Exception { SYNTAX_ERR };
165
166     bool success = false;
167     if (auto value = parseString(weight, CSSPropertyFontWeight))
168         success = m_backing->setWeight(*value);
169     if (!success)
170         return Exception { SYNTAX_ERR };
171     return { };
172 }
173
174 ExceptionOr<void> FontFace::setStretch(const String&)
175 {
176     // We don't support font-stretch. Swallow the call.
177     return { };
178 }
179
180 ExceptionOr<void> FontFace::setUnicodeRange(const String& unicodeRange)
181 {
182     if (unicodeRange.isEmpty())
183         return Exception { SYNTAX_ERR };
184
185     bool success = false;
186     if (auto value = parseString(unicodeRange, CSSPropertyUnicodeRange))
187         success = m_backing->setUnicodeRange(*value);
188     if (!success)
189         return Exception { SYNTAX_ERR };
190     return { };
191 }
192
193 ExceptionOr<void> FontFace::setVariant(const String& variant)
194 {
195     if (variant.isEmpty())
196         return Exception { SYNTAX_ERR };
197
198     auto style = MutableStyleProperties::create();
199     auto result = CSSParser::parseValue(style, CSSPropertyFontVariant, variant, true, HTMLStandardMode, nullptr);
200     if (result == CSSParser::ParseResult::Error)
201         return Exception { SYNTAX_ERR };
202
203     // FIXME: Would be much better to stage the new settings and set them all at once
204     // instead of this dance where we make a backup and revert to it if something fails.
205     FontVariantSettings backup = m_backing->variantSettings();
206
207     auto normal = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal);
208     bool success = true;
209
210     if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantLigatures))
211         success &= m_backing->setVariantLigatures(*value);
212     else
213         m_backing->setVariantLigatures(normal);
214
215     if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantPosition))
216         success &= m_backing->setVariantPosition(*value);
217     else
218         m_backing->setVariantPosition(normal);
219
220     if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantCaps))
221         success &= m_backing->setVariantCaps(*value);
222     else
223         m_backing->setVariantCaps(normal);
224
225     if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantNumeric))
226         success &= m_backing->setVariantNumeric(*value);
227     else
228         m_backing->setVariantNumeric(normal);
229
230     if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantAlternates))
231         success &= m_backing->setVariantAlternates(*value);
232     else
233         m_backing->setVariantAlternates(normal);
234
235     if (auto value = style->getPropertyCSSValue(CSSPropertyFontVariantEastAsian))
236         success &= m_backing->setVariantEastAsian(*value);
237     else
238         m_backing->setVariantEastAsian(normal);
239
240     if (!success) {
241         m_backing->setVariantSettings(backup);
242         return Exception { SYNTAX_ERR };
243     }
244
245     return { };
246 }
247
248 ExceptionOr<void> FontFace::setFeatureSettings(const String& featureSettings)
249 {
250     if (featureSettings.isEmpty())
251         return Exception { SYNTAX_ERR };
252
253     auto value = parseString(featureSettings, CSSPropertyFontFeatureSettings);
254     if (!value)
255         return Exception { SYNTAX_ERR };
256     m_backing->setFeatureSettings(*value);
257     return { };
258 }
259
260 String FontFace::family() const
261 {
262     const_cast<CSSFontFace&>(m_backing.get()).updateStyleIfNeeded();
263     return m_backing->families()->cssText();
264 }
265
266 String FontFace::style() const
267 {
268     const_cast<CSSFontFace&>(m_backing.get()).updateStyleIfNeeded();
269     switch (m_backing->traitsMask() & FontStyleMask) {
270     case FontStyleNormalMask:
271         return String("normal", String::ConstructFromLiteral);
272     case FontStyleItalicMask:
273         return String("italic", String::ConstructFromLiteral);
274     }
275     ASSERT_NOT_REACHED();
276     return String("normal", String::ConstructFromLiteral);
277 }
278
279 String FontFace::weight() const
280 {
281     const_cast<CSSFontFace&>(m_backing.get()).updateStyleIfNeeded();
282     switch (m_backing->traitsMask() & FontWeightMask) {
283     case FontWeight100Mask:
284         return String("100", String::ConstructFromLiteral);
285     case FontWeight200Mask:
286         return String("200", String::ConstructFromLiteral);
287     case FontWeight300Mask:
288         return String("300", String::ConstructFromLiteral);
289     case FontWeight400Mask:
290         return String("normal", String::ConstructFromLiteral);
291     case FontWeight500Mask:
292         return String("500", String::ConstructFromLiteral);
293     case FontWeight600Mask:
294         return String("600", String::ConstructFromLiteral);
295     case FontWeight700Mask:
296         return String("bold", String::ConstructFromLiteral);
297     case FontWeight800Mask:
298         return String("800", String::ConstructFromLiteral);
299     case FontWeight900Mask:
300         return String("900", String::ConstructFromLiteral);
301     }
302     ASSERT_NOT_REACHED();
303     return String("normal", String::ConstructFromLiteral);
304 }
305
306 String FontFace::stretch() const
307 {
308     return ASCIILiteral("normal");
309 }
310
311 String FontFace::unicodeRange() const
312 {
313     const_cast<CSSFontFace&>(m_backing.get()).updateStyleIfNeeded();
314     if (!m_backing->ranges().size())
315         return ASCIILiteral("U+0-10FFFF");
316     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
317     for (auto& range : m_backing->ranges())
318         values->append(CSSUnicodeRangeValue::create(range.from, range.to));
319     return values->cssText();
320 }
321
322 String FontFace::variant() const
323 {
324     const_cast<CSSFontFace&>(m_backing.get()).updateStyleIfNeeded();
325     return computeFontVariant(m_backing->variantSettings())->cssText();
326 }
327
328 String FontFace::featureSettings() const
329 {
330     const_cast<CSSFontFace&>(m_backing.get()).updateStyleIfNeeded();
331     if (!m_backing->featureSettings().size())
332         return ASCIILiteral("normal");
333     RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
334     for (auto& feature : m_backing->featureSettings())
335         list->append(CSSFontFeatureValue::create(FontTag(feature.tag()), feature.value()));
336     return list->cssText();
337 }
338
339 auto FontFace::status() const -> LoadStatus
340 {
341     switch (m_backing->status()) {
342     case CSSFontFace::Status::Pending:
343         return LoadStatus::Unloaded;
344     case CSSFontFace::Status::Loading:
345         return LoadStatus::Loading;
346     case CSSFontFace::Status::TimedOut:
347         return LoadStatus::Error;
348     case CSSFontFace::Status::Success:
349         return LoadStatus::Loaded;
350     case CSSFontFace::Status::Failure:
351         return LoadStatus::Error;
352     }
353     ASSERT_NOT_REACHED();
354     return LoadStatus::Error;
355 }
356
357 void FontFace::adopt(CSSFontFace& newFace)
358 {
359     m_backing->removeClient(*this);
360     m_backing = newFace;
361     m_backing->addClient(*this);
362     newFace.setWrapper(*this);
363 }
364
365 void FontFace::fontStateChanged(CSSFontFace& face, CSSFontFace::Status, CSSFontFace::Status newState)
366 {
367     ASSERT_UNUSED(face, &face == m_backing.ptr());
368     switch (newState) {
369     case CSSFontFace::Status::Loading:
370         // We still need to resolve promises when loading completes, even if all references to use have fallen out of scope.
371         ref();
372         break;
373     case CSSFontFace::Status::TimedOut:
374         break;
375     case CSSFontFace::Status::Success:
376         if (m_promise)
377             std::exchange(m_promise, std::nullopt)->resolve(*this);
378         deref();
379         return;
380     case CSSFontFace::Status::Failure:
381         if (m_promise)
382             std::exchange(m_promise, std::nullopt)->reject(NETWORK_ERR);
383         deref();
384         return;
385     case CSSFontFace::Status::Pending:
386         ASSERT_NOT_REACHED();
387         return;
388     }
389 }
390
391 void FontFace::registerLoaded(Promise&& promise)
392 {
393     ASSERT(!m_promise);
394     switch (m_backing->status()) {
395     case CSSFontFace::Status::Loading:
396     case CSSFontFace::Status::Pending:
397         m_promise = WTFMove(promise);
398         return;
399     case CSSFontFace::Status::Success:
400         promise.resolve(*this);
401         return;
402     case CSSFontFace::Status::TimedOut:
403     case CSSFontFace::Status::Failure:
404         promise.reject(NETWORK_ERR);
405         return;
406     }
407 }
408
409 void FontFace::load()
410 {
411     m_backing->load();
412 }
413
414 }