1 /*
2  * Copyright (C) 2013 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "third_party/blink/renderer/core/css/font_face.h"
32 
33 #include "third_party/blink/public/platform/task_type.h"
34 #include "third_party/blink/renderer/bindings/core/v8/string_or_array_buffer_or_array_buffer_view.h"
35 #include "third_party/blink/renderer/bindings/core/v8/v8_font_face_descriptors.h"
36 #include "third_party/blink/renderer/core/css/binary_data_font_face_source.h"
37 #include "third_party/blink/renderer/core/css/css_font_face.h"
38 #include "third_party/blink/renderer/core/css/css_font_face_src_value.h"
39 #include "third_party/blink/renderer/core/css/css_font_family_value.h"
40 #include "third_party/blink/renderer/core/css/css_font_selector.h"
41 #include "third_party/blink/renderer/core/css/css_font_style_range_value.h"
42 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
43 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
44 #include "third_party/blink/renderer/core/css/css_unicode_range_value.h"
45 #include "third_party/blink/renderer/core/css/css_value_list.h"
46 #include "third_party/blink/renderer/core/css/local_font_face_source.h"
47 #include "third_party/blink/renderer/core/css/offscreen_font_selector.h"
48 #include "third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.h"
49 #include "third_party/blink/renderer/core/css/parser/css_parser.h"
50 #include "third_party/blink/renderer/core/css/remote_font_face_source.h"
51 #include "third_party/blink/renderer/core/css/style_engine.h"
52 #include "third_party/blink/renderer/core/css/style_rule.h"
53 #include "third_party/blink/renderer/core/css_value_keywords.h"
54 #include "third_party/blink/renderer/core/dom/document.h"
55 #include "third_party/blink/renderer/core/dom/dom_exception.h"
56 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
57 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
58 #include "third_party/blink/renderer/core/frame/local_frame.h"
59 #include "third_party/blink/renderer/core/frame/settings.h"
60 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
61 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
62 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
63 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
64 #include "third_party/blink/renderer/platform/bindings/script_state.h"
65 #include "third_party/blink/renderer/platform/font_family_names.h"
66 #include "third_party/blink/renderer/platform/heap/heap.h"
67 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
68 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
69 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
70 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
71 
72 namespace blink {
73 
74 namespace {
75 
ParseCSSValue(const ExecutionContext * context,const String & value,AtRuleDescriptorID descriptor_id)76 const CSSValue* ParseCSSValue(const ExecutionContext* context,
77                               const String& value,
78                               AtRuleDescriptorID descriptor_id) {
79   CSSParserContext* parser_context =
80       context->IsDocument() ? MakeGarbageCollected<CSSParserContext>(
81                                   *To<LocalDOMWindow>(context)->document())
82                             : MakeGarbageCollected<CSSParserContext>(*context);
83   return AtRuleDescriptorParser::ParseFontFaceDescriptor(descriptor_id, value,
84                                                          *parser_context);
85 }
86 
CreateCSSFontFace(FontFace * font_face,const CSSValue * unicode_range)87 CSSFontFace* CreateCSSFontFace(FontFace* font_face,
88                                const CSSValue* unicode_range) {
89   Vector<UnicodeRange> ranges;
90   if (const auto* range_list = To<CSSValueList>(unicode_range)) {
91     unsigned num_ranges = range_list->length();
92     for (unsigned i = 0; i < num_ranges; i++) {
93       const auto& range =
94           To<cssvalue::CSSUnicodeRangeValue>(range_list->Item(i));
95       ranges.push_back(UnicodeRange(range.From(), range.To()));
96     }
97   }
98 
99   return MakeGarbageCollected<CSSFontFace>(font_face, ranges);
100 }
101 
102 }  // namespace
103 
Create(ExecutionContext * context,const AtomicString & family,StringOrArrayBufferOrArrayBufferView & source,const FontFaceDescriptors * descriptors)104 FontFace* FontFace::Create(ExecutionContext* context,
105                            const AtomicString& family,
106                            StringOrArrayBufferOrArrayBufferView& source,
107                            const FontFaceDescriptors* descriptors) {
108   if (source.IsString())
109     return Create(context, family, source.GetAsString(), descriptors);
110   if (source.IsArrayBuffer())
111     return Create(context, family, source.GetAsArrayBuffer(), descriptors);
112   if (source.IsArrayBufferView()) {
113     return Create(context, family, source.GetAsArrayBufferView().View(),
114                   descriptors);
115   }
116   NOTREACHED();
117   return nullptr;
118 }
119 
Create(ExecutionContext * context,const AtomicString & family,const String & source,const FontFaceDescriptors * descriptors)120 FontFace* FontFace::Create(ExecutionContext* context,
121                            const AtomicString& family,
122                            const String& source,
123                            const FontFaceDescriptors* descriptors) {
124   FontFace* font_face =
125       MakeGarbageCollected<FontFace>(context, family, descriptors);
126 
127   const CSSValue* src = ParseCSSValue(context, source, AtRuleDescriptorID::Src);
128   if (!src || !src->IsValueList()) {
129     font_face->SetError(MakeGarbageCollected<DOMException>(
130         DOMExceptionCode::kSyntaxError,
131         "The source provided ('" + source +
132             "') could not be parsed as a value list."));
133   }
134 
135   font_face->InitCSSFontFace(context, *src);
136   return font_face;
137 }
138 
Create(ExecutionContext * context,const AtomicString & family,DOMArrayBuffer * source,const FontFaceDescriptors * descriptors)139 FontFace* FontFace::Create(ExecutionContext* context,
140                            const AtomicString& family,
141                            DOMArrayBuffer* source,
142                            const FontFaceDescriptors* descriptors) {
143   FontFace* font_face =
144       MakeGarbageCollected<FontFace>(context, family, descriptors);
145   font_face->InitCSSFontFace(static_cast<const unsigned char*>(source->Data()),
146                              source->ByteLengthAsSizeT());
147   return font_face;
148 }
149 
Create(ExecutionContext * context,const AtomicString & family,DOMArrayBufferView * source,const FontFaceDescriptors * descriptors)150 FontFace* FontFace::Create(ExecutionContext* context,
151                            const AtomicString& family,
152                            DOMArrayBufferView* source,
153                            const FontFaceDescriptors* descriptors) {
154   FontFace* font_face =
155       MakeGarbageCollected<FontFace>(context, family, descriptors);
156   font_face->InitCSSFontFace(
157       static_cast<const unsigned char*>(source->BaseAddress()),
158       source->byteLengthAsSizeT());
159   return font_face;
160 }
161 
Create(Document * document,const StyleRuleFontFace * font_face_rule)162 FontFace* FontFace::Create(Document* document,
163                            const StyleRuleFontFace* font_face_rule) {
164   const CSSPropertyValueSet& properties = font_face_rule->Properties();
165 
166   // Obtain the font-family property and the src property. Both must be defined.
167   const CSSValue* family =
168       properties.GetPropertyCSSValue(AtRuleDescriptorID::FontFamily);
169   if (!family || (!family->IsFontFamilyValue() && !family->IsIdentifierValue()))
170     return nullptr;
171   const CSSValue* src = properties.GetPropertyCSSValue(AtRuleDescriptorID::Src);
172   if (!src || !src->IsValueList())
173     return nullptr;
174 
175   FontFace* font_face =
176       MakeGarbageCollected<FontFace>(document->GetExecutionContext());
177 
178   if (font_face->SetFamilyValue(*family) &&
179       font_face->SetPropertyFromStyle(properties,
180                                       AtRuleDescriptorID::FontStyle) &&
181       font_face->SetPropertyFromStyle(properties,
182                                       AtRuleDescriptorID::FontWeight) &&
183       font_face->SetPropertyFromStyle(properties,
184                                       AtRuleDescriptorID::FontStretch) &&
185       font_face->SetPropertyFromStyle(properties,
186                                       AtRuleDescriptorID::UnicodeRange) &&
187       font_face->SetPropertyFromStyle(properties,
188                                       AtRuleDescriptorID::FontVariant) &&
189       font_face->SetPropertyFromStyle(
190           properties, AtRuleDescriptorID::FontFeatureSettings) &&
191       font_face->SetPropertyFromStyle(properties,
192                                       AtRuleDescriptorID::FontDisplay) &&
193       font_face->GetFontSelectionCapabilities().IsValid() &&
194       !font_face->family().IsEmpty()) {
195     font_face->InitCSSFontFace(document->GetExecutionContext(), *src);
196     return font_face;
197   }
198   return nullptr;
199 }
200 
FontFace(ExecutionContext * context)201 FontFace::FontFace(ExecutionContext* context)
202     : ExecutionContextClient(context), status_(kUnloaded) {}
203 
FontFace(ExecutionContext * context,const AtomicString & family,const FontFaceDescriptors * descriptors)204 FontFace::FontFace(ExecutionContext* context,
205                    const AtomicString& family,
206                    const FontFaceDescriptors* descriptors)
207     : ExecutionContextClient(context), family_(family), status_(kUnloaded) {
208   SetPropertyFromString(context, descriptors->style(),
209                         AtRuleDescriptorID::FontStyle);
210   SetPropertyFromString(context, descriptors->weight(),
211                         AtRuleDescriptorID::FontWeight);
212   SetPropertyFromString(context, descriptors->stretch(),
213                         AtRuleDescriptorID::FontStretch);
214   SetPropertyFromString(context, descriptors->unicodeRange(),
215                         AtRuleDescriptorID::UnicodeRange);
216   SetPropertyFromString(context, descriptors->variant(),
217                         AtRuleDescriptorID::FontVariant);
218   SetPropertyFromString(context, descriptors->featureSettings(),
219                         AtRuleDescriptorID::FontFeatureSettings);
220   SetPropertyFromString(context, descriptors->display(),
221                         AtRuleDescriptorID::FontDisplay);
222 }
223 
224 FontFace::~FontFace() = default;
225 
style() const226 String FontFace::style() const {
227   return style_ ? style_->CssText() : "normal";
228 }
229 
weight() const230 String FontFace::weight() const {
231   return weight_ ? weight_->CssText() : "normal";
232 }
233 
stretch() const234 String FontFace::stretch() const {
235   return stretch_ ? stretch_->CssText() : "normal";
236 }
237 
unicodeRange() const238 String FontFace::unicodeRange() const {
239   return unicode_range_ ? unicode_range_->CssText() : "U+0-10FFFF";
240 }
241 
variant() const242 String FontFace::variant() const {
243   return variant_ ? variant_->CssText() : "normal";
244 }
245 
featureSettings() const246 String FontFace::featureSettings() const {
247   return feature_settings_ ? feature_settings_->CssText() : "normal";
248 }
249 
display() const250 String FontFace::display() const {
251   return display_ ? display_->CssText() : "auto";
252 }
253 
setStyle(ExecutionContext * context,const String & s,ExceptionState & exception_state)254 void FontFace::setStyle(ExecutionContext* context,
255                         const String& s,
256                         ExceptionState& exception_state) {
257   SetPropertyFromString(context, s, AtRuleDescriptorID::FontStyle,
258                         &exception_state);
259 }
260 
setWeight(ExecutionContext * context,const String & s,ExceptionState & exception_state)261 void FontFace::setWeight(ExecutionContext* context,
262                          const String& s,
263                          ExceptionState& exception_state) {
264   SetPropertyFromString(context, s, AtRuleDescriptorID::FontWeight,
265                         &exception_state);
266 }
267 
setStretch(ExecutionContext * context,const String & s,ExceptionState & exception_state)268 void FontFace::setStretch(ExecutionContext* context,
269                           const String& s,
270                           ExceptionState& exception_state) {
271   SetPropertyFromString(context, s, AtRuleDescriptorID::FontStretch,
272                         &exception_state);
273 }
274 
setUnicodeRange(ExecutionContext * context,const String & s,ExceptionState & exception_state)275 void FontFace::setUnicodeRange(ExecutionContext* context,
276                                const String& s,
277                                ExceptionState& exception_state) {
278   SetPropertyFromString(context, s, AtRuleDescriptorID::UnicodeRange,
279                         &exception_state);
280 }
281 
setVariant(ExecutionContext * context,const String & s,ExceptionState & exception_state)282 void FontFace::setVariant(ExecutionContext* context,
283                           const String& s,
284                           ExceptionState& exception_state) {
285   SetPropertyFromString(context, s, AtRuleDescriptorID::FontVariant,
286                         &exception_state);
287 }
288 
setFeatureSettings(ExecutionContext * context,const String & s,ExceptionState & exception_state)289 void FontFace::setFeatureSettings(ExecutionContext* context,
290                                   const String& s,
291                                   ExceptionState& exception_state) {
292   SetPropertyFromString(context, s, AtRuleDescriptorID::FontFeatureSettings,
293                         &exception_state);
294 }
295 
setDisplay(ExecutionContext * context,const String & s,ExceptionState & exception_state)296 void FontFace::setDisplay(ExecutionContext* context,
297                           const String& s,
298                           ExceptionState& exception_state) {
299   SetPropertyFromString(context, s, AtRuleDescriptorID::FontDisplay,
300                         &exception_state);
301 }
302 
SetPropertyFromString(const ExecutionContext * context,const String & s,AtRuleDescriptorID descriptor_id,ExceptionState * exception_state)303 void FontFace::SetPropertyFromString(const ExecutionContext* context,
304                                      const String& s,
305                                      AtRuleDescriptorID descriptor_id,
306                                      ExceptionState* exception_state) {
307   const CSSValue* value = ParseCSSValue(context, s, descriptor_id);
308   if (value && SetPropertyValue(value, descriptor_id))
309     return;
310 
311   String message = "Failed to set '" + s + "' as a property value.";
312   if (exception_state) {
313     exception_state->ThrowDOMException(DOMExceptionCode::kSyntaxError, message);
314   } else {
315     SetError(MakeGarbageCollected<DOMException>(DOMExceptionCode::kSyntaxError,
316                                                 message));
317   }
318 }
319 
SetPropertyFromStyle(const CSSPropertyValueSet & properties,AtRuleDescriptorID property_id)320 bool FontFace::SetPropertyFromStyle(const CSSPropertyValueSet& properties,
321                                     AtRuleDescriptorID property_id) {
322   return SetPropertyValue(properties.GetPropertyCSSValue(property_id),
323                           property_id);
324 }
325 
SetPropertyValue(const CSSValue * value,AtRuleDescriptorID descriptor_id)326 bool FontFace::SetPropertyValue(const CSSValue* value,
327                                 AtRuleDescriptorID descriptor_id) {
328   switch (descriptor_id) {
329     case AtRuleDescriptorID::FontStyle:
330       style_ = value;
331       break;
332     case AtRuleDescriptorID::FontWeight:
333       weight_ = value;
334       break;
335     case AtRuleDescriptorID::FontStretch:
336       stretch_ = value;
337       break;
338     case AtRuleDescriptorID::UnicodeRange:
339       if (value && !value->IsValueList())
340         return false;
341       unicode_range_ = value;
342       break;
343     case AtRuleDescriptorID::FontVariant:
344       variant_ = value;
345       break;
346     case AtRuleDescriptorID::FontFeatureSettings:
347       feature_settings_ = value;
348       break;
349     case AtRuleDescriptorID::FontDisplay:
350       display_ = value;
351       if (css_font_face_)
352         css_font_face_->SetDisplay(CSSValueToFontDisplay(display_.Get()));
353       break;
354     default:
355       NOTREACHED();
356       return false;
357   }
358   return true;
359 }
360 
SetFamilyValue(const CSSValue & value)361 bool FontFace::SetFamilyValue(const CSSValue& value) {
362   AtomicString family;
363   if (auto* family_value = DynamicTo<CSSFontFamilyValue>(value)) {
364     family = AtomicString(family_value->Value());
365   } else if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
366     // We need to use the raw text for all the generic family types, since
367     // @font-face is a way of actually defining what font to use for those
368     // types.
369     switch (identifier_value->GetValueID()) {
370       case CSSValueID::kSerif:
371         family = font_family_names::kWebkitSerif;
372         break;
373       case CSSValueID::kSansSerif:
374         family = font_family_names::kWebkitSansSerif;
375         break;
376       case CSSValueID::kCursive:
377         family = font_family_names::kWebkitCursive;
378         break;
379       case CSSValueID::kFantasy:
380         family = font_family_names::kWebkitFantasy;
381         break;
382       case CSSValueID::kMonospace:
383         family = font_family_names::kWebkitMonospace;
384         break;
385       default:
386         return false;
387     }
388   }
389   family_ = family;
390   return true;
391 }
392 
status() const393 String FontFace::status() const {
394   switch (status_) {
395     case kUnloaded:
396       return "unloaded";
397     case kLoading:
398       return "loading";
399     case kLoaded:
400       return "loaded";
401     case kError:
402       return "error";
403     default:
404       NOTREACHED();
405   }
406   return g_empty_string;
407 }
408 
SetLoadStatus(LoadStatusType status)409 void FontFace::SetLoadStatus(LoadStatusType status) {
410   status_ = status;
411   DCHECK(status_ != kError || error_);
412 
413   if (!GetExecutionContext())
414     return;
415 
416   if (status_ == kLoaded || status_ == kError) {
417     if (loaded_property_) {
418       if (status_ == kLoaded) {
419         GetExecutionContext()
420             ->GetTaskRunner(TaskType::kDOMManipulation)
421             ->PostTask(FROM_HERE,
422                        WTF::Bind(&LoadedProperty::Resolve<FontFace*>,
423                                  WrapPersistent(loaded_property_.Get()),
424                                  WrapPersistent(this)));
425       } else {
426         GetExecutionContext()
427             ->GetTaskRunner(TaskType::kDOMManipulation)
428             ->PostTask(FROM_HERE,
429                        WTF::Bind(&LoadedProperty::Reject<DOMException*>,
430                                  WrapPersistent(loaded_property_.Get()),
431                                  WrapPersistent(error_.Get())));
432       }
433     }
434 
435     GetExecutionContext()
436         ->GetTaskRunner(TaskType::kDOMManipulation)
437         ->PostTask(FROM_HERE,
438                    WTF::Bind(&FontFace::RunCallbacks, WrapPersistent(this)));
439   }
440 }
441 
RunCallbacks()442 void FontFace::RunCallbacks() {
443   HeapVector<Member<LoadFontCallback>> callbacks;
444   callbacks_.swap(callbacks);
445   for (wtf_size_t i = 0; i < callbacks.size(); ++i) {
446     if (status_ == kLoaded)
447       callbacks[i]->NotifyLoaded(this);
448     else
449       callbacks[i]->NotifyError(this);
450   }
451 }
452 
SetError(DOMException * error)453 void FontFace::SetError(DOMException* error) {
454   if (!error_) {
455     error_ = error ? error
456                    : MakeGarbageCollected<DOMException>(
457                          DOMExceptionCode::kNetworkError);
458   }
459   SetLoadStatus(kError);
460 }
461 
FontStatusPromise(ScriptState * script_state)462 ScriptPromise FontFace::FontStatusPromise(ScriptState* script_state) {
463   if (!loaded_property_) {
464     loaded_property_ = MakeGarbageCollected<LoadedProperty>(
465         ExecutionContext::From(script_state));
466     if (status_ == kLoaded)
467       loaded_property_->Resolve(this);
468     else if (status_ == kError)
469       loaded_property_->Reject(error_.Get());
470   }
471   return loaded_property_->Promise(script_state->World());
472 }
473 
load(ScriptState * script_state)474 ScriptPromise FontFace::load(ScriptState* script_state) {
475   if (status_ == kUnloaded)
476     css_font_face_->Load();
477   DidBeginImperativeLoad();
478   return FontStatusPromise(script_state);
479 }
480 
LoadWithCallback(LoadFontCallback * callback)481 void FontFace::LoadWithCallback(LoadFontCallback* callback) {
482   if (status_ == kUnloaded)
483     css_font_face_->Load();
484   AddCallback(callback);
485 }
486 
AddCallback(LoadFontCallback * callback)487 void FontFace::AddCallback(LoadFontCallback* callback) {
488   if (status_ == kLoaded)
489     callback->NotifyLoaded(this);
490   else if (status_ == kError)
491     callback->NotifyError(this);
492   else
493     callbacks_.push_back(callback);
494 }
495 
GetFontSelectionCapabilities() const496 FontSelectionCapabilities FontFace::GetFontSelectionCapabilities() const {
497   // FontSelectionCapabilities represents a range of available width, slope and
498   // weight values. The first value of each pair is the minimum value, the
499   // second is the maximum value.
500   FontSelectionCapabilities normal_capabilities(
501       {NormalWidthValue(), NormalWidthValue()},
502       {NormalSlopeValue(), NormalSlopeValue()},
503       {NormalWeightValue(), NormalWeightValue()});
504   FontSelectionCapabilities capabilities(normal_capabilities);
505 
506   if (stretch_) {
507     if (auto* stretch_identifier_value =
508             DynamicTo<CSSIdentifierValue>(stretch_.Get())) {
509       switch (stretch_identifier_value->GetValueID()) {
510         case CSSValueID::kUltraCondensed:
511           capabilities.width = {UltraCondensedWidthValue(),
512                                 UltraCondensedWidthValue()};
513           break;
514         case CSSValueID::kExtraCondensed:
515           capabilities.width = {ExtraCondensedWidthValue(),
516                                 ExtraCondensedWidthValue()};
517           break;
518         case CSSValueID::kCondensed:
519           capabilities.width = {CondensedWidthValue(), CondensedWidthValue()};
520           break;
521         case CSSValueID::kSemiCondensed:
522           capabilities.width = {SemiCondensedWidthValue(),
523                                 SemiCondensedWidthValue()};
524           break;
525         case CSSValueID::kSemiExpanded:
526           capabilities.width = {SemiExpandedWidthValue(),
527                                 SemiExpandedWidthValue()};
528           break;
529         case CSSValueID::kExpanded:
530           capabilities.width = {ExpandedWidthValue(), ExpandedWidthValue()};
531           break;
532         case CSSValueID::kExtraExpanded:
533           capabilities.width = {ExtraExpandedWidthValue(),
534                                 ExtraExpandedWidthValue()};
535           break;
536         case CSSValueID::kUltraExpanded:
537           capabilities.width = {UltraExpandedWidthValue(),
538                                 UltraExpandedWidthValue()};
539           break;
540         default:
541           break;
542       }
543     } else if (const auto* stretch_list =
544                    DynamicTo<CSSValueList>(stretch_.Get())) {
545       // Transition FontFace interpretation of parsed values from
546       // CSSIdentifierValue to CSSValueList or CSSPrimitiveValue.
547       // TODO(drott) crbug.com/739139: Update the parser to only produce
548       // CSSPrimitiveValue or CSSValueList.
549       if (stretch_list->length() != 2)
550         return normal_capabilities;
551       const auto* stretch_from =
552           DynamicTo<CSSPrimitiveValue>(&stretch_list->Item(0));
553       const auto* stretch_to =
554           DynamicTo<CSSPrimitiveValue>(&stretch_list->Item(1));
555       if (!stretch_from || !stretch_to)
556         return normal_capabilities;
557       if (!stretch_from->IsPercentage() || !stretch_to->IsPercentage())
558         return normal_capabilities;
559       // https://drafts.csswg.org/css-fonts/#font-prop-desc
560       // "User agents must swap the computed value of the startpoint and
561       // endpoint of the range in order to forbid decreasing ranges."
562       if (stretch_from->GetFloatValue() < stretch_to->GetFloatValue()) {
563         capabilities.width = {FontSelectionValue(stretch_from->GetFloatValue()),
564                               FontSelectionValue(stretch_to->GetFloatValue())};
565       } else {
566         capabilities.width = {
567             FontSelectionValue(stretch_to->GetFloatValue()),
568             FontSelectionValue(stretch_from->GetFloatValue())};
569       }
570     } else if (auto* stretch_primitive_value =
571                    DynamicTo<CSSPrimitiveValue>(stretch_.Get())) {
572       float stretch_value = stretch_primitive_value->GetFloatValue();
573       capabilities.width = {FontSelectionValue(stretch_value),
574                             FontSelectionValue(stretch_value)};
575     } else {
576       NOTREACHED();
577       return normal_capabilities;
578     }
579   }
580 
581   if (style_) {
582     if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(style_.Get())) {
583       switch (identifier_value->GetValueID()) {
584         case CSSValueID::kNormal:
585           capabilities.slope = {NormalSlopeValue(), NormalSlopeValue()};
586           break;
587         case CSSValueID::kOblique:
588           capabilities.slope = {ItalicSlopeValue(), ItalicSlopeValue()};
589           break;
590         case CSSValueID::kItalic:
591           capabilities.slope = {ItalicSlopeValue(), ItalicSlopeValue()};
592           break;
593         default:
594           break;
595       }
596     } else if (const auto* range_value =
597                    DynamicTo<cssvalue::CSSFontStyleRangeValue>(style_.Get())) {
598       if (range_value->GetFontStyleValue()->IsIdentifierValue()) {
599         CSSValueID font_style_id =
600             range_value->GetFontStyleValue()->GetValueID();
601         if (!range_value->GetObliqueValues()) {
602           if (font_style_id == CSSValueID::kNormal)
603             capabilities.slope = {NormalSlopeValue(), NormalSlopeValue()};
604           DCHECK(font_style_id == CSSValueID::kItalic ||
605                  font_style_id == CSSValueID::kOblique);
606           capabilities.slope = {ItalicSlopeValue(), ItalicSlopeValue()};
607         } else {
608           DCHECK(font_style_id == CSSValueID::kOblique);
609           size_t oblique_values_size =
610               range_value->GetObliqueValues()->length();
611           if (oblique_values_size == 1) {
612             const auto& range_start =
613                 To<CSSPrimitiveValue>(range_value->GetObliqueValues()->Item(0));
614             FontSelectionValue oblique_range(range_start.GetFloatValue());
615             capabilities.slope = {oblique_range, oblique_range};
616           } else {
617             DCHECK_EQ(oblique_values_size, 2u);
618             const auto& range_start =
619                 To<CSSPrimitiveValue>(range_value->GetObliqueValues()->Item(0));
620             const auto& range_end =
621                 To<CSSPrimitiveValue>(range_value->GetObliqueValues()->Item(1));
622             // https://drafts.csswg.org/css-fonts/#font-prop-desc
623             // "User agents must swap the computed value of the startpoint and
624             // endpoint of the range in order to forbid decreasing ranges."
625             if (range_start.GetFloatValue() < range_end.GetFloatValue()) {
626               capabilities.slope = {
627                   FontSelectionValue(range_start.GetFloatValue()),
628                   FontSelectionValue(range_end.GetFloatValue())};
629             } else {
630               capabilities.slope = {
631                   FontSelectionValue(range_end.GetFloatValue()),
632                   FontSelectionValue(range_start.GetFloatValue())};
633             }
634           }
635         }
636       }
637     } else {
638       NOTREACHED();
639       return normal_capabilities;
640     }
641   }
642 
643   if (weight_) {
644     if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(weight_.Get())) {
645       switch (identifier_value->GetValueID()) {
646         // Although 'lighter' and 'bolder' are valid keywords for
647         // font-weights, they are invalid inside font-face rules so they are
648         // ignored. Reference:
649         // http://www.w3.org/TR/css3-fonts/#descdef-font-weight.
650         case CSSValueID::kLighter:
651         case CSSValueID::kBolder:
652           break;
653         case CSSValueID::kNormal:
654           capabilities.weight = {NormalWeightValue(), NormalWeightValue()};
655           break;
656         case CSSValueID::kBold:
657           capabilities.weight = {BoldWeightValue(), BoldWeightValue()};
658           break;
659         default:
660           NOTREACHED();
661           break;
662       }
663     } else if (const auto* weight_list =
664                    DynamicTo<CSSValueList>(weight_.Get())) {
665       if (weight_list->length() != 2)
666         return normal_capabilities;
667       const auto* weight_from =
668           DynamicTo<CSSPrimitiveValue>(&weight_list->Item(0));
669       const auto* weight_to =
670           DynamicTo<CSSPrimitiveValue>(&weight_list->Item(1));
671       if (!weight_from || !weight_to)
672         return normal_capabilities;
673       if (!weight_from->IsNumber() || !weight_to->IsNumber() ||
674           weight_from->GetFloatValue() < 1 || weight_to->GetFloatValue() > 1000)
675         return normal_capabilities;
676       // https://drafts.csswg.org/css-fonts/#font-prop-desc
677       // "User agents must swap the computed value of the startpoint and
678       // endpoint of the range in order to forbid decreasing ranges."
679       if (weight_from->GetFloatValue() < weight_to->GetFloatValue()) {
680         capabilities.weight = {FontSelectionValue(weight_from->GetFloatValue()),
681                                FontSelectionValue(weight_to->GetFloatValue())};
682       } else {
683         capabilities.weight = {
684             FontSelectionValue(weight_to->GetFloatValue()),
685             FontSelectionValue(weight_from->GetFloatValue())};
686       }
687     } else if (auto* weight_primitive_value =
688                    DynamicTo<CSSPrimitiveValue>(weight_.Get())) {
689       float weight_value = weight_primitive_value->GetFloatValue();
690       if (weight_value < 1 || weight_value > 1000)
691         return normal_capabilities;
692       capabilities.weight = {FontSelectionValue(weight_value),
693                              FontSelectionValue(weight_value)};
694     } else {
695       NOTREACHED();
696       return normal_capabilities;
697     }
698   }
699 
700   return capabilities;
701 }
702 
ApproximateBlankCharacterCount() const703 size_t FontFace::ApproximateBlankCharacterCount() const {
704   if (status_ == kLoading)
705     return css_font_face_->ApproximateBlankCharacterCount();
706   return 0;
707 }
708 
ContextAllowsDownload(ExecutionContext * context)709 bool ContextAllowsDownload(ExecutionContext* context) {
710   if (!context) {
711     return false;
712   }
713   if (const auto* window = DynamicTo<LocalDOMWindow>(context)) {
714     const Settings* settings =
715         window->GetFrame() ? window->GetFrame()->GetSettings() : nullptr;
716     return settings && settings->GetDownloadableBinaryFontsEnabled();
717   }
718   // TODO(fserb): ideally, we would like to have the settings value available
719   // on workers. Right now, we don't support that.
720   return true;
721 }
722 
InitCSSFontFace(ExecutionContext * context,const CSSValue & src)723 void FontFace::InitCSSFontFace(ExecutionContext* context, const CSSValue& src) {
724   css_font_face_ = CreateCSSFontFace(this, unicode_range_.Get());
725   if (error_)
726     return;
727 
728   // Each item in the src property's list is a single CSSFontFaceSource. Put
729   // them all into a CSSFontFace.
730   const auto& src_list = To<CSSValueList>(src);
731   int src_length = src_list.length();
732 
733   for (int i = 0; i < src_length; i++) {
734     // An item in the list either specifies a string (local font name) or a URL
735     // (remote font to download).
736     const CSSFontFaceSrcValue& item = To<CSSFontFaceSrcValue>(src_list.Item(i));
737 
738     FontSelector* font_selector = nullptr;
739     if (auto* window = DynamicTo<LocalDOMWindow>(context)) {
740       font_selector = window->document()->GetStyleEngine().GetFontSelector();
741     } else if (auto* scope = DynamicTo<WorkerGlobalScope>(context)) {
742       font_selector = scope->GetFontSelector();
743     } else {
744       NOTREACHED();
745     }
746     if (!item.IsLocal()) {
747       if (ContextAllowsDownload(context) && item.IsSupportedFormat()) {
748         RemoteFontFaceSource* source =
749             MakeGarbageCollected<RemoteFontFaceSource>(
750                 css_font_face_, font_selector,
751                 CSSValueToFontDisplay(display_.Get()));
752         item.Fetch(context, source);
753         css_font_face_->AddSource(source);
754       }
755     } else {
756       css_font_face_->AddSource(MakeGarbageCollected<LocalFontFaceSource>(
757           css_font_face_, font_selector, item.GetResource()));
758     }
759   }
760 
761   if (display_) {
762     DEFINE_THREAD_SAFE_STATIC_LOCAL(
763         EnumerationHistogram, font_display_histogram,
764         ("WebFont.FontDisplayValue", kFontDisplayEnumMax));
765     font_display_histogram.Count(CSSValueToFontDisplay(display_.Get()));
766   }
767 }
768 
InitCSSFontFace(const unsigned char * data,size_t size)769 void FontFace::InitCSSFontFace(const unsigned char* data, size_t size) {
770   css_font_face_ = CreateCSSFontFace(this, unicode_range_.Get());
771   if (error_)
772     return;
773 
774   scoped_refptr<SharedBuffer> buffer = SharedBuffer::Create(data, size);
775   BinaryDataFontFaceSource* source =
776       MakeGarbageCollected<BinaryDataFontFaceSource>(buffer.get(),
777                                                      ots_parse_message_);
778   if (source->IsValid()) {
779     SetLoadStatus(kLoaded);
780   } else {
781     SetError(MakeGarbageCollected<DOMException>(
782         DOMExceptionCode::kSyntaxError, "Invalid font data in ArrayBuffer."));
783   }
784   css_font_face_->AddSource(source);
785 }
786 
Trace(Visitor * visitor)787 void FontFace::Trace(Visitor* visitor) {
788   visitor->Trace(style_);
789   visitor->Trace(weight_);
790   visitor->Trace(stretch_);
791   visitor->Trace(unicode_range_);
792   visitor->Trace(variant_);
793   visitor->Trace(feature_settings_);
794   visitor->Trace(display_);
795   visitor->Trace(error_);
796   visitor->Trace(loaded_property_);
797   visitor->Trace(css_font_face_);
798   visitor->Trace(callbacks_);
799   ScriptWrappable::Trace(visitor);
800   ExecutionContextClient::Trace(visitor);
801 }
802 
HadBlankText() const803 bool FontFace::HadBlankText() const {
804   return css_font_face_->HadBlankText();
805 }
806 
HasPendingActivity() const807 bool FontFace::HasPendingActivity() const {
808   return status_ == kLoading && GetExecutionContext();
809 }
810 
GetFontDisplay() const811 FontDisplay FontFace::GetFontDisplay() const {
812   return CSSValueToFontDisplay(display_.Get());
813 }
814 
DidBeginImperativeLoad()815 void FontFace::DidBeginImperativeLoad() {
816   if (GetDocument())
817     GetDocument()->GetFontPreloadManager().ImperativeFontLoadingStarted(this);
818 }
819 
820 }  // namespace blink
821