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