mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
581 lines
24 KiB
Rust
581 lines
24 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||
|
||
use std::cell::{Cell, RefCell};
|
||
use std::rc::Rc;
|
||
|
||
use cssparser::{Parser, ParserInput};
|
||
use dom_struct::dom_struct;
|
||
use fonts::{FontContext, FontContextWebFontMethods, FontTemplate, LowercaseFontFamilyName};
|
||
use js::rust::HandleObject;
|
||
use style::error_reporting::ParseErrorReporter;
|
||
use style::font_face::SourceList;
|
||
use style::parser::ParserContext;
|
||
use style::stylesheets::{CssRuleType, FontFaceRule, Origin, UrlExtraData};
|
||
use style_traits::{ParsingMode, ToCss};
|
||
|
||
use super::bindings::cell::DomRefCell;
|
||
use super::bindings::codegen::UnionTypes::StringOrArrayBufferViewOrArrayBuffer;
|
||
use super::bindings::error::{Error, ErrorResult, Fallible};
|
||
use super::bindings::refcounted::Trusted;
|
||
use super::bindings::reflector::DomGlobal;
|
||
use super::bindings::root::MutNullableDom;
|
||
use super::types::FontFaceSet;
|
||
use crate::dom::bindings::codegen::Bindings::FontFaceBinding::{
|
||
FontFaceDescriptors, FontFaceLoadStatus, FontFaceMethods,
|
||
};
|
||
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
||
use crate::dom::bindings::codegen::UnionTypes;
|
||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
|
||
use crate::dom::bindings::root::DomRoot;
|
||
use crate::dom::bindings::str::DOMString;
|
||
use crate::dom::globalscope::GlobalScope;
|
||
use crate::dom::promise::Promise;
|
||
use crate::dom::window::Window;
|
||
use crate::script_runtime::CanGc;
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#fontface-interface>
|
||
#[dom_struct]
|
||
pub struct FontFace {
|
||
reflector: Reflector,
|
||
status: Cell<FontFaceLoadStatus>,
|
||
family_name: DomRefCell<DOMString>,
|
||
descriptors: DomRefCell<FontFaceDescriptors>,
|
||
|
||
/// A reference to the [`FontFaceSet`] that this `FontFace` is a member of, if it has been
|
||
/// added to one. `None` otherwise. The spec suggests that a `FontFace` can be a member of
|
||
/// multiple `FontFaceSet`s, but this doesn't seem to be the case in practice, as the
|
||
/// `FontFaceSet` constructor is not exposed on the global scope.
|
||
font_face_set: MutNullableDom<FontFaceSet>,
|
||
|
||
/// This holds the [`FontTemplate`] resulting from loading this `FontFace`, to be used when the
|
||
/// `FontFace` is added to the global `FontFaceSet` and thus the `[FontContext]`.
|
||
//
|
||
// TODO: This could potentially share the `FontTemplateRef` created by `FontContext`, rather
|
||
// than having its own copy of the template.
|
||
#[no_trace = "Does not contain managed objects"]
|
||
template: RefCell<Option<(LowercaseFontFamilyName, FontTemplate)>>,
|
||
|
||
#[no_trace = "Does not contain managed objects"]
|
||
/// <https://drafts.csswg.org/css-font-loading/#m-fontface-urls-slot>
|
||
urls: DomRefCell<Option<SourceList>>,
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-fontstatuspromise-slot>
|
||
#[ignore_malloc_size_of = "Rc"]
|
||
font_status_promise: Rc<Promise>,
|
||
}
|
||
|
||
/// Given the various font face descriptors, construct the equivalent `@font-face` css rule as a
|
||
/// string and parse it using `style` crate. Returns `Err(Error::Syntax)` if parsing fails.
|
||
///
|
||
/// Due to lack of support in the `style` crate, parsing the whole `@font-face` rule is much easier
|
||
/// to implement than parsing each declaration on its own.
|
||
fn parse_font_face_descriptors(
|
||
global: &GlobalScope,
|
||
family_name: &DOMString,
|
||
sources: Option<&str>,
|
||
input_descriptors: &FontFaceDescriptors,
|
||
) -> Fallible<FontFaceRule> {
|
||
let window = global.as_window(); // TODO: Support calling FontFace APIs from Worker
|
||
let quirks_mode = window.Document().quirks_mode();
|
||
let url_data = UrlExtraData(window.get_url().get_arc());
|
||
let error_reporter = FontFaceErrorReporter {
|
||
not_encountered_error: Cell::new(true),
|
||
};
|
||
let parser_context = ParserContext::new(
|
||
Origin::Author,
|
||
&url_data,
|
||
Some(CssRuleType::FontFace),
|
||
ParsingMode::DEFAULT,
|
||
quirks_mode,
|
||
/* namespaces = */ Default::default(),
|
||
Some(&error_reporter as &dyn ParseErrorReporter),
|
||
None,
|
||
);
|
||
|
||
let FontFaceDescriptors {
|
||
ascentOverride,
|
||
descentOverride,
|
||
display,
|
||
featureSettings,
|
||
lineGapOverride,
|
||
stretch,
|
||
style,
|
||
unicodeRange,
|
||
variationSettings,
|
||
weight,
|
||
} = input_descriptors;
|
||
|
||
let _ = variationSettings; // TODO: Stylo doesn't parse font-variation-settings yet.
|
||
let maybe_sources = sources.map_or_else(String::new, |sources| format!("src: {sources};"));
|
||
let font_face_rule = format!(
|
||
r"
|
||
ascent-override: {ascentOverride};
|
||
descent-override: {descentOverride};
|
||
font-display: {display};
|
||
font-family: {family_name};
|
||
font-feature-settings: {featureSettings};
|
||
font-stretch: {stretch};
|
||
font-style: {style};
|
||
font-weight: {weight};
|
||
line-gap-override: {lineGapOverride};
|
||
unicode-range: {unicodeRange};
|
||
{maybe_sources}
|
||
"
|
||
);
|
||
|
||
// TODO: Should this be the source location in the script that invoked the font face API?
|
||
let location = cssparser::SourceLocation { line: 0, column: 0 };
|
||
let mut input = ParserInput::new(&font_face_rule);
|
||
let mut parser = Parser::new(&mut input);
|
||
let mut parsed_font_face_rule =
|
||
style::font_face::parse_font_face_block(&parser_context, &mut parser, location);
|
||
|
||
if let Some(ref mut sources) = parsed_font_face_rule.sources {
|
||
let supported_sources: Vec<_> = sources
|
||
.0
|
||
.iter()
|
||
.rev()
|
||
.filter(FontContext::is_supported_web_font_source)
|
||
.cloned()
|
||
.collect();
|
||
if supported_sources.is_empty() {
|
||
error_reporter.not_encountered_error.set(false);
|
||
} else {
|
||
sources.0 = supported_sources;
|
||
}
|
||
}
|
||
|
||
if error_reporter.not_encountered_error.get() {
|
||
Ok(parsed_font_face_rule)
|
||
} else {
|
||
Err(Error::Syntax)
|
||
}
|
||
}
|
||
|
||
fn serialize_parsed_descriptors(font_face_rule: &FontFaceRule) -> FontFaceDescriptors {
|
||
FontFaceDescriptors {
|
||
ascentOverride: font_face_rule.ascent_override.to_css_string().into(),
|
||
descentOverride: font_face_rule.descent_override.to_css_string().into(),
|
||
display: font_face_rule.display.to_css_string().into(),
|
||
featureSettings: font_face_rule.feature_settings.to_css_string().into(),
|
||
lineGapOverride: font_face_rule.line_gap_override.to_css_string().into(),
|
||
stretch: font_face_rule.stretch.to_css_string().into(),
|
||
style: font_face_rule.style.to_css_string().into(),
|
||
unicodeRange: font_face_rule.unicode_range.to_css_string().into(),
|
||
variationSettings: font_face_rule.variation_settings.to_css_string().into(),
|
||
weight: font_face_rule.weight.to_css_string().into(),
|
||
}
|
||
}
|
||
|
||
struct FontFaceErrorReporter {
|
||
not_encountered_error: Cell<bool>,
|
||
}
|
||
|
||
impl ParseErrorReporter for FontFaceErrorReporter {
|
||
fn report_error(
|
||
&self,
|
||
_url: &UrlExtraData,
|
||
_location: cssparser::SourceLocation,
|
||
_error: style::error_reporting::ContextualParseError,
|
||
) {
|
||
self.not_encountered_error.set(false);
|
||
}
|
||
}
|
||
|
||
impl FontFace {
|
||
/// Construct a [`FontFace`] to be used in the case of failure in parsing the
|
||
/// font face descriptors.
|
||
fn new_failed_font_face(global: &GlobalScope, can_gc: CanGc) -> Self {
|
||
let font_status_promise = Promise::new(global, can_gc);
|
||
// If any of them fail to parse correctly, reject font face’s [[FontStatusPromise]] with a
|
||
// DOMException named "SyntaxError"
|
||
font_status_promise.reject_error(Error::Syntax, can_gc);
|
||
|
||
// set font face’s corresponding attributes to the empty string, and set font face’s status
|
||
// attribute to "error"
|
||
Self {
|
||
reflector: Reflector::new(),
|
||
font_face_set: MutNullableDom::default(),
|
||
font_status_promise,
|
||
family_name: DomRefCell::default(),
|
||
urls: DomRefCell::default(),
|
||
descriptors: DomRefCell::new(FontFaceDescriptors {
|
||
ascentOverride: DOMString::new(),
|
||
descentOverride: DOMString::new(),
|
||
display: DOMString::new(),
|
||
featureSettings: DOMString::new(),
|
||
lineGapOverride: DOMString::new(),
|
||
stretch: DOMString::new(),
|
||
style: DOMString::new(),
|
||
unicodeRange: DOMString::new(),
|
||
variationSettings: DOMString::new(),
|
||
weight: DOMString::new(),
|
||
}),
|
||
status: Cell::new(FontFaceLoadStatus::Error),
|
||
template: RefCell::default(),
|
||
}
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#font-face-constructor>
|
||
fn new_inherited(
|
||
global: &GlobalScope,
|
||
family_name: DOMString,
|
||
source: StringOrArrayBufferViewOrArrayBuffer,
|
||
descriptors: &FontFaceDescriptors,
|
||
can_gc: CanGc,
|
||
) -> Self {
|
||
// TODO: Add support for ArrayBuffer and ArrayBufferView sources.
|
||
let StringOrArrayBufferViewOrArrayBuffer::String(ref source_string) = source else {
|
||
return Self::new_failed_font_face(global, can_gc);
|
||
};
|
||
|
||
// Step 1. Parse the family argument, and the members of the descriptors argument,
|
||
// according to the grammars of the corresponding descriptors of the CSS @font-face rule If
|
||
// the source argument is a CSSOMString, parse it according to the grammar of the CSS src
|
||
// descriptor of the @font-face rule.
|
||
let parse_result =
|
||
parse_font_face_descriptors(global, &family_name, Some(source_string), descriptors);
|
||
|
||
let Ok(ref parsed_font_face_rule) = parse_result else {
|
||
// If any of them fail to parse correctly, reject font face’s
|
||
// [[FontStatusPromise]] with a DOMException named "SyntaxError", set font face’s
|
||
// corresponding attributes to the empty string, and set font face’s status attribute
|
||
// to "error".
|
||
return Self::new_failed_font_face(global, can_gc);
|
||
};
|
||
|
||
// Set its internal [[FontStatusPromise]] slot to a fresh pending Promise object.
|
||
let font_status_promise = Promise::new(global, can_gc);
|
||
|
||
let sources = parsed_font_face_rule
|
||
.sources
|
||
.clone()
|
||
.expect("Sources should be non-None after validation");
|
||
|
||
// Let font face be a fresh FontFace object.
|
||
Self {
|
||
reflector: Reflector::new(),
|
||
|
||
// Set font face’s status attribute to "unloaded".
|
||
status: Cell::new(FontFaceLoadStatus::Unloaded),
|
||
|
||
// Set font face’s corresponding attributes to the serialization of the parsed values.
|
||
descriptors: DomRefCell::new(serialize_parsed_descriptors(parsed_font_face_rule)),
|
||
|
||
font_face_set: MutNullableDom::default(),
|
||
family_name: DomRefCell::new(family_name.clone()),
|
||
urls: DomRefCell::new(Some(sources)),
|
||
template: RefCell::default(),
|
||
font_status_promise,
|
||
}
|
||
}
|
||
|
||
pub(crate) fn new(
|
||
global: &GlobalScope,
|
||
proto: Option<HandleObject>,
|
||
font_family: DOMString,
|
||
source: StringOrArrayBufferViewOrArrayBuffer,
|
||
descriptors: &FontFaceDescriptors,
|
||
can_gc: CanGc,
|
||
) -> DomRoot<Self> {
|
||
reflect_dom_object_with_proto(
|
||
Box::new(Self::new_inherited(
|
||
global,
|
||
font_family,
|
||
source,
|
||
descriptors,
|
||
can_gc,
|
||
)),
|
||
global,
|
||
proto,
|
||
can_gc,
|
||
)
|
||
}
|
||
|
||
pub(super) fn set_associated_font_face_set(&self, font_face_set: &FontFaceSet) {
|
||
self.font_face_set.set(Some(font_face_set));
|
||
}
|
||
|
||
pub(super) fn loaded(&self) -> bool {
|
||
self.status.get() == FontFaceLoadStatus::Loaded
|
||
}
|
||
|
||
pub(super) fn template(&self) -> Option<(LowercaseFontFamilyName, FontTemplate)> {
|
||
self.template.borrow().clone()
|
||
}
|
||
|
||
/// Implements the body of the setter for the descriptor attributes of the [`FontFace`] interface.
|
||
///
|
||
/// <https://drafts.csswg.org/css-font-loading/#fontface-interface>:
|
||
/// On setting, parse the string according to the grammar for the corresponding @font-face
|
||
/// descriptor. If it does not match the grammar, throw a SyntaxError; otherwise, set the attribute
|
||
/// to the serialization of the parsed value.
|
||
fn validate_and_set_descriptors(&self, new_descriptors: FontFaceDescriptors) -> ErrorResult {
|
||
let global = self.global();
|
||
let parsed_font_face_rule = parse_font_face_descriptors(
|
||
&global,
|
||
&self.family_name.borrow(),
|
||
None,
|
||
&new_descriptors,
|
||
)?;
|
||
|
||
*self.descriptors.borrow_mut() = serialize_parsed_descriptors(&parsed_font_face_rule);
|
||
Ok(())
|
||
}
|
||
}
|
||
|
||
impl FontFaceMethods<crate::DomTypeHolder> for FontFace {
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-family>
|
||
fn Family(&self) -> DOMString {
|
||
self.family_name.borrow().clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-family>
|
||
fn SetFamily(&self, family_name: DOMString) -> ErrorResult {
|
||
let descriptors = self.descriptors.borrow();
|
||
let global = self.global();
|
||
let _ = parse_font_face_descriptors(&global, &family_name, None, &descriptors)?;
|
||
*self.family_name.borrow_mut() = family_name;
|
||
Ok(())
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-style>
|
||
fn Style(&self) -> DOMString {
|
||
self.descriptors.borrow().style.clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-style>
|
||
fn SetStyle(&self, value: DOMString) -> ErrorResult {
|
||
let mut new_descriptors = self.descriptors.borrow().clone();
|
||
new_descriptors.style = value;
|
||
self.validate_and_set_descriptors(new_descriptors)
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-weight>
|
||
fn Weight(&self) -> DOMString {
|
||
self.descriptors.borrow().weight.clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-weight>
|
||
fn SetWeight(&self, value: DOMString) -> ErrorResult {
|
||
let mut new_descriptors = self.descriptors.borrow().clone();
|
||
new_descriptors.weight = value;
|
||
self.validate_and_set_descriptors(new_descriptors)
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-stretch>
|
||
fn Stretch(&self) -> DOMString {
|
||
self.descriptors.borrow().stretch.clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-stretch>
|
||
fn SetStretch(&self, value: DOMString) -> ErrorResult {
|
||
let mut new_descriptors = self.descriptors.borrow().clone();
|
||
new_descriptors.stretch = value;
|
||
self.validate_and_set_descriptors(new_descriptors)
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-unicoderange>
|
||
fn UnicodeRange(&self) -> DOMString {
|
||
self.descriptors.borrow().unicodeRange.clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-unicoderange>
|
||
fn SetUnicodeRange(&self, value: DOMString) -> ErrorResult {
|
||
let mut new_descriptors = self.descriptors.borrow().clone();
|
||
new_descriptors.unicodeRange = value;
|
||
self.validate_and_set_descriptors(new_descriptors)
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-featuresettings>
|
||
fn FeatureSettings(&self) -> DOMString {
|
||
self.descriptors.borrow().featureSettings.clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-featuresettings>
|
||
fn SetFeatureSettings(&self, value: DOMString) -> ErrorResult {
|
||
let mut new_descriptors = self.descriptors.borrow().clone();
|
||
new_descriptors.featureSettings = value;
|
||
self.validate_and_set_descriptors(new_descriptors)
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-variationsettings>
|
||
fn VariationSettings(&self) -> DOMString {
|
||
self.descriptors.borrow().variationSettings.clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-variationsettings>
|
||
fn SetVariationSettings(&self, value: DOMString) -> ErrorResult {
|
||
let mut new_descriptors = self.descriptors.borrow().clone();
|
||
new_descriptors.variationSettings = value;
|
||
self.validate_and_set_descriptors(new_descriptors)
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-display>
|
||
fn Display(&self) -> DOMString {
|
||
self.descriptors.borrow().display.clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-display>
|
||
fn SetDisplay(&self, value: DOMString) -> ErrorResult {
|
||
let mut new_descriptors = self.descriptors.borrow().clone();
|
||
new_descriptors.display = value;
|
||
self.validate_and_set_descriptors(new_descriptors)
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-ascentoverride>
|
||
fn AscentOverride(&self) -> DOMString {
|
||
self.descriptors.borrow().ascentOverride.clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-ascentoverride>
|
||
fn SetAscentOverride(&self, value: DOMString) -> ErrorResult {
|
||
let mut new_descriptors = self.descriptors.borrow().clone();
|
||
new_descriptors.ascentOverride = value;
|
||
self.validate_and_set_descriptors(new_descriptors)
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-descentoverride>
|
||
fn DescentOverride(&self) -> DOMString {
|
||
self.descriptors.borrow().descentOverride.clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-descentoverride>
|
||
fn SetDescentOverride(&self, value: DOMString) -> ErrorResult {
|
||
let mut new_descriptors = self.descriptors.borrow().clone();
|
||
new_descriptors.descentOverride = value;
|
||
self.validate_and_set_descriptors(new_descriptors)
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-linegapoverride>
|
||
fn LineGapOverride(&self) -> DOMString {
|
||
self.descriptors.borrow().lineGapOverride.clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-linegapoverride>
|
||
fn SetLineGapOverride(&self, value: DOMString) -> ErrorResult {
|
||
let mut new_descriptors = self.descriptors.borrow().clone();
|
||
new_descriptors.lineGapOverride = value;
|
||
self.validate_and_set_descriptors(new_descriptors)
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-status>
|
||
fn Status(&self) -> FontFaceLoadStatus {
|
||
self.status.get()
|
||
}
|
||
|
||
/// The load() method of FontFace forces a url-based font face to request its font data and
|
||
/// load. For fonts constructed from a buffer source, or fonts that are already loading or
|
||
/// loaded, it does nothing.
|
||
/// <https://drafts.csswg.org/css-font-loading/#font-face-load>
|
||
fn Load(&self) -> Rc<Promise> {
|
||
let Some(sources) = self.urls.borrow_mut().take() else {
|
||
// Step 2. If font face’s [[Urls]] slot is null, or its status attribute is anything
|
||
// other than "unloaded", return font face’s [[FontStatusPromise]] and abort these
|
||
// steps.
|
||
return self.font_status_promise.clone();
|
||
};
|
||
|
||
// FontFace must not be loaded at this point as `self.urls` is not None, implying `Load`
|
||
// wasn't called already. In our implementation, `urls` is set after parsing, so it
|
||
// cannot be `Some` if the status is `Error`.
|
||
debug_assert_eq!(self.status.get(), FontFaceLoadStatus::Unloaded);
|
||
|
||
let global = self.global();
|
||
let trusted = Trusted::new(self);
|
||
let task_source = global
|
||
.task_manager()
|
||
.font_loading_task_source()
|
||
.to_sendable();
|
||
|
||
let finished_callback = Box::new(
|
||
move |family_name: LowercaseFontFamilyName, load_result: Option<_>| {
|
||
let trusted = trusted.clone();
|
||
|
||
// Step 5. When the load operation completes, successfully or not, queue a task to
|
||
// run the following steps synchronously:
|
||
task_source.queue(task!(resolve_font_face_load_task: move || {
|
||
let font_face = trusted.root();
|
||
|
||
match load_result {
|
||
None => {
|
||
// Step 5.1. If the attempt to load fails, reject font face’s
|
||
// [[FontStatusPromise]] with a DOMException whose name is "NetworkError"
|
||
// and set font face’s status attribute to "error".
|
||
font_face.status.set(FontFaceLoadStatus::Error);
|
||
font_face.font_status_promise.reject_error(Error::Network, CanGc::note());
|
||
}
|
||
Some(template) => {
|
||
// Step 5.2. Otherwise, font face now represents the loaded font;
|
||
// fulfill font face’s [[FontStatusPromise]] with font face and set
|
||
// font face’s status attribute to "loaded".
|
||
font_face.status.set(FontFaceLoadStatus::Loaded);
|
||
let old_template = font_face.template.borrow_mut().replace((family_name, template));
|
||
debug_assert!(old_template.is_none(), "FontFace's template must be intialized only once");
|
||
font_face.font_status_promise.resolve_native(&font_face, CanGc::note());
|
||
}
|
||
}
|
||
|
||
if let Some(font_face_set) = font_face.font_face_set.get() {
|
||
// For each FontFaceSet font face is in: ...
|
||
//
|
||
// This implements steps 5.1.1, 5.1.2, 5.2.1 and 5.2.2 - these
|
||
// take care of changing the status of the `FontFaceSet` in which this
|
||
// `FontFace` is a member, for both failed and successful load.
|
||
font_face_set.handle_font_face_status_changed(&font_face);
|
||
}
|
||
}));
|
||
},
|
||
);
|
||
|
||
// We parse the descriptors again because they are stored as `DOMString`s in this `FontFace`
|
||
// but the `load_web_font_for_script` API needs parsed values.
|
||
let parsed_font_face_rule = parse_font_face_descriptors(
|
||
&global,
|
||
&self.family_name.borrow(),
|
||
None,
|
||
&self.descriptors.borrow(),
|
||
)
|
||
.expect("Parsing shouldn't fail as descriptors are valid by construction");
|
||
|
||
// Construct a WebFontDocumentContext object for the current document.
|
||
let document_context = global.as_window().new_document_context();
|
||
|
||
// Step 4. Using the value of font face’s [[Urls]] slot, attempt to load a font as defined
|
||
// in [CSS-FONTS-3], as if it was the value of a @font-face rule’s src descriptor.
|
||
// TODO: FontFaceSet is not supported on Workers yet. The `as_window` call below should be
|
||
// replaced when we do support it.
|
||
global.as_window().font_context().load_web_font_for_script(
|
||
global.webview_id(),
|
||
sources,
|
||
(&parsed_font_face_rule).into(),
|
||
finished_callback,
|
||
&document_context,
|
||
);
|
||
|
||
// Step 3. Set font face’s status attribute to "loading", return font face’s
|
||
// [[FontStatusPromise]], and continue executing the rest of this algorithm asynchronously.
|
||
self.status.set(FontFaceLoadStatus::Loading);
|
||
self.font_status_promise.clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#dom-fontface-loaded>
|
||
fn Loaded(&self) -> Rc<Promise> {
|
||
self.font_status_promise.clone()
|
||
}
|
||
|
||
/// <https://drafts.csswg.org/css-font-loading/#font-face-constructor>
|
||
fn Constructor(
|
||
window: &Window,
|
||
proto: Option<HandleObject>,
|
||
can_gc: CanGc,
|
||
family: DOMString,
|
||
source: UnionTypes::StringOrArrayBufferViewOrArrayBuffer,
|
||
descriptors: &FontFaceDescriptors,
|
||
) -> DomRoot<FontFace> {
|
||
let global = window.as_global_scope();
|
||
FontFace::new(global, proto, family, source, descriptors, can_gc)
|
||
}
|
||
}
|