mirror of
https://github.com/servo/servo.git
synced 2025-06-18 13:24:29 +00:00
Fix #2802: fix parsing of font-family in @font-face
This commit is contained in:
parent
639a6c51bf
commit
0945bd9fb4
3 changed files with 91 additions and 56 deletions
|
@ -6,7 +6,7 @@ use cssparser::ast::*;
|
||||||
use cssparser::parse_declaration_list;
|
use cssparser::parse_declaration_list;
|
||||||
use errors::{ErrorLoggerIterator, log_css_error};
|
use errors::{ErrorLoggerIterator, log_css_error};
|
||||||
use std::ascii::StrAsciiExt;
|
use std::ascii::StrAsciiExt;
|
||||||
use parsing_utils::one_component_value;
|
use parsing_utils::BufferedIter;
|
||||||
use stylesheets::{CSSRule, CSSFontFaceRule};
|
use stylesheets::{CSSRule, CSSFontFaceRule};
|
||||||
use url::{Url, UrlParser};
|
use url::{Url, UrlParser};
|
||||||
|
|
||||||
|
@ -59,14 +59,13 @@ pub fn parse_font_face_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, base_
|
||||||
let name_lower = name.as_slice().to_ascii_lower();
|
let name_lower = name.as_slice().to_ascii_lower();
|
||||||
match name_lower.as_slice() {
|
match name_lower.as_slice() {
|
||||||
"font-family" => {
|
"font-family" => {
|
||||||
// FIXME(#2802): Share code with the font-family parser.
|
let iter = &mut BufferedIter::new(value.as_slice().skip_whitespace());
|
||||||
match one_component_value(value.as_slice()) {
|
match ::properties::longhands::font_family::parse_one_family(iter) {
|
||||||
Ok(&String(ref string_value)) => {
|
Ok(::properties::computed_values::font_family::FamilyName(name)) => {
|
||||||
maybe_family = Some(string_value.clone());
|
maybe_family = Some(name);
|
||||||
},
|
},
|
||||||
_ => {
|
// This also includes generic family names:
|
||||||
log_css_error(location, format!("Unsupported font-family string {:s}", name).as_slice());
|
_ => log_css_error(location, "Invalid font-family in @font-face"),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"src" => {
|
"src" => {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
|
|
||||||
use std::ascii::StrAsciiExt;
|
use std::ascii::StrAsciiExt;
|
||||||
use cssparser::ast::{ComponentValue, Ident, SkipWhitespaceIterable};
|
use cssparser::ast::{ComponentValue, Ident, SkipWhitespaceIterable, SkipWhitespaceIterator};
|
||||||
|
|
||||||
|
|
||||||
pub fn one_component_value<'a>(input: &'a [ComponentValue]) -> Result<&'a ComponentValue, ()> {
|
pub fn one_component_value<'a>(input: &'a [ComponentValue]) -> Result<&'a ComponentValue, ()> {
|
||||||
|
@ -22,3 +22,39 @@ pub fn get_ident_lower(component_value: &ComponentValue) -> Result<String, ()> {
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct BufferedIter<E, I> {
|
||||||
|
iter: I,
|
||||||
|
buffer: Option<E>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, I: Iterator<E>> BufferedIter<E, I> {
|
||||||
|
pub fn new(iter: I) -> BufferedIter<E, I> {
|
||||||
|
BufferedIter {
|
||||||
|
iter: iter,
|
||||||
|
buffer: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn push_back(&mut self, value: E) {
|
||||||
|
assert!(self.buffer.is_none());
|
||||||
|
self.buffer = Some(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, I: Iterator<E>> Iterator<E> for BufferedIter<E, I> {
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<E> {
|
||||||
|
if self.buffer.is_some() {
|
||||||
|
self.buffer.take()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.iter.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub type ParserIter<'a> = BufferedIter<&'a ComponentValue, SkipWhitespaceIterator<'a>>;
|
||||||
|
|
|
@ -718,61 +718,61 @@ pub mod longhands {
|
||||||
pub type T = Vec<FontFamily>;
|
pub type T = Vec<FontFamily>;
|
||||||
}
|
}
|
||||||
pub type SpecifiedValue = computed_value::T;
|
pub type SpecifiedValue = computed_value::T;
|
||||||
#[inline] pub fn get_initial_value() -> computed_value::T { vec!(FamilyName("serif".to_string())) }
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
|
vec![FamilyName("serif".to_string())]
|
||||||
|
}
|
||||||
/// <familiy-name>#
|
/// <familiy-name>#
|
||||||
/// <familiy-name> = <string> | [ <ident>+ ]
|
/// <familiy-name> = <string> | [ <ident>+ ]
|
||||||
/// TODO: <generic-familiy>
|
/// TODO: <generic-familiy>
|
||||||
pub fn parse(input: &[ComponentValue], _base_url: &Url) -> Result<SpecifiedValue, ()> {
|
pub fn parse(input: &[ComponentValue], _base_url: &Url) -> Result<SpecifiedValue, ()> {
|
||||||
from_iter(input.skip_whitespace())
|
from_iter(input.skip_whitespace())
|
||||||
}
|
}
|
||||||
pub fn from_iter<'a>(mut iter: SkipWhitespaceIterator<'a>) -> Result<SpecifiedValue, ()> {
|
pub fn from_iter<'a>(iter: SkipWhitespaceIterator<'a>) -> Result<SpecifiedValue, ()> {
|
||||||
let mut result = vec!();
|
let iter = &mut BufferedIter::new(iter);
|
||||||
macro_rules! add(
|
let mut families = vec![try!(parse_one_family(iter))];
|
||||||
($value: expr, $b: expr) => {
|
for component_value in iter {
|
||||||
{
|
match component_value {
|
||||||
result.push($value);
|
&Comma => {
|
||||||
match iter.next() {
|
families.push(try!(parse_one_family(iter)));
|
||||||
Some(&Comma) => (),
|
},
|
||||||
None => $b,
|
_ => return Err(())
|
||||||
_ => return Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
'outer: loop {
|
|
||||||
match iter.next() {
|
|
||||||
// TODO: avoid copying strings?
|
|
||||||
Some(&String(ref value)) => add!(FamilyName(value.clone()), break 'outer),
|
|
||||||
Some(&Ident(ref value)) => {
|
|
||||||
match value.as_slice().to_ascii_lower().as_slice() {
|
|
||||||
// "serif" => add!(Serif, break 'outer),
|
|
||||||
// "sans-serif" => add!(SansSerif, break 'outer),
|
|
||||||
// "cursive" => add!(Cursive, break 'outer),
|
|
||||||
// "fantasy" => add!(Fantasy, break 'outer),
|
|
||||||
// "monospace" => add!(Monospace, break 'outer),
|
|
||||||
_ => {
|
|
||||||
let mut idents = vec!(value.as_slice());
|
|
||||||
loop {
|
|
||||||
match iter.next() {
|
|
||||||
Some(&Ident(ref value)) => idents.push(value.as_slice()),
|
|
||||||
Some(&Comma) => {
|
|
||||||
result.push(FamilyName(idents.connect(" ")));
|
|
||||||
break
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
result.push(FamilyName(idents.connect(" ")));
|
|
||||||
break 'outer
|
|
||||||
},
|
|
||||||
_ => return Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return Err(()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(families)
|
||||||
|
}
|
||||||
|
pub fn parse_one_family<'a>(iter: &mut ParserIter) -> Result<FontFamily, ()> {
|
||||||
|
// TODO: avoid copying strings?
|
||||||
|
let mut idents = match iter.next() {
|
||||||
|
Some(&String(ref value)) => return Ok(FamilyName(value.clone())),
|
||||||
|
Some(&Ident(ref value)) => {
|
||||||
|
// match value.as_slice().to_ascii_lower().as_slice() {
|
||||||
|
// "serif" => return Ok(Serif),
|
||||||
|
// "sans-serif" => return Ok(SansSerif),
|
||||||
|
// "cursive" => return Ok(Cursive),
|
||||||
|
// "fantasy" => return Ok(Fantasy),
|
||||||
|
// "monospace" => return Ok(Monospace),
|
||||||
|
// _ => {
|
||||||
|
vec![value.as_slice()]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
_ => return Err(())
|
||||||
|
};
|
||||||
|
for component_value in iter {
|
||||||
|
match component_value {
|
||||||
|
&Ident(ref value) => {
|
||||||
|
idents.push(value.as_slice());
|
||||||
|
iter.next();
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
iter.push_back(component_value);
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(FamilyName(idents.connect(" ")))
|
||||||
}
|
}
|
||||||
</%self:longhand>
|
</%self:longhand>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue