mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
script: add skeleton implementation of FontFace
API (#35262)
This patch implements the `FontFace` interface, but with some caveats 1. The interface is only exposed on `Window`. Support for Workers will be handled in the future. 2. The concept of `css-connected` `FontFace` is not implemented, so `@font-face` rules in stylesheets will not be represented in the DOM. 3. The constructor only supports using `url()` strings as source and `ArrayBuffer` and `ArrayBufferView` are not supported yet. A skeleton implementation of the `load` method of `FontFaceSet` is also implemented in this patch. The intention is to support some web pages that don't load without this method. Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
This commit is contained in:
parent
29e0fad21e
commit
56840e0a35
52 changed files with 1160 additions and 551 deletions
|
@ -81,6 +81,7 @@ pub struct Preferences {
|
||||||
pub dom_customelements_enabled: bool,
|
pub dom_customelements_enabled: bool,
|
||||||
pub dom_document_dblclick_timeout: i64,
|
pub dom_document_dblclick_timeout: i64,
|
||||||
pub dom_document_dblclick_dist: i64,
|
pub dom_document_dblclick_dist: i64,
|
||||||
|
pub dom_fontface_enabled: bool,
|
||||||
pub dom_forcetouch_enabled: bool,
|
pub dom_forcetouch_enabled: bool,
|
||||||
pub dom_fullscreen_test: bool,
|
pub dom_fullscreen_test: bool,
|
||||||
pub dom_gamepad_enabled: bool,
|
pub dom_gamepad_enabled: bool,
|
||||||
|
@ -245,6 +246,7 @@ impl Preferences {
|
||||||
dom_customelements_enabled: true,
|
dom_customelements_enabled: true,
|
||||||
dom_document_dblclick_dist: 1,
|
dom_document_dblclick_dist: 1,
|
||||||
dom_document_dblclick_timeout: 300,
|
dom_document_dblclick_timeout: 300,
|
||||||
|
dom_fontface_enabled: false,
|
||||||
dom_forcetouch_enabled: false,
|
dom_forcetouch_enabled: false,
|
||||||
dom_fullscreen_test: false,
|
dom_fullscreen_test: false,
|
||||||
dom_gamepad_enabled: true,
|
dom_gamepad_enabled: true,
|
||||||
|
|
|
@ -11,7 +11,7 @@ use std::sync::Arc;
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use base::id::WebViewId;
|
use base::id::WebViewId;
|
||||||
use fnv::FnvHasher;
|
use fnv::FnvHasher;
|
||||||
use fonts_traits::WebFontLoadFinishedCallback;
|
use fonts_traits::StylesheetWebFontLoadFinishedCallback;
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
|
@ -21,7 +21,9 @@ use parking_lot::{Mutex, RwLock};
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use style::computed_values::font_variant_caps::T as FontVariantCaps;
|
use style::computed_values::font_variant_caps::T as FontVariantCaps;
|
||||||
use style::font_face::{FontFaceSourceFormat, FontFaceSourceFormatKeyword, Source, UrlSource};
|
use style::font_face::{
|
||||||
|
FontFaceSourceFormat, FontFaceSourceFormatKeyword, Source, SourceList, UrlSource,
|
||||||
|
};
|
||||||
use style::media_queries::Device;
|
use style::media_queries::Device;
|
||||||
use style::properties::style_structs::Font as FontStyleStruct;
|
use style::properties::style_structs::Font as FontStyleStruct;
|
||||||
use style::shared_lock::SharedRwLockReadGuard;
|
use style::shared_lock::SharedRwLockReadGuard;
|
||||||
|
@ -133,18 +135,6 @@ impl FontContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle the situation where a web font finishes loading, specifying if the load suceeded or failed.
|
|
||||||
fn handle_web_font_load_finished(
|
|
||||||
&self,
|
|
||||||
finished_callback: &WebFontLoadFinishedCallback,
|
|
||||||
succeeded: bool,
|
|
||||||
) {
|
|
||||||
if succeeded {
|
|
||||||
self.invalidate_font_groups_after_web_font_load();
|
|
||||||
}
|
|
||||||
finished_callback(succeeded);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a `FontGroup` representing fonts which can be used for layout, given the `style`.
|
/// Returns a `FontGroup` representing fonts which can be used for layout, given the `style`.
|
||||||
/// Font groups are cached, so subsequent calls with the same `style` will return a reference
|
/// Font groups are cached, so subsequent calls with the same `style` will return a reference
|
||||||
/// to an existing `FontGroup`.
|
/// to an existing `FontGroup`.
|
||||||
|
@ -355,17 +345,138 @@ impl FontContext {
|
||||||
fn invalidate_font_groups_after_web_font_load(&self) {
|
fn invalidate_font_groups_after_web_font_load(&self) {
|
||||||
self.resolved_font_groups.write().clear();
|
self.resolved_font_groups.write().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_supported_web_font_source(source: &&Source) -> bool {
|
||||||
|
let url_source = match source {
|
||||||
|
Source::Url(ref url_source) => url_source,
|
||||||
|
Source::Local(_) => return true,
|
||||||
|
};
|
||||||
|
let format_hint = match url_source.format_hint {
|
||||||
|
Some(ref format_hint) => format_hint,
|
||||||
|
None => return true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if matches!(
|
||||||
|
format_hint,
|
||||||
|
FontFaceSourceFormat::Keyword(
|
||||||
|
FontFaceSourceFormatKeyword::Truetype |
|
||||||
|
FontFaceSourceFormatKeyword::Opentype |
|
||||||
|
FontFaceSourceFormatKeyword::Woff |
|
||||||
|
FontFaceSourceFormatKeyword::Woff2
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let FontFaceSourceFormat::String(string) = format_hint {
|
||||||
|
return string == "truetype" ||
|
||||||
|
string == "opentype" ||
|
||||||
|
string == "woff" ||
|
||||||
|
string == "woff2";
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub(crate) struct WebFontDownloadState {
|
pub(crate) struct WebFontDownloadState {
|
||||||
webview_id: WebViewId,
|
webview_id: Option<WebViewId>,
|
||||||
pub(crate) css_font_face_descriptors: Arc<CSSFontFaceDescriptors>,
|
css_font_face_descriptors: CSSFontFaceDescriptors,
|
||||||
remaining_sources: Vec<Source>,
|
remaining_sources: Vec<Source>,
|
||||||
finished_callback: WebFontLoadFinishedCallback,
|
|
||||||
core_resource_thread: CoreResourceThread,
|
core_resource_thread: CoreResourceThread,
|
||||||
local_fonts: Arc<HashMap<Atom, Option<FontTemplateRef>>>,
|
local_fonts: HashMap<Atom, Option<FontTemplateRef>>,
|
||||||
pub(crate) stylesheet: DocumentStyleSheet,
|
font_context: Arc<FontContext>,
|
||||||
|
initiator: WebFontLoadInitiator,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebFontDownloadState {
|
||||||
|
fn new(
|
||||||
|
webview_id: Option<WebViewId>,
|
||||||
|
font_context: Arc<FontContext>,
|
||||||
|
css_font_face_descriptors: CSSFontFaceDescriptors,
|
||||||
|
initiator: WebFontLoadInitiator,
|
||||||
|
sources: Vec<Source>,
|
||||||
|
local_fonts: HashMap<Atom, Option<FontTemplateRef>>,
|
||||||
|
) -> WebFontDownloadState {
|
||||||
|
match initiator {
|
||||||
|
WebFontLoadInitiator::Stylesheet(ref stylesheet, _) => {
|
||||||
|
font_context
|
||||||
|
.web_fonts
|
||||||
|
.write()
|
||||||
|
.handle_web_font_load_started_for_stylesheet(stylesheet);
|
||||||
|
},
|
||||||
|
WebFontLoadInitiator::Script(_) => {
|
||||||
|
font_context
|
||||||
|
.web_fonts
|
||||||
|
.write()
|
||||||
|
.handle_web_font_load_started_for_script();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let core_resource_thread = font_context.resource_threads.lock().clone();
|
||||||
|
WebFontDownloadState {
|
||||||
|
webview_id,
|
||||||
|
css_font_face_descriptors,
|
||||||
|
remaining_sources: sources,
|
||||||
|
core_resource_thread,
|
||||||
|
local_fonts,
|
||||||
|
font_context,
|
||||||
|
initiator,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_web_font_load_success(self, new_template: FontTemplate) {
|
||||||
|
let family_name = self.css_font_face_descriptors.family_name.clone();
|
||||||
|
match self.initiator {
|
||||||
|
WebFontLoadInitiator::Stylesheet(ref stylesheet, ref callback) => {
|
||||||
|
let not_cancelled = self
|
||||||
|
.font_context
|
||||||
|
.web_fonts
|
||||||
|
.write()
|
||||||
|
.handle_web_font_loaded_for_stylesheet(stylesheet, family_name, new_template);
|
||||||
|
self.font_context
|
||||||
|
.invalidate_font_groups_after_web_font_load();
|
||||||
|
callback(not_cancelled);
|
||||||
|
},
|
||||||
|
WebFontLoadInitiator::Script(callback) => {
|
||||||
|
self.font_context
|
||||||
|
.web_fonts
|
||||||
|
.write()
|
||||||
|
.handle_web_font_load_finished_for_script();
|
||||||
|
callback(family_name, Some(new_template));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_web_font_load_failure(self) {
|
||||||
|
let family_name = self.css_font_face_descriptors.family_name.clone();
|
||||||
|
match self.initiator {
|
||||||
|
WebFontLoadInitiator::Stylesheet(ref stylesheet, ref callback) => {
|
||||||
|
self.font_context
|
||||||
|
.web_fonts
|
||||||
|
.write()
|
||||||
|
.handle_web_font_load_failed_for_stylesheet(stylesheet);
|
||||||
|
callback(false);
|
||||||
|
},
|
||||||
|
WebFontLoadInitiator::Script(callback) => {
|
||||||
|
self.font_context
|
||||||
|
.web_fonts
|
||||||
|
.write()
|
||||||
|
.handle_web_font_load_finished_for_script();
|
||||||
|
callback(family_name, None);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn font_load_cancelled(&self) -> bool {
|
||||||
|
match self.initiator {
|
||||||
|
WebFontLoadInitiator::Stylesheet(ref stylesheet, _) => self
|
||||||
|
.font_context
|
||||||
|
.web_fonts
|
||||||
|
.read()
|
||||||
|
.font_load_cancelled_for_stylesheet(stylesheet),
|
||||||
|
WebFontLoadInitiator::Script(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FontContextWebFontMethods {
|
pub trait FontContextWebFontMethods {
|
||||||
|
@ -375,8 +486,20 @@ pub trait FontContextWebFontMethods {
|
||||||
stylesheet: &DocumentStyleSheet,
|
stylesheet: &DocumentStyleSheet,
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
device: &Device,
|
device: &Device,
|
||||||
finished_callback: WebFontLoadFinishedCallback,
|
finished_callback: StylesheetWebFontLoadFinishedCallback,
|
||||||
) -> usize;
|
) -> usize;
|
||||||
|
fn load_web_font_for_script(
|
||||||
|
&self,
|
||||||
|
webview_id: Option<WebViewId>,
|
||||||
|
source_list: SourceList,
|
||||||
|
descriptors: CSSFontFaceDescriptors,
|
||||||
|
finished_callback: ScriptWebFontLoadFinishedCallback,
|
||||||
|
);
|
||||||
|
fn add_template_to_font_context(
|
||||||
|
&self,
|
||||||
|
family_name: LowercaseFontFamilyName,
|
||||||
|
font_template: FontTemplate,
|
||||||
|
);
|
||||||
fn remove_all_web_fonts_from_stylesheet(&self, stylesheet: &DocumentStyleSheet);
|
fn remove_all_web_fonts_from_stylesheet(&self, stylesheet: &DocumentStyleSheet);
|
||||||
fn collect_unused_webrender_resources(&self, all: bool)
|
fn collect_unused_webrender_resources(&self, all: bool)
|
||||||
-> (Vec<FontKey>, Vec<FontInstanceKey>);
|
-> (Vec<FontKey>, Vec<FontInstanceKey>);
|
||||||
|
@ -389,7 +512,7 @@ impl FontContextWebFontMethods for Arc<FontContext> {
|
||||||
stylesheet: &DocumentStyleSheet,
|
stylesheet: &DocumentStyleSheet,
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
device: &Device,
|
device: &Device,
|
||||||
finished_callback: WebFontLoadFinishedCallback,
|
finished_callback: StylesheetWebFontLoadFinishedCallback,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let mut number_loading = 0;
|
let mut number_loading = 0;
|
||||||
for rule in stylesheet.effective_rules(device, guard) {
|
for rule in stylesheet.effective_rules(device, guard) {
|
||||||
|
@ -402,57 +525,17 @@ impl FontContextWebFontMethods for Arc<FontContext> {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let sources: Vec<Source> = font_face
|
let css_font_face_descriptors = rule.into();
|
||||||
.sources()
|
let completion_handler =
|
||||||
.0
|
WebFontLoadInitiator::Stylesheet(stylesheet.clone(), finished_callback.clone());
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.filter(is_supported_web_font_source)
|
|
||||||
.cloned()
|
|
||||||
.collect();
|
|
||||||
if sources.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch all local fonts first, beacause if we try to fetch them later on during the process of
|
|
||||||
// loading the list of web font `src`s we may be running in the context of the router thread, which
|
|
||||||
// means we won't be able to seend IPC messages to the FontCacheThread.
|
|
||||||
//
|
|
||||||
// TODO: This is completely wrong. The specification says that `local()` font-family should match
|
|
||||||
// against full PostScript names, but this is matching against font family names. This works...
|
|
||||||
// sometimes.
|
|
||||||
let mut local_fonts = HashMap::new();
|
|
||||||
for source in sources.iter() {
|
|
||||||
if let Source::Local(family_name) = source {
|
|
||||||
local_fonts
|
|
||||||
.entry(family_name.name.clone())
|
|
||||||
.or_insert_with(|| {
|
|
||||||
let family = SingleFontFamily::FamilyName(FamilyName {
|
|
||||||
name: family_name.name.clone(),
|
|
||||||
syntax: FontFamilyNameSyntax::Quoted,
|
|
||||||
});
|
|
||||||
self.system_font_service_proxy
|
|
||||||
.find_matching_font_templates(None, &family)
|
|
||||||
.first()
|
|
||||||
.cloned()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
number_loading += 1;
|
number_loading += 1;
|
||||||
self.web_fonts
|
self.start_loading_one_web_font(
|
||||||
.write()
|
Some(webview_id),
|
||||||
.handle_web_font_load_started_for_stylesheet(stylesheet);
|
font_face.sources(),
|
||||||
|
css_font_face_descriptors,
|
||||||
self.process_next_web_font_source(WebFontDownloadState {
|
completion_handler,
|
||||||
webview_id,
|
);
|
||||||
css_font_face_descriptors: Arc::new(rule.into()),
|
|
||||||
remaining_sources: sources,
|
|
||||||
finished_callback: finished_callback.clone(),
|
|
||||||
core_resource_thread: self.resource_threads.lock().clone(),
|
|
||||||
local_fonts: Arc::new(local_fonts),
|
|
||||||
stylesheet: stylesheet.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
number_loading
|
number_loading
|
||||||
|
@ -553,15 +636,84 @@ impl FontContextWebFontMethods for Arc<FontContext> {
|
||||||
removed_instance_keys.into_iter().collect(),
|
removed_instance_keys.into_iter().collect(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_web_font_for_script(
|
||||||
|
&self,
|
||||||
|
webview_id: Option<WebViewId>,
|
||||||
|
sources: SourceList,
|
||||||
|
descriptors: CSSFontFaceDescriptors,
|
||||||
|
finished_callback: ScriptWebFontLoadFinishedCallback,
|
||||||
|
) {
|
||||||
|
let completion_handler = WebFontLoadInitiator::Script(finished_callback);
|
||||||
|
self.start_loading_one_web_font(webview_id, &sources, descriptors, completion_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_template_to_font_context(
|
||||||
|
&self,
|
||||||
|
family_name: LowercaseFontFamilyName,
|
||||||
|
new_template: FontTemplate,
|
||||||
|
) {
|
||||||
|
self.web_fonts
|
||||||
|
.write()
|
||||||
|
.add_new_template(family_name, new_template);
|
||||||
|
self.invalidate_font_groups_after_web_font_load();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontContext {
|
impl FontContext {
|
||||||
|
fn start_loading_one_web_font(
|
||||||
|
self: &Arc<FontContext>,
|
||||||
|
webview_id: Option<WebViewId>,
|
||||||
|
source_list: &SourceList,
|
||||||
|
css_font_face_descriptors: CSSFontFaceDescriptors,
|
||||||
|
completion_handler: WebFontLoadInitiator,
|
||||||
|
) {
|
||||||
|
let sources: Vec<Source> = source_list
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.filter(Self::is_supported_web_font_source)
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Fetch all local fonts first, beacause if we try to fetch them later on during the process of
|
||||||
|
// loading the list of web font `src`s we may be running in the context of the router thread, which
|
||||||
|
// means we won't be able to seend IPC messages to the FontCacheThread.
|
||||||
|
//
|
||||||
|
// TODO: This is completely wrong. The specification says that `local()` font-family should match
|
||||||
|
// against full PostScript names, but this is matching against font family names. This works...
|
||||||
|
// sometimes.
|
||||||
|
let mut local_fonts = HashMap::new();
|
||||||
|
for source in sources.iter() {
|
||||||
|
if let Source::Local(family_name) = source {
|
||||||
|
local_fonts
|
||||||
|
.entry(family_name.name.clone())
|
||||||
|
.or_insert_with(|| {
|
||||||
|
let family = SingleFontFamily::FamilyName(FamilyName {
|
||||||
|
name: family_name.name.clone(),
|
||||||
|
syntax: FontFamilyNameSyntax::Quoted,
|
||||||
|
});
|
||||||
|
self.system_font_service_proxy
|
||||||
|
.find_matching_font_templates(None, &family)
|
||||||
|
.first()
|
||||||
|
.cloned()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.process_next_web_font_source(WebFontDownloadState::new(
|
||||||
|
webview_id,
|
||||||
|
self.clone(),
|
||||||
|
css_font_face_descriptors,
|
||||||
|
completion_handler,
|
||||||
|
sources,
|
||||||
|
local_fonts,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
fn process_next_web_font_source(self: &Arc<FontContext>, mut state: WebFontDownloadState) {
|
fn process_next_web_font_source(self: &Arc<FontContext>, mut state: WebFontDownloadState) {
|
||||||
let Some(source) = state.remaining_sources.pop() else {
|
let Some(source) = state.remaining_sources.pop() else {
|
||||||
self.web_fonts
|
state.handle_web_font_load_failure();
|
||||||
.write()
|
|
||||||
.handle_web_font_failed_to_load(&state);
|
|
||||||
self.handle_web_font_load_finished(&state.finished_callback, false);
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -581,17 +733,13 @@ impl FontContext {
|
||||||
let template = FontTemplate::new_for_local_web_font(
|
let template = FontTemplate::new_for_local_web_font(
|
||||||
local_template.clone(),
|
local_template.clone(),
|
||||||
&state.css_font_face_descriptors,
|
&state.css_font_face_descriptors,
|
||||||
state.stylesheet.clone(),
|
state.initiator.stylesheet().cloned(),
|
||||||
)
|
)
|
||||||
.ok()?;
|
.ok()?;
|
||||||
Some(template)
|
Some(template)
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
let not_cancelled = self
|
state.handle_web_font_load_success(new_template);
|
||||||
.web_fonts
|
|
||||||
.write()
|
|
||||||
.handle_web_font_loaded(&state, new_template);
|
|
||||||
self.handle_web_font_load_finished(&state.finished_callback, not_cancelled);
|
|
||||||
} else {
|
} else {
|
||||||
this.process_next_web_font_source(state);
|
this.process_next_web_font_source(state);
|
||||||
}
|
}
|
||||||
|
@ -600,12 +748,29 @@ impl FontContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type ScriptWebFontLoadFinishedCallback =
|
||||||
|
Box<dyn FnOnce(LowercaseFontFamilyName, Option<FontTemplate>) + Send>;
|
||||||
|
|
||||||
|
pub(crate) enum WebFontLoadInitiator {
|
||||||
|
Stylesheet(DocumentStyleSheet, StylesheetWebFontLoadFinishedCallback),
|
||||||
|
Script(ScriptWebFontLoadFinishedCallback),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebFontLoadInitiator {
|
||||||
|
pub(crate) fn stylesheet(&self) -> Option<&DocumentStyleSheet> {
|
||||||
|
match self {
|
||||||
|
Self::Stylesheet(stylesheet, _) => Some(stylesheet),
|
||||||
|
Self::Script(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct RemoteWebFontDownloader {
|
struct RemoteWebFontDownloader {
|
||||||
font_context: Arc<FontContext>,
|
state: Option<WebFontDownloadState>,
|
||||||
url: ServoArc<Url>,
|
url: ServoArc<Url>,
|
||||||
web_font_family_name: LowercaseFontFamilyName,
|
web_font_family_name: LowercaseFontFamilyName,
|
||||||
response_valid: Mutex<bool>,
|
response_valid: bool,
|
||||||
response_data: Mutex<Vec<u8>>,
|
response_data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DownloaderResponseResult {
|
enum DownloaderResponseResult {
|
||||||
|
@ -628,23 +793,21 @@ impl RemoteWebFontDownloader {
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: This shouldn't use NoReferrer, but the current documents url
|
// FIXME: This shouldn't use NoReferrer, but the current documents url
|
||||||
let request = RequestBuilder::new(
|
let request =
|
||||||
Some(state.webview_id),
|
RequestBuilder::new(state.webview_id, url.clone().into(), Referrer::NoReferrer)
|
||||||
url.clone().into(),
|
.destination(Destination::Font);
|
||||||
Referrer::NoReferrer,
|
|
||||||
)
|
|
||||||
.destination(Destination::Font);
|
|
||||||
|
|
||||||
debug!("Loading @font-face {} from {}", web_font_family_name, url);
|
|
||||||
let downloader = Self {
|
|
||||||
font_context,
|
|
||||||
url,
|
|
||||||
web_font_family_name,
|
|
||||||
response_valid: Mutex::new(false),
|
|
||||||
response_data: Mutex::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let core_resource_thread_clone = state.core_resource_thread.clone();
|
let core_resource_thread_clone = state.core_resource_thread.clone();
|
||||||
|
|
||||||
|
debug!("Loading @font-face {} from {}", web_font_family_name, url);
|
||||||
|
let mut downloader = Self {
|
||||||
|
url,
|
||||||
|
web_font_family_name,
|
||||||
|
response_valid: false,
|
||||||
|
response_data: Vec::new(),
|
||||||
|
state: Some(state),
|
||||||
|
};
|
||||||
|
|
||||||
fetch_async(
|
fetch_async(
|
||||||
&core_resource_thread_clone,
|
&core_resource_thread_clone,
|
||||||
request,
|
request,
|
||||||
|
@ -653,40 +816,42 @@ impl RemoteWebFontDownloader {
|
||||||
match downloader.handle_web_font_fetch_message(response_message) {
|
match downloader.handle_web_font_fetch_message(response_message) {
|
||||||
DownloaderResponseResult::InProcess => {},
|
DownloaderResponseResult::InProcess => {},
|
||||||
DownloaderResponseResult::Finished => {
|
DownloaderResponseResult::Finished => {
|
||||||
if !downloader.process_downloaded_font_and_signal_completion(&state) {
|
if !downloader.process_downloaded_font_and_signal_completion() {
|
||||||
downloader
|
font_context.process_next_web_font_source(downloader.take_state())
|
||||||
.font_context
|
|
||||||
.process_next_web_font_source(state.clone())
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DownloaderResponseResult::Failure => downloader
|
DownloaderResponseResult::Failure => {
|
||||||
.font_context
|
font_context.process_next_web_font_source(downloader.take_state())
|
||||||
.process_next_web_font_source(state.clone()),
|
},
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn take_state(&mut self) -> WebFontDownloadState {
|
||||||
|
self.state
|
||||||
|
.take()
|
||||||
|
.expect("must be non-None until download either succeeds or fails")
|
||||||
|
}
|
||||||
|
|
||||||
/// After a download finishes, try to process the downloaded data, returning true if
|
/// After a download finishes, try to process the downloaded data, returning true if
|
||||||
/// the font is added successfully to the [`FontContext`] or false if it isn't.
|
/// the font is added successfully to the [`FontContext`] or false if it isn't.
|
||||||
fn process_downloaded_font_and_signal_completion(&self, state: &WebFontDownloadState) -> bool {
|
fn process_downloaded_font_and_signal_completion(&mut self) -> bool {
|
||||||
if self
|
let state = self
|
||||||
.font_context
|
.state
|
||||||
.web_fonts
|
.as_ref()
|
||||||
.read()
|
.expect("must be non-None until processing is completed");
|
||||||
.font_load_cancelled_for_stylesheet(&state.stylesheet)
|
if state.font_load_cancelled() {
|
||||||
{
|
self.take_state().handle_web_font_load_failure();
|
||||||
self.font_context
|
|
||||||
.handle_web_font_load_finished(&state.finished_callback, false);
|
|
||||||
// Returning true here prevents trying to load the next font on the source list.
|
// Returning true here prevents trying to load the next font on the source list.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let font_data = std::mem::take(&mut *self.response_data.lock());
|
let font_data = std::mem::take(&mut self.response_data);
|
||||||
trace!(
|
trace!(
|
||||||
"@font-face {} data={:?}",
|
"Downloaded @font-face {} ({} bytes)",
|
||||||
self.web_font_family_name,
|
self.web_font_family_name,
|
||||||
font_data
|
font_data.len()
|
||||||
);
|
);
|
||||||
|
|
||||||
let font_data = match fontsan::process(&font_data) {
|
let font_data = match fontsan::process(&font_data) {
|
||||||
|
@ -705,6 +870,8 @@ impl RemoteWebFontDownloader {
|
||||||
let Ok(handle) = PlatformFont::new_from_data(identifier, &font_data, None) else {
|
let Ok(handle) = PlatformFont::new_from_data(identifier, &font_data, None) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let state = self.take_state();
|
||||||
let mut descriptor = handle.descriptor();
|
let mut descriptor = handle.descriptor();
|
||||||
descriptor
|
descriptor
|
||||||
.override_values_with_css_font_template_descriptors(&state.css_font_face_descriptors);
|
.override_values_with_css_font_template_descriptors(&state.css_font_face_descriptors);
|
||||||
|
@ -712,20 +879,16 @@ impl RemoteWebFontDownloader {
|
||||||
let new_template = FontTemplate::new(
|
let new_template = FontTemplate::new(
|
||||||
FontIdentifier::Web(url),
|
FontIdentifier::Web(url),
|
||||||
descriptor,
|
descriptor,
|
||||||
Some(state.stylesheet.clone()),
|
state.initiator.stylesheet().cloned(),
|
||||||
);
|
);
|
||||||
self.font_context
|
|
||||||
|
state
|
||||||
|
.font_context
|
||||||
.font_data
|
.font_data
|
||||||
.write()
|
.write()
|
||||||
.insert(new_template.identifier.clone(), font_data);
|
.insert(new_template.identifier.clone(), font_data);
|
||||||
|
|
||||||
let not_cancelled = self
|
state.handle_web_font_load_success(new_template);
|
||||||
.font_context
|
|
||||||
.web_fonts
|
|
||||||
.write()
|
|
||||||
.handle_web_font_loaded(state, new_template);
|
|
||||||
self.font_context
|
|
||||||
.handle_web_font_load_finished(&state.finished_callback, not_cancelled);
|
|
||||||
|
|
||||||
// If the load was canceled above, then we still want to return true from this function in
|
// If the load was canceled above, then we still want to return true from this function in
|
||||||
// order to halt any attempt to load sources that come later on the source list.
|
// order to halt any attempt to load sources that come later on the source list.
|
||||||
|
@ -733,7 +896,7 @@ impl RemoteWebFontDownloader {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_web_font_fetch_message(
|
fn handle_web_font_fetch_message(
|
||||||
&self,
|
&mut self,
|
||||||
response_message: FetchResponseMsg,
|
response_message: FetchResponseMsg,
|
||||||
) -> DownloaderResponseResult {
|
) -> DownloaderResponseResult {
|
||||||
match response_message {
|
match response_message {
|
||||||
|
@ -746,7 +909,7 @@ impl RemoteWebFontDownloader {
|
||||||
self.web_font_family_name,
|
self.web_font_family_name,
|
||||||
meta_result.is_ok()
|
meta_result.is_ok()
|
||||||
);
|
);
|
||||||
*self.response_valid.lock() = meta_result.is_ok();
|
self.response_valid = meta_result.is_ok();
|
||||||
DownloaderResponseResult::InProcess
|
DownloaderResponseResult::InProcess
|
||||||
},
|
},
|
||||||
FetchResponseMsg::ProcessResponseChunk(_, new_bytes) => {
|
FetchResponseMsg::ProcessResponseChunk(_, new_bytes) => {
|
||||||
|
@ -755,8 +918,8 @@ impl RemoteWebFontDownloader {
|
||||||
self.web_font_family_name,
|
self.web_font_family_name,
|
||||||
new_bytes
|
new_bytes
|
||||||
);
|
);
|
||||||
if *self.response_valid.lock() {
|
if self.response_valid {
|
||||||
self.response_data.lock().extend(new_bytes)
|
self.response_data.extend(new_bytes)
|
||||||
}
|
}
|
||||||
DownloaderResponseResult::InProcess
|
DownloaderResponseResult::InProcess
|
||||||
},
|
},
|
||||||
|
@ -766,7 +929,7 @@ impl RemoteWebFontDownloader {
|
||||||
self.web_font_family_name,
|
self.web_font_family_name,
|
||||||
response
|
response
|
||||||
);
|
);
|
||||||
if response.is_err() || !*self.response_valid.lock() {
|
if response.is_err() || !self.response_valid {
|
||||||
return DownloaderResponseResult::Failure;
|
return DownloaderResponseResult::Failure;
|
||||||
}
|
}
|
||||||
DownloaderResponseResult::Finished
|
DownloaderResponseResult::Finished
|
||||||
|
@ -804,35 +967,3 @@ impl Hash for FontGroupCacheKey {
|
||||||
self.style.hash.hash(hasher)
|
self.style.hash.hash(hasher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_supported_web_font_source(source: &&Source) -> bool {
|
|
||||||
let url_source = match source {
|
|
||||||
Source::Url(ref url_source) => url_source,
|
|
||||||
Source::Local(_) => return true,
|
|
||||||
};
|
|
||||||
let format_hint = match url_source.format_hint {
|
|
||||||
Some(ref format_hint) => format_hint,
|
|
||||||
None => return true,
|
|
||||||
};
|
|
||||||
|
|
||||||
if matches!(
|
|
||||||
format_hint,
|
|
||||||
FontFaceSourceFormat::Keyword(
|
|
||||||
FontFaceSourceFormatKeyword::Truetype |
|
|
||||||
FontFaceSourceFormatKeyword::Opentype |
|
|
||||||
FontFaceSourceFormatKeyword::Woff |
|
|
||||||
FontFaceSourceFormatKeyword::Woff2
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let FontFaceSourceFormat::String(string) = format_hint {
|
|
||||||
return string == "truetype" ||
|
|
||||||
string == "opentype" ||
|
|
||||||
string == "woff" ||
|
|
||||||
string == "woff2";
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,14 +12,14 @@ use style::stylesheets::DocumentStyleSheet;
|
||||||
use style::values::computed::{FontStyle, FontWeight};
|
use style::values::computed::{FontStyle, FontWeight};
|
||||||
|
|
||||||
use crate::font::FontDescriptor;
|
use crate::font::FontDescriptor;
|
||||||
use crate::font_context::WebFontDownloadState;
|
|
||||||
use crate::font_template::{FontTemplate, FontTemplateRef, FontTemplateRefMethods, IsOblique};
|
use crate::font_template::{FontTemplate, FontTemplateRef, FontTemplateRefMethods, IsOblique};
|
||||||
use crate::system_font_service::{FontIdentifier, LowercaseFontFamilyName};
|
use crate::system_font_service::{FontIdentifier, LowercaseFontFamilyName};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct FontStore {
|
pub struct FontStore {
|
||||||
pub(crate) families: HashMap<LowercaseFontFamilyName, FontTemplates>,
|
pub(crate) families: HashMap<LowercaseFontFamilyName, FontTemplates>,
|
||||||
web_fonts_loading: Vec<(DocumentStyleSheet, usize)>,
|
web_fonts_loading_for_stylesheets: Vec<(DocumentStyleSheet, usize)>,
|
||||||
|
web_fonts_loading_for_script: usize,
|
||||||
}
|
}
|
||||||
pub(crate) type CrossThreadFontStore = Arc<RwLock<FontStore>>;
|
pub(crate) type CrossThreadFontStore = Arc<RwLock<FontStore>>;
|
||||||
|
|
||||||
|
@ -33,13 +33,13 @@ impl FontStore {
|
||||||
stylesheet: &DocumentStyleSheet,
|
stylesheet: &DocumentStyleSheet,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
!self
|
!self
|
||||||
.web_fonts_loading
|
.web_fonts_loading_for_stylesheets
|
||||||
.iter()
|
.iter()
|
||||||
.any(|(loading_stylesheet, _)| loading_stylesheet == stylesheet)
|
.any(|(loading_stylesheet, _)| loading_stylesheet == stylesheet)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn handle_stylesheet_removed(&mut self, stylesheet: &DocumentStyleSheet) {
|
pub(crate) fn handle_stylesheet_removed(&mut self, stylesheet: &DocumentStyleSheet) {
|
||||||
self.web_fonts_loading
|
self.web_fonts_loading_for_stylesheets
|
||||||
.retain(|(loading_stylesheet, _)| loading_stylesheet != stylesheet);
|
.retain(|(loading_stylesheet, _)| loading_stylesheet != stylesheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,54 +48,82 @@ impl FontStore {
|
||||||
stylesheet: &DocumentStyleSheet,
|
stylesheet: &DocumentStyleSheet,
|
||||||
) {
|
) {
|
||||||
if let Some((_, count)) = self
|
if let Some((_, count)) = self
|
||||||
.web_fonts_loading
|
.web_fonts_loading_for_stylesheets
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.find(|(loading_stylesheet, _)| loading_stylesheet == stylesheet)
|
.find(|(loading_stylesheet, _)| loading_stylesheet == stylesheet)
|
||||||
{
|
{
|
||||||
*count += 1;
|
*count += 1;
|
||||||
} else {
|
} else {
|
||||||
self.web_fonts_loading.push((stylesheet.clone(), 1))
|
self.web_fonts_loading_for_stylesheets
|
||||||
|
.push((stylesheet.clone(), 1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_one_web_font_loading_for_stylesheet(&mut self, stylesheet: &DocumentStyleSheet) {
|
fn remove_one_web_font_loading_for_stylesheet(&mut self, stylesheet: &DocumentStyleSheet) {
|
||||||
if let Some((_, count)) = self
|
if let Some((_, count)) = self
|
||||||
.web_fonts_loading
|
.web_fonts_loading_for_stylesheets
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.find(|(loading_stylesheet, _)| loading_stylesheet == stylesheet)
|
.find(|(loading_stylesheet, _)| loading_stylesheet == stylesheet)
|
||||||
{
|
{
|
||||||
*count -= 1;
|
*count -= 1;
|
||||||
}
|
}
|
||||||
self.web_fonts_loading.retain(|(_, count)| *count != 0);
|
self.web_fonts_loading_for_stylesheets
|
||||||
|
.retain(|(_, count)| *count != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn handle_web_font_failed_to_load(&mut self, state: &WebFontDownloadState) {
|
pub(crate) fn handle_web_font_load_failed_for_stylesheet(
|
||||||
self.remove_one_web_font_loading_for_stylesheet(&state.stylesheet);
|
&mut self,
|
||||||
|
stylesheet: &DocumentStyleSheet,
|
||||||
|
) {
|
||||||
|
self.remove_one_web_font_loading_for_stylesheet(stylesheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle a web font load finishing, adding the new font to the [`FontStore`]. If the web font
|
/// Handle a web font load finishing, adding the new font to the [`FontStore`]. If the web font
|
||||||
/// load was canceled (for instance, if the stylesheet was removed), then do nothing and return
|
/// load was canceled (for instance, if the stylesheet was removed), then do nothing and return
|
||||||
/// false.
|
/// false.
|
||||||
pub(crate) fn handle_web_font_loaded(
|
pub(crate) fn handle_web_font_loaded_for_stylesheet(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &WebFontDownloadState,
|
stylesheet: &DocumentStyleSheet,
|
||||||
|
family_name: LowercaseFontFamilyName,
|
||||||
new_template: FontTemplate,
|
new_template: FontTemplate,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Abort processing this web font if the originating stylesheet was removed.
|
// Abort processing this web font if the originating stylesheet was removed.
|
||||||
if self.font_load_cancelled_for_stylesheet(&state.stylesheet) {
|
if self.font_load_cancelled_for_stylesheet(stylesheet) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let family_name = state.css_font_face_descriptors.family_name.clone();
|
|
||||||
|
self.add_new_template(family_name, new_template);
|
||||||
|
|
||||||
|
self.remove_one_web_font_loading_for_stylesheet(stylesheet);
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_new_template(
|
||||||
|
&mut self,
|
||||||
|
family_name: LowercaseFontFamilyName,
|
||||||
|
new_template: FontTemplate,
|
||||||
|
) {
|
||||||
self.families
|
self.families
|
||||||
.entry(family_name)
|
.entry(family_name)
|
||||||
.or_default()
|
.or_default()
|
||||||
.add_template(new_template);
|
.add_template(new_template);
|
||||||
self.remove_one_web_font_loading_for_stylesheet(&state.stylesheet);
|
}
|
||||||
true
|
|
||||||
|
pub(crate) fn handle_web_font_load_started_for_script(&mut self) {
|
||||||
|
self.web_fonts_loading_for_script += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn handle_web_font_load_finished_for_script(&mut self) {
|
||||||
|
self.web_fonts_loading_for_script -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn number_of_fonts_still_loading(&self) -> usize {
|
pub(crate) fn number_of_fonts_still_loading(&self) -> usize {
|
||||||
self.web_fonts_loading.iter().map(|(_, count)| count).sum()
|
self.web_fonts_loading_for_script +
|
||||||
|
self.web_fonts_loading_for_stylesheets
|
||||||
|
.iter()
|
||||||
|
.map(|(_, count)| count)
|
||||||
|
.sum::<usize>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,13 +177,13 @@ impl FontTemplate {
|
||||||
pub fn new_for_local_web_font(
|
pub fn new_for_local_web_font(
|
||||||
local_template: FontTemplateRef,
|
local_template: FontTemplateRef,
|
||||||
css_font_template_descriptors: &CSSFontFaceDescriptors,
|
css_font_template_descriptors: &CSSFontFaceDescriptors,
|
||||||
stylesheet: DocumentStyleSheet,
|
stylesheet: Option<DocumentStyleSheet>,
|
||||||
) -> Result<FontTemplate, &'static str> {
|
) -> Result<FontTemplate, &'static str> {
|
||||||
let mut alias_template = local_template.borrow().clone();
|
let mut alias_template = local_template.borrow().clone();
|
||||||
alias_template
|
alias_template
|
||||||
.descriptor
|
.descriptor
|
||||||
.override_values_with_css_font_template_descriptors(css_font_template_descriptors);
|
.override_values_with_css_font_template_descriptors(css_font_template_descriptors);
|
||||||
alias_template.stylesheet = Some(stylesheet);
|
alias_template.stylesheet = stylesheet;
|
||||||
Ok(alias_template)
|
Ok(alias_template)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -565,7 +565,7 @@ impl SystemFontServiceProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||||
pub struct LowercaseFontFamilyName {
|
pub struct LowercaseFontFamilyName {
|
||||||
inner: String,
|
inner: String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ use fnv::FnvHashMap;
|
||||||
use fonts::{
|
use fonts::{
|
||||||
get_and_reset_text_shaping_performance_counter, FontContext, FontContextWebFontMethods,
|
get_and_reset_text_shaping_performance_counter, FontContext, FontContextWebFontMethods,
|
||||||
};
|
};
|
||||||
use fonts_traits::WebFontLoadFinishedCallback;
|
use fonts_traits::StylesheetWebFontLoadFinishedCallback;
|
||||||
use fxhash::{FxHashMap, FxHashSet};
|
use fxhash::{FxHashMap, FxHashSet};
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use layout::construct::ConstructionResult;
|
use layout::construct::ConstructionResult;
|
||||||
|
@ -627,7 +627,7 @@ impl LayoutThread {
|
||||||
stylesheet,
|
stylesheet,
|
||||||
guard,
|
guard,
|
||||||
self.stylist.device(),
|
self.stylist.device(),
|
||||||
Arc::new(web_font_finished_loading_callback) as WebFontLoadFinishedCallback,
|
Arc::new(web_font_finished_loading_callback) as StylesheetWebFontLoadFinishedCallback,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as
|
||||||
use euclid::{Point2D, Scale, Size2D, Vector2D};
|
use euclid::{Point2D, Scale, Size2D, Vector2D};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use fonts::{FontContext, FontContextWebFontMethods};
|
use fonts::{FontContext, FontContextWebFontMethods};
|
||||||
use fonts_traits::WebFontLoadFinishedCallback;
|
use fonts_traits::StylesheetWebFontLoadFinishedCallback;
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
|
@ -602,7 +602,7 @@ impl LayoutThread {
|
||||||
stylesheet,
|
stylesheet,
|
||||||
guard,
|
guard,
|
||||||
self.stylist.device(),
|
self.stylist.device(),
|
||||||
Arc::new(web_font_finished_loading_callback) as WebFontLoadFinishedCallback,
|
Arc::new(web_font_finished_loading_callback) as StylesheetWebFontLoadFinishedCallback,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -711,6 +711,7 @@ malloc_size_of_is_0!(std::sync::atomic::AtomicUsize);
|
||||||
malloc_size_of_is_0!(std::time::Duration);
|
malloc_size_of_is_0!(std::time::Duration);
|
||||||
malloc_size_of_is_0!(std::time::Instant);
|
malloc_size_of_is_0!(std::time::Instant);
|
||||||
malloc_size_of_is_0!(std::time::SystemTime);
|
malloc_size_of_is_0!(std::time::SystemTime);
|
||||||
|
malloc_size_of_is_0!(style::font_face::SourceList);
|
||||||
|
|
||||||
macro_rules! malloc_size_of_is_webrender_malloc_size_of(
|
macro_rules! malloc_size_of_is_webrender_malloc_size_of(
|
||||||
($($ty:ty),+) => (
|
($($ty:ty),+) => (
|
||||||
|
|
|
@ -104,6 +104,7 @@ impl Formattable for ProfilerCategory {
|
||||||
ProfilerCategory::ScriptDocumentEvent => "Script Document Event",
|
ProfilerCategory::ScriptDocumentEvent => "Script Document Event",
|
||||||
ProfilerCategory::ScriptEvaluate => "Script JS Evaluate",
|
ProfilerCategory::ScriptEvaluate => "Script JS Evaluate",
|
||||||
ProfilerCategory::ScriptFileRead => "Script File Read",
|
ProfilerCategory::ScriptFileRead => "Script File Read",
|
||||||
|
ProfilerCategory::ScriptFontLoading => "Script Font Loading",
|
||||||
ProfilerCategory::ScriptHistoryEvent => "Script History Event",
|
ProfilerCategory::ScriptHistoryEvent => "Script History Event",
|
||||||
ProfilerCategory::ScriptImageCacheMsg => "Script Image Cache Msg",
|
ProfilerCategory::ScriptImageCacheMsg => "Script Image Cache Msg",
|
||||||
ProfilerCategory::ScriptInputEvent => "Script Input Event",
|
ProfilerCategory::ScriptInputEvent => "Script Input Event",
|
||||||
|
|
|
@ -594,7 +594,7 @@ impl EventSourceMethods<crate::DomTypeHolder> for EventSource {
|
||||||
last_event_id: String::new(),
|
last_event_id: String::new(),
|
||||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||||
};
|
};
|
||||||
let listener = NetworkListener {
|
let mut listener = NetworkListener {
|
||||||
context: Arc::new(Mutex::new(context)),
|
context: Arc::new(Mutex::new(context)),
|
||||||
task_source: global.task_manager().networking_task_source().into(),
|
task_source: global.task_manager().networking_task_source().into(),
|
||||||
};
|
};
|
||||||
|
|
577
components/script/dom/fontface.rs
Normal file
577
components/script/dom/fontface.rs
Normal file
|
@ -0,0 +1,577 @@
|
||||||
|
/* 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::{reflect_dom_object_with_proto, Reflector};
|
||||||
|
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 {
|
||||||
|
ref ascentOverride,
|
||||||
|
ref descentOverride,
|
||||||
|
ref display,
|
||||||
|
ref featureSettings,
|
||||||
|
ref lineGapOverride,
|
||||||
|
ref stretch,
|
||||||
|
ref style,
|
||||||
|
ref unicodeRange,
|
||||||
|
ref variationSettings,
|
||||||
|
ref 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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,26 +5,35 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
|
use fonts::FontContextWebFontMethods;
|
||||||
use js::rust::HandleObject;
|
use js::rust::HandleObject;
|
||||||
|
|
||||||
|
use super::bindings::reflector::DomGlobal;
|
||||||
|
use super::types::Window;
|
||||||
use crate::dom::bindings::codegen::Bindings::FontFaceSetBinding::FontFaceSetMethods;
|
use crate::dom::bindings::codegen::Bindings::FontFaceSetBinding::FontFaceSetMethods;
|
||||||
|
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
||||||
|
use crate::dom::bindings::refcounted::TrustedPromise;
|
||||||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||||
use crate::dom::bindings::root::DomRoot;
|
use crate::dom::bindings::root::DomRoot;
|
||||||
|
use crate::dom::bindings::str::DOMString;
|
||||||
use crate::dom::eventtarget::EventTarget;
|
use crate::dom::eventtarget::EventTarget;
|
||||||
|
use crate::dom::fontface::FontFace;
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
use crate::dom::promise::Promise;
|
use crate::dom::promise::Promise;
|
||||||
use crate::realms::enter_realm;
|
|
||||||
use crate::script_runtime::CanGc;
|
use crate::script_runtime::CanGc;
|
||||||
|
|
||||||
|
/// <https://drafts.csswg.org/css-font-loading/#FontFaceSet-interface>
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub(crate) struct FontFaceSet {
|
pub(crate) struct FontFaceSet {
|
||||||
target: EventTarget,
|
target: EventTarget,
|
||||||
|
|
||||||
|
/// <https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-readypromise-slot>
|
||||||
#[ignore_malloc_size_of = "Rc"]
|
#[ignore_malloc_size_of = "Rc"]
|
||||||
promise: Rc<Promise>,
|
promise: Rc<Promise>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontFaceSet {
|
impl FontFaceSet {
|
||||||
pub(crate) fn new_inherited(global: &GlobalScope, can_gc: CanGc) -> Self {
|
fn new_inherited(global: &GlobalScope, can_gc: CanGc) -> Self {
|
||||||
FontFaceSet {
|
FontFaceSet {
|
||||||
target: EventTarget::new_inherited(),
|
target: EventTarget::new_inherited(),
|
||||||
promise: Promise::new(global, can_gc),
|
promise: Promise::new(global, can_gc),
|
||||||
|
@ -44,9 +53,24 @@ impl FontFaceSet {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn handle_font_face_status_changed(&self, font_face: &FontFace) {
|
||||||
|
if font_face.loaded() {
|
||||||
|
let Some(window) = DomRoot::downcast::<Window>(self.global()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let (family_name, template) = font_face
|
||||||
|
.template()
|
||||||
|
.expect("A loaded web font should have a template");
|
||||||
|
window
|
||||||
|
.font_context()
|
||||||
|
.add_template_to_font_context(family_name, template);
|
||||||
|
window.Document().dirty_all_nodes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn fulfill_ready_promise_if_needed(&self) {
|
pub(crate) fn fulfill_ready_promise_if_needed(&self) {
|
||||||
if !self.promise.is_fulfilled() {
|
if !self.promise.is_fulfilled() {
|
||||||
let _ac = enter_realm(&*self.promise);
|
|
||||||
self.promise.resolve_native(self);
|
self.promise.resolve_native(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,4 +81,43 @@ impl FontFaceSetMethods<crate::DomTypeHolder> for FontFaceSet {
|
||||||
fn Ready(&self) -> Rc<Promise> {
|
fn Ready(&self) -> Rc<Promise> {
|
||||||
self.promise.clone()
|
self.promise.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-add>
|
||||||
|
fn Add(&self, font_face: &FontFace) -> DomRoot<FontFaceSet> {
|
||||||
|
font_face.set_associated_font_face_set(self);
|
||||||
|
self.handle_font_face_status_changed(font_face);
|
||||||
|
DomRoot::from_ref(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-load>
|
||||||
|
fn Load(&self, _font: DOMString, _text: DOMString, can_gc: CanGc) -> Rc<Promise> {
|
||||||
|
// Step 1. Let font face set be the FontFaceSet object this method was called on. Let
|
||||||
|
// promise be a newly-created promise object.
|
||||||
|
let promise = Promise::new(&self.global(), can_gc);
|
||||||
|
|
||||||
|
// TODO: Step 3. Find the matching font faces from font face set using the font and text
|
||||||
|
// arguments passed to the function, and let font face list be the return value (ignoring
|
||||||
|
// the found faces flag). If a syntax error was returned, reject promise with a SyntaxError
|
||||||
|
// exception and terminate these steps.
|
||||||
|
|
||||||
|
let trusted = TrustedPromise::new(promise.clone());
|
||||||
|
// Step 4. Queue a task to run the following steps synchronously:
|
||||||
|
self.global()
|
||||||
|
.task_manager()
|
||||||
|
.font_loading_task_source()
|
||||||
|
.queue(task!(resolve_font_face_set_load_task: move || {
|
||||||
|
let promise = trusted.root();
|
||||||
|
|
||||||
|
// TODO: Step 4.1. For all of the font faces in the font face list, call their load()
|
||||||
|
// method.
|
||||||
|
|
||||||
|
// TODO: Step 4.2. Resolve promise with the result of waiting for all of the
|
||||||
|
// [[FontStatusPromise]]s of each font face in the font face list, in order.
|
||||||
|
let matched_fonts = Vec::<&FontFace>::new();
|
||||||
|
promise.resolve_native(&matched_fonts);
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Step 2. Return promise. Complete the rest of these steps asynchronously.
|
||||||
|
promise
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,6 +321,7 @@ pub(crate) mod filelist;
|
||||||
pub(crate) mod filereader;
|
pub(crate) mod filereader;
|
||||||
pub(crate) mod filereadersync;
|
pub(crate) mod filereadersync;
|
||||||
pub(crate) mod focusevent;
|
pub(crate) mod focusevent;
|
||||||
|
pub(crate) mod fontface;
|
||||||
pub(crate) mod fontfaceset;
|
pub(crate) mod fontfaceset;
|
||||||
pub(crate) mod formdata;
|
pub(crate) mod formdata;
|
||||||
pub(crate) mod formdataevent;
|
pub(crate) mod formdataevent;
|
||||||
|
|
|
@ -634,6 +634,10 @@ impl Window {
|
||||||
) -> EventStatus {
|
) -> EventStatus {
|
||||||
event.dispatch(self.upcast(), true, can_gc)
|
event.dispatch(self.upcast(), true, can_gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn font_context(&self) -> &Arc<FontContext> {
|
||||||
|
&self.font_context
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#atob
|
// https://html.spec.whatwg.org/multipage/#atob
|
||||||
|
|
|
@ -73,7 +73,7 @@ pub(crate) fn submit_timing_data(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Listener: PreInvoke + Send + 'static> NetworkListener<Listener> {
|
impl<Listener: PreInvoke + Send + 'static> NetworkListener<Listener> {
|
||||||
pub(crate) fn notify<A: Action<Listener> + Send + 'static>(&self, action: A) {
|
pub(crate) fn notify<A: Action<Listener> + Send + 'static>(&mut self, action: A) {
|
||||||
self.task_source.queue(ListenerTask {
|
self.task_source.queue(ListenerTask {
|
||||||
context: self.context.clone(),
|
context: self.context.clone(),
|
||||||
action,
|
action,
|
||||||
|
@ -83,11 +83,11 @@ impl<Listener: PreInvoke + Send + 'static> NetworkListener<Listener> {
|
||||||
|
|
||||||
// helps type inference
|
// helps type inference
|
||||||
impl<Listener: FetchResponseListener + PreInvoke + Send + 'static> NetworkListener<Listener> {
|
impl<Listener: FetchResponseListener + PreInvoke + Send + 'static> NetworkListener<Listener> {
|
||||||
pub(crate) fn notify_fetch(&self, action: FetchResponseMsg) {
|
pub(crate) fn notify_fetch(&mut self, action: FetchResponseMsg) {
|
||||||
self.notify(action);
|
self.notify(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn into_callback(self) -> BoxedFetchCallback {
|
pub(crate) fn into_callback(mut self) -> BoxedFetchCallback {
|
||||||
Box::new(move |response_msg| self.notify_fetch(response_msg))
|
Box::new(move |response_msg| self.notify_fetch(response_msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ pub(crate) enum ScriptThreadEventCategory {
|
||||||
DevtoolsMsg,
|
DevtoolsMsg,
|
||||||
DocumentEvent,
|
DocumentEvent,
|
||||||
FileRead,
|
FileRead,
|
||||||
|
FontLoading,
|
||||||
FormPlannedNavigation,
|
FormPlannedNavigation,
|
||||||
HistoryEvent,
|
HistoryEvent,
|
||||||
ImageCacheMsg,
|
ImageCacheMsg,
|
||||||
|
@ -139,6 +140,7 @@ impl From<ScriptThreadEventCategory> for ProfilerCategory {
|
||||||
ScriptThreadEventCategory::EnterFullscreen => ProfilerCategory::ScriptEnterFullscreen,
|
ScriptThreadEventCategory::EnterFullscreen => ProfilerCategory::ScriptEnterFullscreen,
|
||||||
ScriptThreadEventCategory::ExitFullscreen => ProfilerCategory::ScriptExitFullscreen,
|
ScriptThreadEventCategory::ExitFullscreen => ProfilerCategory::ScriptExitFullscreen,
|
||||||
ScriptThreadEventCategory::FileRead => ProfilerCategory::ScriptFileRead,
|
ScriptThreadEventCategory::FileRead => ProfilerCategory::ScriptFileRead,
|
||||||
|
ScriptThreadEventCategory::FontLoading => ProfilerCategory::ScriptFontLoading,
|
||||||
ScriptThreadEventCategory::FormPlannedNavigation => {
|
ScriptThreadEventCategory::FormPlannedNavigation => {
|
||||||
ProfilerCategory::ScriptPlannedNavigation
|
ProfilerCategory::ScriptPlannedNavigation
|
||||||
},
|
},
|
||||||
|
@ -181,6 +183,7 @@ impl From<ScriptThreadEventCategory> for ScriptHangAnnotation {
|
||||||
ScriptThreadEventCategory::DocumentEvent => ScriptHangAnnotation::DocumentEvent,
|
ScriptThreadEventCategory::DocumentEvent => ScriptHangAnnotation::DocumentEvent,
|
||||||
ScriptThreadEventCategory::InputEvent => ScriptHangAnnotation::InputEvent,
|
ScriptThreadEventCategory::InputEvent => ScriptHangAnnotation::InputEvent,
|
||||||
ScriptThreadEventCategory::FileRead => ScriptHangAnnotation::FileRead,
|
ScriptThreadEventCategory::FileRead => ScriptHangAnnotation::FileRead,
|
||||||
|
ScriptThreadEventCategory::FontLoading => ScriptHangAnnotation::FontLoading,
|
||||||
ScriptThreadEventCategory::FormPlannedNavigation => {
|
ScriptThreadEventCategory::FormPlannedNavigation => {
|
||||||
ScriptHangAnnotation::FormPlannedNavigation
|
ScriptHangAnnotation::FormPlannedNavigation
|
||||||
},
|
},
|
||||||
|
|
|
@ -1614,6 +1614,9 @@ impl ScriptThread {
|
||||||
ScriptThreadEventCategory::FileRead => {
|
ScriptThreadEventCategory::FileRead => {
|
||||||
time_profile!(ProfilerCategory::ScriptFileRead, None, profiler_chan, f)
|
time_profile!(ProfilerCategory::ScriptFileRead, None, profiler_chan, f)
|
||||||
},
|
},
|
||||||
|
ScriptThreadEventCategory::FontLoading => {
|
||||||
|
time_profile!(ProfilerCategory::ScriptFontLoading, None, profiler_chan, f)
|
||||||
|
},
|
||||||
ScriptThreadEventCategory::FormPlannedNavigation => time_profile!(
|
ScriptThreadEventCategory::FormPlannedNavigation => time_profile!(
|
||||||
ProfilerCategory::ScriptPlannedNavigation,
|
ProfilerCategory::ScriptPlannedNavigation,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -134,6 +134,7 @@ impl TaskManager {
|
||||||
task_source_functions!(self, canvas_blob_task_source, Canvas);
|
task_source_functions!(self, canvas_blob_task_source, Canvas);
|
||||||
task_source_functions!(self, dom_manipulation_task_source, DOMManipulation);
|
task_source_functions!(self, dom_manipulation_task_source, DOMManipulation);
|
||||||
task_source_functions!(self, file_reading_task_source, FileReading);
|
task_source_functions!(self, file_reading_task_source, FileReading);
|
||||||
|
task_source_functions!(self, font_loading_task_source, FontLoading);
|
||||||
task_source_functions!(self, gamepad_task_source, Gamepad);
|
task_source_functions!(self, gamepad_task_source, Gamepad);
|
||||||
task_source_functions!(self, media_element_task_source, MediaElement);
|
task_source_functions!(self, media_element_task_source, MediaElement);
|
||||||
task_source_functions!(self, networking_task_source, Networking);
|
task_source_functions!(self, networking_task_source, Networking);
|
||||||
|
|
|
@ -27,6 +27,8 @@ pub(crate) enum TaskSourceName {
|
||||||
Canvas,
|
Canvas,
|
||||||
DOMManipulation,
|
DOMManipulation,
|
||||||
FileReading,
|
FileReading,
|
||||||
|
/// <https://drafts.csswg.org/css-font-loading/#task-source>
|
||||||
|
FontLoading,
|
||||||
HistoryTraversal,
|
HistoryTraversal,
|
||||||
Networking,
|
Networking,
|
||||||
PerformanceTimeline,
|
PerformanceTimeline,
|
||||||
|
@ -48,6 +50,7 @@ impl From<TaskSourceName> for ScriptThreadEventCategory {
|
||||||
TaskSourceName::Canvas => ScriptThreadEventCategory::ScriptEvent,
|
TaskSourceName::Canvas => ScriptThreadEventCategory::ScriptEvent,
|
||||||
TaskSourceName::DOMManipulation => ScriptThreadEventCategory::ScriptEvent,
|
TaskSourceName::DOMManipulation => ScriptThreadEventCategory::ScriptEvent,
|
||||||
TaskSourceName::FileReading => ScriptThreadEventCategory::FileRead,
|
TaskSourceName::FileReading => ScriptThreadEventCategory::FileRead,
|
||||||
|
TaskSourceName::FontLoading => ScriptThreadEventCategory::FontLoading,
|
||||||
TaskSourceName::HistoryTraversal => ScriptThreadEventCategory::HistoryEvent,
|
TaskSourceName::HistoryTraversal => ScriptThreadEventCategory::HistoryEvent,
|
||||||
TaskSourceName::Networking => ScriptThreadEventCategory::NetworkEvent,
|
TaskSourceName::Networking => ScriptThreadEventCategory::NetworkEvent,
|
||||||
TaskSourceName::PerformanceTimeline => {
|
TaskSourceName::PerformanceTimeline => {
|
||||||
|
@ -71,6 +74,7 @@ impl TaskSourceName {
|
||||||
TaskSourceName::Canvas,
|
TaskSourceName::Canvas,
|
||||||
TaskSourceName::DOMManipulation,
|
TaskSourceName::DOMManipulation,
|
||||||
TaskSourceName::FileReading,
|
TaskSourceName::FileReading,
|
||||||
|
TaskSourceName::FontLoading,
|
||||||
TaskSourceName::HistoryTraversal,
|
TaskSourceName::HistoryTraversal,
|
||||||
TaskSourceName::Networking,
|
TaskSourceName::Networking,
|
||||||
TaskSourceName::PerformanceTimeline,
|
TaskSourceName::PerformanceTimeline,
|
||||||
|
|
|
@ -175,6 +175,10 @@ DOMInterfaces = {
|
||||||
'canGc': ['Abort'],
|
'canGc': ['Abort'],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'FontFaceSet': {
|
||||||
|
'canGc': ['Load'],
|
||||||
|
},
|
||||||
|
|
||||||
'GamepadHapticActuator': {
|
'GamepadHapticActuator': {
|
||||||
'inRealms': ['PlayEffect', 'Reset'],
|
'inRealms': ['PlayEffect', 'Reset'],
|
||||||
'canGc': ['PlayEffect', 'Reset'],
|
'canGc': ['PlayEffect', 'Reset'],
|
||||||
|
@ -577,6 +581,10 @@ DOMInterfaces = {
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionaries = {
|
Dictionaries = {
|
||||||
|
'FontFaceDescriptors': {
|
||||||
|
'derives': ['Clone', 'MallocSizeOf']
|
||||||
|
},
|
||||||
|
|
||||||
'GPUCanvasConfiguration': {
|
'GPUCanvasConfiguration': {
|
||||||
'derives': ['Clone']
|
'derives': ['Clone']
|
||||||
},
|
},
|
||||||
|
|
54
components/script_bindings/webidls/FontFace.webidl
Normal file
54
components/script_bindings/webidls/FontFace.webidl
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
typedef DOMString CSSOMString;
|
||||||
|
|
||||||
|
dictionary FontFaceDescriptors {
|
||||||
|
CSSOMString style = "normal";
|
||||||
|
CSSOMString weight = "normal";
|
||||||
|
CSSOMString stretch = "normal";
|
||||||
|
CSSOMString unicodeRange = "U+0-10FFFF";
|
||||||
|
CSSOMString featureSettings = "normal";
|
||||||
|
CSSOMString variationSettings = "normal";
|
||||||
|
CSSOMString display = "auto";
|
||||||
|
CSSOMString ascentOverride = "normal";
|
||||||
|
CSSOMString descentOverride = "normal";
|
||||||
|
CSSOMString lineGapOverride = "normal";
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FontFaceLoadStatus { "unloaded", "loading", "loaded", "error" };
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/css-font-loading/#fontface-interface
|
||||||
|
[Exposed=(Window /*, Worker */), Pref="dom_fontface_enabled"] // TODO: Add support for FontFace in Workers.
|
||||||
|
interface FontFace {
|
||||||
|
constructor(CSSOMString family, (CSSOMString or BufferSource) source,
|
||||||
|
optional FontFaceDescriptors descriptors = {});
|
||||||
|
[SetterThrows]
|
||||||
|
attribute CSSOMString family;
|
||||||
|
[SetterThrows]
|
||||||
|
attribute CSSOMString style;
|
||||||
|
[SetterThrows]
|
||||||
|
attribute CSSOMString weight;
|
||||||
|
[SetterThrows]
|
||||||
|
attribute CSSOMString stretch;
|
||||||
|
[SetterThrows]
|
||||||
|
attribute CSSOMString unicodeRange;
|
||||||
|
[SetterThrows]
|
||||||
|
attribute CSSOMString featureSettings;
|
||||||
|
[SetterThrows]
|
||||||
|
attribute CSSOMString variationSettings;
|
||||||
|
[SetterThrows]
|
||||||
|
attribute CSSOMString display;
|
||||||
|
[SetterThrows]
|
||||||
|
attribute CSSOMString ascentOverride;
|
||||||
|
[SetterThrows]
|
||||||
|
attribute CSSOMString descentOverride;
|
||||||
|
[SetterThrows]
|
||||||
|
attribute CSSOMString lineGapOverride;
|
||||||
|
|
||||||
|
readonly attribute FontFaceLoadStatus status;
|
||||||
|
|
||||||
|
Promise<FontFace> load();
|
||||||
|
readonly attribute Promise<FontFace> loaded;
|
||||||
|
};
|
|
@ -19,12 +19,13 @@ enum FontFaceSetLoadStatus { "loading" , "loaded" };
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-font-loading/#FontFaceSet-interface
|
// https://drafts.csswg.org/css-font-loading/#FontFaceSet-interface
|
||||||
[Exposed=(Window,Worker)]
|
[Exposed=(Window /*, Worker */)]
|
||||||
interface FontFaceSet : EventTarget {
|
interface FontFaceSet : EventTarget {
|
||||||
// constructor(sequence<FontFace> initialFaces);
|
// constructor(sequence<FontFace> initialFaces);
|
||||||
|
|
||||||
// setlike<FontFace>;
|
// setlike<FontFace>;
|
||||||
// FontFaceSet add(FontFace font);
|
[Pref="dom_fontface_enabled"]
|
||||||
|
FontFaceSet add(FontFace font);
|
||||||
// boolean delete(FontFace font);
|
// boolean delete(FontFace font);
|
||||||
// undefined clear();
|
// undefined clear();
|
||||||
|
|
||||||
|
@ -35,7 +36,8 @@ interface FontFaceSet : EventTarget {
|
||||||
|
|
||||||
// check and start loads if appropriate
|
// check and start loads if appropriate
|
||||||
// and fulfill promise when all loads complete
|
// and fulfill promise when all loads complete
|
||||||
// Promise<sequence<FontFace>> load(DOMString font, optional DOMString text = " ");
|
[Pref="dom_fontface_enabled"]
|
||||||
|
Promise<sequence<FontFace>> load(DOMString font, optional DOMString text = " ");
|
||||||
|
|
||||||
// return whether all fonts in the fontlist are loaded
|
// return whether all fonts in the fontlist are loaded
|
||||||
// (does not initiate load if not available)
|
// (does not initiate load if not available)
|
||||||
|
|
|
@ -21,6 +21,7 @@ pub enum ScriptHangAnnotation {
|
||||||
DevtoolsMsg,
|
DevtoolsMsg,
|
||||||
DocumentEvent,
|
DocumentEvent,
|
||||||
FileRead,
|
FileRead,
|
||||||
|
FontLoading,
|
||||||
FormPlannedNavigation,
|
FormPlannedNavigation,
|
||||||
ImageCacheMsg,
|
ImageCacheMsg,
|
||||||
InputEvent,
|
InputEvent,
|
||||||
|
|
|
@ -17,4 +17,4 @@ int_range_index! {
|
||||||
struct ByteIndex(isize)
|
struct ByteIndex(isize)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type WebFontLoadFinishedCallback = Arc<dyn Fn(bool) + Send + Sync + 'static>;
|
pub type StylesheetWebFontLoadFinishedCallback = Arc<dyn Fn(bool) + Send + Sync + 'static>;
|
||||||
|
|
|
@ -524,7 +524,7 @@ enum ToFetchThreadMessage {
|
||||||
FetchResponse(FetchResponseMsg),
|
FetchResponse(FetchResponseMsg),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type BoxedFetchCallback = Box<dyn Fn(FetchResponseMsg) + Send + 'static>;
|
pub type BoxedFetchCallback = Box<dyn FnMut(FetchResponseMsg) + Send + 'static>;
|
||||||
|
|
||||||
/// A thread to handle fetches in a Servo process. This thread is responsible for
|
/// A thread to handle fetches in a Servo process. This thread is responsible for
|
||||||
/// listening for new fetch requests as well as updates on those operations and forwarding
|
/// listening for new fetch requests as well as updates on those operations and forwarding
|
||||||
|
@ -601,7 +601,7 @@ impl FetchThread {
|
||||||
matches!(fetch_response_msg, FetchResponseMsg::ProcessResponseEOF(..));
|
matches!(fetch_response_msg, FetchResponseMsg::ProcessResponseEOF(..));
|
||||||
|
|
||||||
self.active_fetches
|
self.active_fetches
|
||||||
.get(&request_id)
|
.get_mut(&request_id)
|
||||||
.expect("Got fetch response for unknown fetch")(
|
.expect("Got fetch response for unknown fetch")(
|
||||||
fetch_response_msg
|
fetch_response_msg
|
||||||
);
|
);
|
||||||
|
|
|
@ -90,43 +90,44 @@ pub enum ProfilerCategory {
|
||||||
|
|
||||||
ScriptEvent = 0x66,
|
ScriptEvent = 0x66,
|
||||||
ScriptFileRead = 0x67,
|
ScriptFileRead = 0x67,
|
||||||
ScriptImageCacheMsg = 0x68,
|
ScriptFontLoading = 0x68,
|
||||||
ScriptInputEvent = 0x69,
|
ScriptImageCacheMsg = 0x69,
|
||||||
ScriptNetworkEvent = 0x6a,
|
ScriptInputEvent = 0x6a,
|
||||||
|
ScriptNetworkEvent = 0x6b,
|
||||||
|
|
||||||
/// The script thread is parsing HTML, rather than doing other work like evaluating scripts or doing layout.
|
/// The script thread is parsing HTML, rather than doing other work like evaluating scripts or doing layout.
|
||||||
ScriptParseHTML = 0x6b,
|
ScriptParseHTML = 0x6c,
|
||||||
|
|
||||||
ScriptPlannedNavigation = 0x6c,
|
ScriptPlannedNavigation = 0x6d,
|
||||||
ScriptResize = 0x6d,
|
ScriptResize = 0x6e,
|
||||||
ScriptRendering = 0x6e,
|
ScriptRendering = 0x6f,
|
||||||
ScriptSetScrollState = 0x6f,
|
ScriptSetScrollState = 0x70,
|
||||||
ScriptSetViewport = 0x70,
|
ScriptSetViewport = 0x71,
|
||||||
ScriptTimerEvent = 0x71,
|
ScriptTimerEvent = 0x72,
|
||||||
ScriptStylesheetLoad = 0x72,
|
ScriptStylesheetLoad = 0x73,
|
||||||
ScriptUpdateReplacedElement = 0x73,
|
ScriptUpdateReplacedElement = 0x74,
|
||||||
ScriptWebSocketEvent = 0x74,
|
ScriptWebSocketEvent = 0x75,
|
||||||
ScriptWorkerEvent = 0x75,
|
ScriptWorkerEvent = 0x76,
|
||||||
ScriptServiceWorkerEvent = 0x76,
|
ScriptServiceWorkerEvent = 0x77,
|
||||||
|
|
||||||
/// The script thread is parsing XML, rather than doing other work like evaluating scripts or doing layout.
|
/// The script thread is parsing XML, rather than doing other work like evaluating scripts or doing layout.
|
||||||
ScriptParseXML = 0x77,
|
ScriptParseXML = 0x78,
|
||||||
|
|
||||||
ScriptEnterFullscreen = 0x78,
|
ScriptEnterFullscreen = 0x79,
|
||||||
ScriptExitFullscreen = 0x79,
|
ScriptExitFullscreen = 0x7a,
|
||||||
ScriptWorkletEvent = 0x7a,
|
ScriptWorkletEvent = 0x7b,
|
||||||
ScriptPerformanceEvent = 0x7b,
|
ScriptPerformanceEvent = 0x7c,
|
||||||
ScriptHistoryEvent = 0x7c,
|
ScriptHistoryEvent = 0x7d,
|
||||||
ScriptPortMessage = 0x7d,
|
ScriptPortMessage = 0x7e,
|
||||||
ScriptWebGPUMsg = 0x7e,
|
ScriptWebGPUMsg = 0x7f,
|
||||||
|
|
||||||
/// Web performance metrics.
|
/// Web performance metrics.
|
||||||
TimeToFirstPaint = 0x80,
|
TimeToFirstPaint = 0x90,
|
||||||
TimeToFirstContentfulPaint = 0x81,
|
TimeToFirstContentfulPaint = 0x91,
|
||||||
TimeToInteractive = 0x82,
|
TimeToInteractive = 0x92,
|
||||||
|
|
||||||
IpcReceiver = 0x83,
|
IpcReceiver = 0x93,
|
||||||
IpcBytesReceiver = 0x84,
|
IpcBytesReceiver = 0x94,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProfilerCategory {
|
impl ProfilerCategory {
|
||||||
|
@ -151,6 +152,7 @@ impl ProfilerCategory {
|
||||||
ProfilerCategory::ScriptEvaluate => "ScriptEvaluate",
|
ProfilerCategory::ScriptEvaluate => "ScriptEvaluate",
|
||||||
ProfilerCategory::ScriptEvent => "ScriptEvent",
|
ProfilerCategory::ScriptEvent => "ScriptEvent",
|
||||||
ProfilerCategory::ScriptFileRead => "ScriptFileRead",
|
ProfilerCategory::ScriptFileRead => "ScriptFileRead",
|
||||||
|
ProfilerCategory::ScriptFontLoading => "ScriptFontLoading",
|
||||||
ProfilerCategory::ScriptImageCacheMsg => "ScriptImageCacheMsg",
|
ProfilerCategory::ScriptImageCacheMsg => "ScriptImageCacheMsg",
|
||||||
ProfilerCategory::ScriptInputEvent => "ScriptInputEvent",
|
ProfilerCategory::ScriptInputEvent => "ScriptInputEvent",
|
||||||
ProfilerCategory::ScriptNetworkEvent => "ScriptNetworkEvent",
|
ProfilerCategory::ScriptNetworkEvent => "ScriptNetworkEvent",
|
||||||
|
|
2
tests/wpt/meta/__dir__.ini
vendored
2
tests/wpt/meta/__dir__.ini
vendored
|
@ -1 +1 @@
|
||||||
prefs: ["dom_imagebitmap_enabled:true", "dom_offscreen_canvas_enabled:true", "dom_shadowdom_enabled:true", "dom_xpath_enabled:true", "dom_intersection_observer_enabled:true", "dom_resize_observer_enabled:true", "dom_notification_enabled:true"]
|
prefs: ["dom_imagebitmap_enabled:true", "dom_offscreen_canvas_enabled:true", "dom_shadowdom_enabled:true", "dom_xpath_enabled:true", "dom_intersection_observer_enabled:true", "dom_resize_observer_enabled:true", "dom_notification_enabled:true", "dom_fontface_enabled:true"]
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[layer-cssom-order-reverse.html]
|
[layer-cssom-order-reverse.html]
|
||||||
[Insert layer invalidates @font-face]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Delete layer invalidates @font-face]
|
[Delete layer invalidates @font-face]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
[layer-font-face-override.html]
|
[layer-font-face-override.html]
|
||||||
|
bug: https://github.com/servo/servo/issues/35520
|
||||||
|
|
||||||
[@font-face unlayered overrides layered]
|
[@font-face unlayered overrides layered]
|
||||||
expected: FAIL
|
expected: [FAIL, PASS]
|
||||||
|
|
||||||
[@font-face override between layers]
|
[@font-face override between layers]
|
||||||
expected: FAIL
|
expected: [FAIL, PASS]
|
||||||
|
|
||||||
[@font-face override update with appended sheet 1]
|
[@font-face override update with appended sheet 1]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
[fallback-remote-to-data-url.html]
|
[fallback-remote-to-data-url.html]
|
||||||
expected: ERROR
|
[We should use the inline custom font to render the page when the primary remote font is loading]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
[font-display-change.html]
|
[font-display-change.html]
|
||||||
expected: TIMEOUT
|
bug: https://github.com/servo/servo/issues/35521
|
||||||
|
expected: [FAIL, TIMEOUT, PASS]
|
||||||
|
|
|
@ -1,16 +1,4 @@
|
||||||
[format-specifiers-variations.html]
|
[format-specifiers-variations.html]
|
||||||
[Load Ahem with format woff]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Load Ahem with format truetype]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Load Ahem with format opentype]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Load Ahem with format woff2]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Load Ahem with format woff-variations]
|
[Load Ahem with format woff-variations]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -22,123 +10,3 @@
|
||||||
|
|
||||||
[Load Ahem with format woff2-variations]
|
[Load Ahem with format woff2-variations]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Do not load Ahem with format xyzwoff]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format xyztruetype]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format xyzopentype]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format xyzwoff2]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format xyzwoff-variations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format xyztruetype-variations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format xyzopentype-variations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format xyzwoff2-variations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format woffxyz]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format truetypexyz]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format opentypexyz]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format woff2xyz]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format woff-variationsxyz]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format truetype-variationsxyz]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format opentype-variationsxyz]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format woff2-variationsxyz]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format wo]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format truety]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format openty]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format wof]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format woff-variatio]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format truetype-variatio]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format opentype-variatio]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format woff2-variatio]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format ff]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format uetype]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format entype]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format ff2]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format ff-variations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format uetype-variations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format entype-variations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format ff2-variations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format wff]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format tretype]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format opntype]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format wff2]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format woff-ariations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format truetye-variations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format opentye-variations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Do not load Ahem with format woff2variations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -38,5 +38,20 @@
|
||||||
[Property font-size-adjust value 'ic-height from-font']
|
[Property font-size-adjust value 'ic-height from-font']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CSS Fonts Module Level 5: getComputedStyle().fontSizeAdjust]
|
[Property font-size-adjust value 'calc(0.5)']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Property font-size-adjust value 'ex-height calc(0.5)']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Property font-size-adjust value 'cap-height calc(0.5)']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Property font-size-adjust value 'cap-height calc(0.5 + 1)']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Property font-size-adjust value 'cap-height calc(-0.5)']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Property font-size-adjust value 'cap-height calc(10 + (sign(20cqw - 10px) * 5))']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
|
@ -1,156 +0,0 @@
|
||||||
[font-parse-numeric-stretch-style-weight.html]
|
|
||||||
[Valid value 100 matches 100 for weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 700 matches 700 for weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 900 matches 900 for weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value bold matches bold for weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value normal matches normal for weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 100 400 matches 100 400 for weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 100 101.5 matches 100 101.5 for weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 999.8 999.9 matches 999.8 999.9 for weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 500 400 matches 500 400 for weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 0% matches 0% for stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value calc(0% - 10%) matches calc(-10%) for stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 100% matches 100% for stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 110% matches 110% for stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 111.5% matches 111.5% for stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 50% 200% matches 50% 200% for stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 0.1% 1% matches 0.1% 1% for stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value 900% 901% matches 900% 901% for stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value ultra-condensed matches ultra-condensed for stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value ultra-expanded matches ultra-expanded for stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value normal matches normal for style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value italic matches italic for style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value oblique matches oblique for style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value oblique 10deg matches oblique 10deg for style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Valid value oblique 10deg 20deg matches oblique 10deg 20deg for style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value 0 must not be accepted as weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value 0.9 must not be accepted as weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value -100 200 must not be accepted as weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value 100 -200 must not be accepted as weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value 100 1001 must not be accepted as weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value 1001 must not be accepted as weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value 1000.5 must not be accepted as weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value 100 200 300 must not be accepted as weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value a must not be accepted as weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value a b c must not be accepted as weight in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value -0.5% must not be accepted as stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value -1% must not be accepted as stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value 60% 70% 80% must not be accepted as stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value a% must not be accepted as stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value a b c must not be accepted as stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value 0.1 must not be accepted as stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value -60% 80% must not be accepted as stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value ultra-expannnned must not be accepted as stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value 50% 0 must not be accepted as stretch in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value oblique 100deg must not be accepted as style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value oblique italic must not be accepted as style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value oblique -91deg must not be accepted as style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value oblique 0 must not be accepted as style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value oblique 10 must not be accepted as style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value iiitalic must not be accepted as style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value 90deg must not be accepted as style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value 11 must not be accepted as style in @font-face.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Value italic 90deg must not be accepted as style in @font-face.]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +1,2 @@
|
||||||
[clip-path-svg-text-font-loading.html]
|
[clip-path-svg-text-font-loading.html]
|
||||||
expected: TIMEOUT
|
expected: FAIL
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
[ch-empty-pseudo-recalc-on-font-load.html]
|
[ch-empty-pseudo-recalc-on-font-load.html]
|
||||||
expected: ERROR
|
|
||||||
[ch in pseudo-element ::before should be recalculated after loading a web font]
|
[ch in pseudo-element ::before should be recalculated after loading a web font]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
[ch-pseudo-recalc-on-font-load.html]
|
[ch-pseudo-recalc-on-font-load.html]
|
||||||
expected: ERROR
|
|
||||||
[ch in pseudo-element ::before should be recalculated after loading a web font]
|
[ch in pseudo-element ::before should be recalculated after loading a web font]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
[ch-recalc-on-font-load.html]
|
|
||||||
expected: ERROR
|
|
||||||
[ch in a normal div should be recalculated after loading a web font]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[ch in display:contents should be recalculated after loading a web font]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
||||||
[ch in display:none should be recalculated after loading a web font]
|
|
||||||
expected: TIMEOUT
|
|
|
@ -1,4 +0,0 @@
|
||||||
[2d.text.draw.fill.maxWidth.fontface.html]
|
|
||||||
[fillText works on @font-face fonts]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[2d.text.measure.width.empty.html]
|
[2d.text.measure.width.empty.html]
|
||||||
[The empty string has zero width for OffscreenCanvas]
|
[The empty string has zero width for OffscreenCanvas]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[The empty string has zero width]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.condensed.html.ini
vendored
Normal file
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.condensed.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[canvas.2d.fontStretch.condensed.html]
|
||||||
|
expected: FAIL
|
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.expanded.html.ini
vendored
Normal file
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.expanded.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[canvas.2d.fontStretch.expanded.html]
|
||||||
|
expected: FAIL
|
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.extra-condensed.html.ini
vendored
Normal file
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.extra-condensed.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[canvas.2d.fontStretch.extra-condensed.html]
|
||||||
|
expected: FAIL
|
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.extra-expanded.html.ini
vendored
Normal file
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.extra-expanded.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[canvas.2d.fontStretch.extra-expanded.html]
|
||||||
|
expected: FAIL
|
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.normal.html.ini
vendored
Normal file
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.normal.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[canvas.2d.fontStretch.normal.html]
|
||||||
|
expected: FAIL
|
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.semi-condensed.html.ini
vendored
Normal file
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.semi-condensed.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[canvas.2d.fontStretch.semi-condensed.html]
|
||||||
|
expected: FAIL
|
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.semi-expanded.html.ini
vendored
Normal file
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.semi-expanded.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[canvas.2d.fontStretch.semi-expanded.html]
|
||||||
|
expected: FAIL
|
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.ultra-condensed.html.ini
vendored
Normal file
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.ultra-condensed.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[canvas.2d.fontStretch.ultra-condensed.html]
|
||||||
|
expected: FAIL
|
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.ultra-expanded.html.ini
vendored
Normal file
2
tests/wpt/meta/html/canvas/offscreen/text/canvas.2d.fontStretch.ultra-expanded.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[canvas.2d.fontStretch.ultra-expanded.html]
|
||||||
|
expected: FAIL
|
3
tests/wpt/meta/webidl/current-realm.html.ini
vendored
3
tests/wpt/meta/webidl/current-realm.html.ini
vendored
|
@ -4,6 +4,3 @@
|
||||||
|
|
||||||
[getImageData]
|
[getImageData]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[FontFace's load()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
2
tests/wpt/mozilla/meta/MANIFEST.json
vendored
2
tests/wpt/mozilla/meta/MANIFEST.json
vendored
|
@ -13513,7 +13513,7 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"interfaces.worker.js": [
|
"interfaces.worker.js": [
|
||||||
"fc621bbafeec167942f802caae43b9f2ef23b29b",
|
"f708bfb25594a239be31671e9fd15d6771309a12",
|
||||||
[
|
[
|
||||||
"mozilla/interfaces.worker.html",
|
"mozilla/interfaces.worker.html",
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -34,7 +34,6 @@ test_interfaces([
|
||||||
"FileReader",
|
"FileReader",
|
||||||
"FileReaderSync",
|
"FileReaderSync",
|
||||||
"FinalizationRegistry",
|
"FinalizationRegistry",
|
||||||
"FontFaceSet",
|
|
||||||
"FormData",
|
"FormData",
|
||||||
"Headers",
|
"Headers",
|
||||||
"History",
|
"History",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue