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