mirror of
https://github.com/servo/servo.git
synced 2025-07-29 10:10:34 +01:00
Move Stylesheet loading and ownership from the layout task into HTML elements Stylesheets for `HTMLLinkElement`s are now loaded by the resource task, triggered by the element in question. Stylesheets are owned by the elements they're associated with, which can be `HTMLStyleElement`, `HTMLLinkElement`, and `HTMLMetaElement` (for `<meta name="viewport">). Additionally, the quirks mode stylesheet (just as the user and user agent stylesheets a couple of commits ago), is implemented as a lazy static, loaded once per process and shared between all documents. This all has various nice consequences: - Stylesheet loading becomes a non-blocking operation. - Stylesheets are removed when the element they're associated with is removed from the document. - It'll be possible to implement the CSSOM APIs that require direct access to the stylesheets (i.e., ~ all of them). - Various subtle correctness issues are fixed. One piece of interesting follow-up work would be to move parsing of external stylesheets to the resource task, too. Right now, it happens in the link element once loading is complete, so blocks the script task. Moving it to the resource task would probably be fairly straight-forward as it doesn't require access to any external state. Depends on #7979 because without that loading stylesheets asynchronously breaks lots of content. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8039) <!-- Reviewable:end -->
132 lines
4.1 KiB
Rust
132 lines
4.1 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
use computed_values::font_family::FontFamily;
|
|
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
|
|
use parser::{ParserContext, log_css_error};
|
|
use properties::longhands::font_family::parse_one_family;
|
|
use std::ascii::AsciiExt;
|
|
use string_cache::Atom;
|
|
use url::{Url, UrlParser};
|
|
use util::mem::HeapSizeOf;
|
|
|
|
#[derive(Clone, Debug, HeapSizeOf, PartialEq, Eq, Deserialize, Serialize)]
|
|
pub enum Source {
|
|
Url(UrlSource),
|
|
Local(Atom),
|
|
}
|
|
|
|
#[derive(Clone, Debug, HeapSizeOf, PartialEq, Eq, Deserialize, Serialize)]
|
|
pub struct UrlSource {
|
|
pub url: Url,
|
|
pub format_hints: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, HeapSizeOf, PartialEq, Eq)]
|
|
pub struct FontFaceRule {
|
|
pub family: Atom,
|
|
pub sources: Vec<Source>,
|
|
}
|
|
|
|
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser)
|
|
-> Result<FontFaceRule, ()> {
|
|
let mut family = None;
|
|
let mut src = None;
|
|
let mut iter = DeclarationListParser::new(input, FontFaceRuleParser { context: context });
|
|
while let Some(declaration) = iter.next() {
|
|
match declaration {
|
|
Err(range) => {
|
|
let pos = range.start;
|
|
let message = format!("Unsupported @font-face descriptor declaration: '{}'",
|
|
iter.input.slice(range));
|
|
log_css_error(iter.input, pos, &*message);
|
|
}
|
|
Ok(FontFaceDescriptorDeclaration::Family(value)) => {
|
|
family = Some(value);
|
|
}
|
|
Ok(FontFaceDescriptorDeclaration::Src(value)) => {
|
|
src = Some(value);
|
|
}
|
|
}
|
|
}
|
|
match (family, src) {
|
|
(Some(family), Some(src)) => {
|
|
Ok(FontFaceRule {
|
|
family: family,
|
|
sources: src,
|
|
})
|
|
}
|
|
_ => Err(())
|
|
}
|
|
}
|
|
|
|
enum FontFaceDescriptorDeclaration {
|
|
Family(Atom),
|
|
Src(Vec<Source>),
|
|
}
|
|
|
|
|
|
struct FontFaceRuleParser<'a, 'b: 'a> {
|
|
context: &'a ParserContext<'b>,
|
|
}
|
|
|
|
|
|
/// Default methods reject all at rules.
|
|
impl<'a, 'b> AtRuleParser for FontFaceRuleParser<'a, 'b> {
|
|
type Prelude = ();
|
|
type AtRule = FontFaceDescriptorDeclaration;
|
|
}
|
|
|
|
|
|
impl<'a, 'b> DeclarationParser for FontFaceRuleParser<'a, 'b> {
|
|
type Declaration = FontFaceDescriptorDeclaration;
|
|
|
|
fn parse_value(&self, name: &str, input: &mut Parser) -> Result<FontFaceDescriptorDeclaration, ()> {
|
|
match_ignore_ascii_case! { name,
|
|
"font-family" => {
|
|
Ok(FontFaceDescriptorDeclaration::Family(try!(
|
|
parse_one_non_generic_family_name(input))))
|
|
},
|
|
"src" => {
|
|
Ok(FontFaceDescriptorDeclaration::Src(try!(input.parse_comma_separated(|input| {
|
|
parse_one_src(self.context, input)
|
|
}))))
|
|
}
|
|
_ => Err(())
|
|
}
|
|
}
|
|
}
|
|
|
|
fn parse_one_non_generic_family_name(input: &mut Parser) -> Result<Atom, ()> {
|
|
match parse_one_family(input) {
|
|
Ok(FontFamily::FamilyName(name)) => Ok(name.clone()),
|
|
_ => Err(())
|
|
}
|
|
}
|
|
|
|
|
|
fn parse_one_src(context: &ParserContext, input: &mut Parser) -> Result<Source, ()> {
|
|
if input.try(|input| input.expect_function_matching("local")).is_ok() {
|
|
return Ok(Source::Local(try!(input.parse_nested_block(parse_one_non_generic_family_name))))
|
|
}
|
|
let url = try!(input.expect_url());
|
|
let url = UrlParser::new().base_url(context.base_url).parse(&url).unwrap_or_else(
|
|
|_error| Url::parse("about:invalid").unwrap());
|
|
|
|
// Parsing optional format()
|
|
let format_hints = if input.try(|input| input.expect_function_matching("format")).is_ok() {
|
|
try!(input.parse_nested_block(|input| {
|
|
input.parse_comma_separated(|input| {
|
|
Ok((try!(input.expect_string())).into_owned())
|
|
})
|
|
}))
|
|
} else {
|
|
vec![]
|
|
};
|
|
|
|
Ok(Source::Url(UrlSource {
|
|
url: url,
|
|
format_hints: format_hints,
|
|
}))
|
|
}
|