aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/gfx/font_cache_task.rs83
-rw-r--r--src/components/gfx/font_context.rs2
-rw-r--r--src/components/gfx/font_template.rs80
-rw-r--r--src/components/gfx/gfx.rs1
-rw-r--r--src/components/gfx/platform/android/font_template.rs15
-rw-r--r--src/components/gfx/platform/linux/font_template.rs15
-rw-r--r--src/components/gfx/platform/macos/font.rs18
-rw-r--r--src/components/gfx/platform/macos/font_template.rs23
-rw-r--r--src/components/layout/layout_task.rs21
-rw-r--r--src/components/main/servo.rs2
-rw-r--r--src/components/style/font_face.rs207
-rw-r--r--src/components/style/style.rs4
-rw-r--r--src/components/style/stylesheets.rs6
13 files changed, 425 insertions, 52 deletions
diff --git a/src/components/gfx/font_cache_task.rs b/src/components/gfx/font_cache_task.rs
index a3f7f8c2882..1dc919c5d26 100644
--- a/src/components/gfx/font_cache_task.rs
+++ b/src/components/gfx/font_cache_task.rs
@@ -11,6 +11,8 @@ use std::collections::HashMap;
use sync::Arc;
use font_template::{FontTemplate, FontTemplateDescriptor};
use platform::font_template::FontTemplateData;
+use servo_net::resource_task::{ResourceTask, load_whole_resource};
+use url::Url;
/// A list of font templates that make up a given font family.
struct FontFamily {
@@ -40,13 +42,35 @@ impl FontFamily {
}
}
+ // If a request is made for a font family that exists,
+ // pick the first valid font in the family if we failed
+ // to find an exact match for the descriptor.
+ for template in self.templates.mut_iter() {
+ let maybe_template = template.get();
+ if maybe_template.is_some() {
+ return maybe_template;
+ }
+ }
+
None
}
+
+ fn add_template(&mut self, identifier: &str, maybe_data: Option<Vec<u8>>) {
+ for template in self.templates.iter() {
+ if template.identifier() == identifier {
+ return;
+ }
+ }
+
+ let template = FontTemplate::new(identifier, maybe_data);
+ self.templates.push(template);
+ }
}
/// Commands that the FontContext sends to the font cache task.
pub enum Command {
GetFontTemplate(String, FontTemplateDescriptor, Sender<Reply>),
+ AddWebFont(Vec<Url>, String, Sender<()>),
Exit(Sender<()>),
}
@@ -61,7 +85,9 @@ struct FontCache {
port: Receiver<Command>,
generic_fonts: HashMap<String, String>,
local_families: HashMap<String, FontFamily>,
+ web_families: HashMap<String, FontFamily>,
font_context: FontContextHandle,
+ resource_task: ResourceTask,
}
impl FontCache {
@@ -72,7 +98,6 @@ impl FontCache {
match msg {
GetFontTemplate(family, descriptor, result) => {
let maybe_font_template = self.get_font_template(&family, &descriptor);
-
let font_template = match maybe_font_template {
Some(font_template) => font_template,
None => self.get_last_resort_template(&descriptor),
@@ -80,6 +105,25 @@ impl FontCache {
result.send(GetFontTemplateReply(font_template));
}
+ AddWebFont(urls, family_name, result) => {
+ for url in urls.iter() {
+ let maybe_resource = load_whole_resource(&self.resource_task, url.clone());
+ match maybe_resource {
+ Ok((_, bytes)) => {
+ if !self.web_families.contains_key(&family_name) {
+ let family = FontFamily::new();
+ self.web_families.insert(family_name.clone(), family);
+ }
+ let family = self.web_families.get_mut(&family_name);
+ family.add_template(format!("{}", url).as_slice(), Some(bytes));
+ },
+ Err(msg) => {
+ fail!(msg);
+ }
+ }
+ }
+ result.send(());
+ }
Exit(result) => {
result.send(());
break;
@@ -105,9 +149,8 @@ impl FontCache {
}
}
- fn find_font_in_family<'a>(&'a mut self,
- family_name: &String,
- desc: &FontTemplateDescriptor) -> Option<Arc<FontTemplateData>> {
+ fn find_font_in_local_family<'a>(&'a mut self, family_name: &String, desc: &FontTemplateDescriptor)
+ -> Option<Arc<FontTemplateData>> {
// TODO(Issue #188): look up localized font family names if canonical name not found
// look up canonical name
if self.local_families.contains_key(family_name) {
@@ -116,8 +159,7 @@ impl FontCache {
if s.templates.len() == 0 {
get_variations_for_family(family_name.as_slice(), |path| {
- let template = FontTemplate::new(path.as_slice());
- s.templates.push(template);
+ s.add_template(path.as_slice(), None);
});
}
@@ -135,16 +177,31 @@ impl FontCache {
}
}
+ fn find_font_in_web_family<'a>(&'a mut self, family_name: &String, desc: &FontTemplateDescriptor)
+ -> Option<Arc<FontTemplateData>> {
+ if self.web_families.contains_key(family_name) {
+ let family = self.web_families.get_mut(family_name);
+ let maybe_font = family.find_font_for_style(desc, &self.font_context);
+ maybe_font
+ } else {
+ None
+ }
+ }
+
fn get_font_template(&mut self, family: &String, desc: &FontTemplateDescriptor) -> Option<Arc<FontTemplateData>> {
let transformed_family_name = self.transform_family(family);
- self.find_font_in_family(&transformed_family_name, desc)
+ let mut maybe_template = self.find_font_in_web_family(&transformed_family_name, desc);
+ if maybe_template.is_none() {
+ maybe_template = self.find_font_in_local_family(&transformed_family_name, desc);
+ }
+ maybe_template
}
fn get_last_resort_template(&mut self, desc: &FontTemplateDescriptor) -> Arc<FontTemplateData> {
let last_resort = get_last_resort_font_families();
for family in last_resort.iter() {
- let maybe_font_in_family = self.find_font_in_family(family, desc);
+ let maybe_font_in_family = self.find_font_in_local_family(family, desc);
if maybe_font_in_family.is_some() {
return maybe_font_in_family.unwrap();
}
@@ -162,7 +219,7 @@ pub struct FontCacheTask {
}
impl FontCacheTask {
- pub fn new() -> FontCacheTask {
+ pub fn new(resource_task: ResourceTask) -> FontCacheTask {
let (chan, port) = channel();
spawn(proc() {
@@ -178,7 +235,9 @@ impl FontCacheTask {
port: port,
generic_fonts: generic_fonts,
local_families: HashMap::new(),
+ web_families: HashMap::new(),
font_context: FontContextHandle::new(),
+ resource_task: resource_task,
};
cache.refresh_local_families();
@@ -205,6 +264,12 @@ impl FontCacheTask {
}
}
+ pub fn add_web_font(&mut self, urls: Vec<Url>, family: &str) {
+ let (response_chan, response_port) = channel();
+ self.chan.send(AddWebFont(urls, family.to_string(), response_chan));
+ response_port.recv();
+ }
+
pub fn exit(&self) {
let (response_chan, response_port) = channel();
self.chan.send(Exit(response_chan));
diff --git a/src/components/gfx/font_context.rs b/src/components/gfx/font_context.rs
index a9cccae61fb..0a1ef69e0ce 100644
--- a/src/components/gfx/font_context.rs
+++ b/src/components/gfx/font_context.rs
@@ -34,7 +34,7 @@ fn create_scaled_font(backend: BackendType, template: &Arc<FontTemplateData>, pt
#[cfg(target_os="macos")]
fn create_scaled_font(backend: BackendType, template: &Arc<FontTemplateData>, pt_size: f64) -> ScaledFont {
- let cgfont = template.ctfont.copy_to_CGFont();
+ let cgfont = template.ctfont.get_ref().copy_to_CGFont();
ScaledFont::new(backend, &cgfont, pt_size as AzFloat)
}
diff --git a/src/components/gfx/font_template.rs b/src/components/gfx/font_template.rs
index 12753da68a1..3f4916b69c5 100644
--- a/src/components/gfx/font_template.rs
+++ b/src/components/gfx/font_template.rs
@@ -42,21 +42,44 @@ impl PartialEq for FontTemplateDescriptor {
pub struct FontTemplate {
identifier: String,
descriptor: Option<FontTemplateDescriptor>,
- data: Option<Weak<FontTemplateData>>,
+ weak_ref: Option<Weak<FontTemplateData>>,
+ strong_ref: Option<Arc<FontTemplateData>>, // GWTODO: Add code path to unset the strong_ref for web fonts!
+ is_valid: bool,
}
/// Holds all of the template information for a font that
/// is common, regardless of the number of instances of
/// this font handle per thread.
impl FontTemplate {
- pub fn new(identifier: &str) -> FontTemplate {
+ pub fn new(identifier: &str, maybe_bytes: Option<Vec<u8>>) -> FontTemplate {
+ let maybe_data = match maybe_bytes {
+ Some(_) => Some(FontTemplateData::new(identifier, maybe_bytes)),
+ None => None,
+ };
+
+ let maybe_strong_ref = match maybe_data {
+ Some(data) => Some(Arc::new(data)),
+ None => None,
+ };
+
+ let maybe_weak_ref = match maybe_strong_ref {
+ Some(ref strong_ref) => Some(strong_ref.downgrade()),
+ None => None,
+ };
+
FontTemplate {
identifier: identifier.to_string(),
descriptor: None,
- data: None,
+ weak_ref: maybe_weak_ref,
+ strong_ref: maybe_strong_ref,
+ is_valid: true,
}
}
+ pub fn identifier<'a>(&'a self) -> &'a str {
+ self.identifier.as_slice()
+ }
+
/// Get the data for creating a font if it matches a given descriptor.
pub fn get_if_matches(&mut self, fctx: &FontContextHandle,
requested_desc: &FontTemplateDescriptor) -> Option<Arc<FontTemplateData>> {
@@ -74,19 +97,29 @@ impl FontTemplate {
}
},
None => {
- let data = self.get_data();
- let handle = FontHandleMethods::new_from_template(fctx, data.clone(), None);
- let handle: FontHandle = match handle {
- Ok(handle) => handle,
- Err(()) => fail!("TODO - Handle failure to create a font from template."),
- };
- let actual_desc = FontTemplateDescriptor::new(handle.boldness(),
- handle.is_italic());
- let desc_match = actual_desc == *requested_desc;
-
- self.descriptor = Some(actual_desc);
- if desc_match {
- Some(data)
+ if self.is_valid {
+ let data = self.get_data();
+ let handle: Result<FontHandle, ()> = FontHandleMethods::new_from_template(fctx, data.clone(), None);
+ match handle {
+ Ok(handle) => {
+ let actual_desc = FontTemplateDescriptor::new(handle.boldness(),
+ handle.is_italic());
+ let desc_match = actual_desc == *requested_desc;
+
+ self.descriptor = Some(actual_desc);
+ self.is_valid = true;
+ if desc_match {
+ Some(data)
+ } else {
+ None
+ }
+ }
+ Err(()) => {
+ self.is_valid = false;
+ debug!("Unable to create a font from template {}", self.identifier);
+ None
+ }
+ }
} else {
None
}
@@ -94,11 +127,19 @@ impl FontTemplate {
}
}
+ /// Get the data for creating a font.
+ pub fn get(&mut self) -> Option<Arc<FontTemplateData>> {
+ match self.is_valid {
+ true => Some(self.get_data()),
+ false => None
+ }
+ }
+
/// Get the font template data. If any strong references still
/// exist, it will return a clone, otherwise it will load the
/// font data and store a weak reference to it internally.
pub fn get_data(&mut self) -> Arc<FontTemplateData> {
- let maybe_data = match self.data {
+ let maybe_data = match self.weak_ref {
Some(ref data) => data.upgrade(),
None => None,
};
@@ -106,8 +147,9 @@ impl FontTemplate {
match maybe_data {
Some(data) => data,
None => {
- let template_data = Arc::new(FontTemplateData::new(self.identifier.as_slice()));
- self.data = Some(template_data.downgrade());
+ assert!(self.strong_ref.is_none());
+ let template_data = Arc::new(FontTemplateData::new(self.identifier.as_slice(), None));
+ self.weak_ref = Some(template_data.downgrade());
template_data
}
}
diff --git a/src/components/gfx/gfx.rs b/src/components/gfx/gfx.rs
index 32fa30aba51..3e3ad8a308e 100644
--- a/src/components/gfx/gfx.rs
+++ b/src/components/gfx/gfx.rs
@@ -29,6 +29,7 @@ extern crate servo_util = "util";
extern crate servo_msg = "msg";
extern crate style;
extern crate sync;
+extern crate url = "url_";
// Eventually we would like the shaper to be pluggable, as many operating systems have their own
// shapers. For now, however, this is a hard dependency.
diff --git a/src/components/gfx/platform/android/font_template.rs b/src/components/gfx/platform/android/font_template.rs
index d1a821a0bf3..e8c058ee9ac 100644
--- a/src/components/gfx/platform/android/font_template.rs
+++ b/src/components/gfx/platform/android/font_template.rs
@@ -15,10 +15,17 @@ pub struct FontTemplateData {
}
impl FontTemplateData {
- pub fn new(identifier: &str) -> FontTemplateData {
- // TODO: Handle file load failure!
- let mut file = File::open_mode(&Path::new(identifier), io::Open, io::Read).unwrap();
- let bytes = file.read_to_end().unwrap();
+ pub fn new(identifier: &str, font_data: Option<Vec<u8>>) -> FontTemplateData {
+ let bytes = match font_data {
+ Some(bytes) => {
+ bytes
+ },
+ None => {
+ // TODO: Handle file load failure!
+ let mut file = File::open_mode(&Path::new(identifier), io::Open, io::Read).unwrap();
+ file.read_to_end().unwrap()
+ },
+ };
FontTemplateData {
bytes: bytes,
diff --git a/src/components/gfx/platform/linux/font_template.rs b/src/components/gfx/platform/linux/font_template.rs
index e00a1018317..663ea64ab29 100644
--- a/src/components/gfx/platform/linux/font_template.rs
+++ b/src/components/gfx/platform/linux/font_template.rs
@@ -15,10 +15,17 @@ pub struct FontTemplateData {
}
impl FontTemplateData {
- pub fn new(identifier: &str) -> FontTemplateData {
- // TODO: Handle file load failure!
- let mut file = File::open_mode(&Path::new(identifier), io::Open, io::Read).unwrap();
- let bytes = file.read_to_end().unwrap();
+ pub fn new(identifier: &str, font_data: Option<Vec<u8>>) -> FontTemplateData {
+ let bytes = match font_data {
+ Some(bytes) => {
+ bytes
+ },
+ None => {
+ // TODO: Handle file load failure!
+ let mut file = File::open_mode(&Path::new(identifier), io::Open, io::Read).unwrap();
+ file.read_to_end().unwrap()
+ },
+ };
FontTemplateData {
bytes: bytes,
diff --git a/src/components/gfx/platform/macos/font.rs b/src/components/gfx/platform/macos/font.rs
index a6a5f092d78..682c44088d2 100644
--- a/src/components/gfx/platform/macos/font.rs
+++ b/src/components/gfx/platform/macos/font.rs
@@ -65,13 +65,17 @@ impl FontHandleMethods for FontHandle {
Some(s) => s,
None => 0.0
};
- let ct_result = core_text::font::new_from_name(template.identifier.as_slice(), size);
- ct_result.and_then(|ctfont| {
- Ok(FontHandle {
- font_data: template.clone(),
- ctfont: ctfont,
- })
- })
+ match template.ctfont {
+ Some(ref ctfont) => {
+ Ok(FontHandle {
+ font_data: template.clone(),
+ ctfont: ctfont.clone_with_font_size(size),
+ })
+ }
+ None => {
+ Err(())
+ }
+ }
}
fn get_template(&self) -> Arc<FontTemplateData> {
diff --git a/src/components/gfx/platform/macos/font_template.rs b/src/components/gfx/platform/macos/font_template.rs
index bda41186da3..8641d491523 100644
--- a/src/components/gfx/platform/macos/font_template.rs
+++ b/src/components/gfx/platform/macos/font_template.rs
@@ -2,6 +2,8 @@
* 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 core_graphics::data_provider::CGDataProvider;
+use core_graphics::font::CGFont;
use core_text::font::CTFont;
use core_text;
@@ -10,15 +12,28 @@ use core_text;
/// CTFont object is cached here for use by the
/// render functions that create CGFont references.
pub struct FontTemplateData {
- pub ctfont: CTFont,
+ pub ctfont: Option<CTFont>,
pub identifier: String,
}
impl FontTemplateData {
- pub fn new(identifier: &str) -> FontTemplateData {
- let ctfont_result = core_text::font::new_from_name(identifier.as_slice(), 0.0);
+ pub fn new(identifier: &str, font_data: Option<Vec<u8>>) -> FontTemplateData {
+ let ctfont = match font_data {
+ Some(bytes) => {
+ let fontprov = CGDataProvider::from_buffer(bytes.as_slice());
+ let cgfont_result = CGFont::from_data_provider(fontprov);
+ match cgfont_result {
+ Ok(cgfont) => Some(core_text::font::new_from_CGFont(&cgfont, 0.0)),
+ Err(_) => None
+ }
+ },
+ None => {
+ Some(core_text::font::new_from_name(identifier.as_slice(), 0.0).unwrap())
+ }
+ };
+
FontTemplateData {
- ctfont: ctfont_result.unwrap(),
+ ctfont: ctfont,
identifier: identifier.to_string(),
}
}
diff --git a/src/components/layout/layout_task.rs b/src/components/layout/layout_task.rs
index 3d9cca46737..c40ed74f342 100644
--- a/src/components/layout/layout_task.rs
+++ b/src/components/layout/layout_task.rs
@@ -59,6 +59,7 @@ use std::comm::{channel, Sender, Receiver};
use std::mem;
use std::ptr;
use style::{AuthorOrigin, Stylesheet, Stylist};
+use style::CSSFontFaceRule;
use sync::{Arc, Mutex};
use url::Url;
@@ -447,7 +448,25 @@ impl LayoutTask {
}
fn handle_add_stylesheet(&mut self, sheet: Stylesheet) {
- self.stylist.add_stylesheet(sheet, AuthorOrigin)
+ // Find all font-face rules and notify the font cache of them.
+ // GWTODO: Need to handle unloading web fonts (when we handle unloading stylesheets!)
+ // GWTODO: Need to handle font-face nested within media rules.
+ for rule in sheet.rules.iter() {
+ match rule {
+ &CSSFontFaceRule(ref font_face_rule) => {
+ let mut font_urls = vec!();
+ for source_line in font_face_rule.source_lines.iter() {
+ for source in source_line.sources.iter() {
+ font_urls.push(source.url.clone());
+ }
+ }
+ self.font_cache_task.add_web_font(font_urls, font_face_rule.family.as_slice());
+ },
+ _ => {}
+ }
+ }
+
+ self.stylist.add_stylesheet(sheet, AuthorOrigin);
}
/// Retrieves the flow tree root from the root node.
diff --git a/src/components/main/servo.rs b/src/components/main/servo.rs
index fcf3f9fd315..09225b9ae96 100644
--- a/src/components/main/servo.rs
+++ b/src/components/main/servo.rs
@@ -125,7 +125,7 @@ pub fn run(opts: opts::Opts) {
} else {
ImageCacheTask::new(resource_task.clone())
};
- let font_cache_task = FontCacheTask::new();
+ let font_cache_task = FontCacheTask::new(resource_task.clone());
let constellation_chan = Constellation::<layout::layout_task::LayoutTask>::start(
compositor_chan,
opts,
diff --git a/src/components/style/font_face.rs b/src/components/style/font_face.rs
new file mode 100644
index 00000000000..228c5d459ae
--- /dev/null
+++ b/src/components/style/font_face.rs
@@ -0,0 +1,207 @@
+/* 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 cssparser::ast::*;
+use cssparser::parse_declaration_list;
+use errors::{ErrorLoggerIterator, log_css_error};
+use std::ascii::StrAsciiExt;
+use parsing_utils::one_component_value;
+use stylesheets::{CSSRule, CSSFontFaceRule};
+use url::{Url, UrlParser};
+
+#[deriving(PartialEq)]
+pub enum FontFaceFormat {
+ UnknownFormat,
+ WoffFormat,
+ TtfFormat,
+ SvgFormat,
+ EotFormat,
+}
+
+pub struct FontFaceSource {
+ pub url: Url,
+ pub format_hints: Vec<FontFaceFormat>,
+}
+
+pub struct FontFaceSourceLine {
+ pub sources: Vec<FontFaceSource>
+}
+
+pub struct FontFaceRule {
+ pub family: String,
+ pub source_lines: Vec<FontFaceSourceLine>,
+}
+
+pub fn parse_font_face_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, base_url: &Url) {
+ let mut maybe_family = None;
+ let mut source_lines = vec!();
+
+ if rule.prelude.as_slice().skip_whitespace().next().is_some() {
+ log_css_error(rule.location, "@font-face prelude contains unexpected characters");
+ return;
+ }
+
+ let block = match rule.block {
+ Some(block) => block,
+ None => {
+ log_css_error(rule.location, "Invalid @font-face rule");
+ return
+ }
+ };
+
+ for item in ErrorLoggerIterator(parse_declaration_list(block.move_iter())) {
+ match item {
+ DeclAtRule(rule) => log_css_error(
+ rule.location, format!("Unsupported at-rule in declaration list: @{:s}", rule.name).as_slice()),
+ Declaration(Declaration{ location: location, name: name, value: value, important: _}) => {
+
+ let name_lower = name.as_slice().to_ascii_lower();
+ match name_lower.as_slice() {
+ "font-family" => {
+ // FIXME(#2802): Share code with the font-family parser.
+ match one_component_value(value.as_slice()) {
+ Some(&String(ref string_value)) => {
+ maybe_family = Some(string_value.clone());
+ },
+ _ => {
+ log_css_error(location, format!("Unsupported font-family string {:s}", name).as_slice());
+ }
+ }
+ },
+ "src" => {
+ let mut iter = value.as_slice().skip_whitespace();
+ let mut sources = vec!();
+ let mut syntax_error = false;
+
+ 'outer: loop {
+
+ // url() or local() should be next
+ let maybe_url = match iter.next() {
+ Some(&URL(ref string_value)) => {
+ let maybe_url = UrlParser::new().base_url(base_url).parse(string_value.as_slice());
+ let url = maybe_url.unwrap_or_else(|_| Url::parse("about:invalid").unwrap());
+ Some(url)
+ },
+ Some(&Function(ref string_value, ref _values)) => {
+ match string_value.as_slice() {
+ "local" => {
+ log_css_error(location, "local font face is not supported yet - skipping");
+ None
+ },
+ _ => {
+ log_css_error(location, format!("Unexpected token {}", string_value).as_slice());
+ syntax_error = true;
+ break;
+ }
+ }
+ },
+ _ => {
+ log_css_error(location, "Unsupported declaration type");
+ syntax_error = true;
+ break;
+ }
+ };
+
+ let mut next_token = iter.next();
+
+ match maybe_url {
+ Some(url) => {
+ let mut source = FontFaceSource {
+ url: url,
+ format_hints: vec!(),
+ };
+
+ // optional format, or comma to start loop again
+ match next_token {
+ Some(&Function(ref string_value, ref values)) => {
+ match string_value.as_slice() {
+ "format" => {
+ let mut format_iter = values.as_slice().skip_whitespace();
+
+ loop {
+ let fmt_token = format_iter.next();
+ match fmt_token {
+ Some(&String(ref format_hint)) => {
+ let hint = match format_hint.as_slice() {
+ "embedded-opentype" => EotFormat,
+ "woff" => WoffFormat,
+ "truetype" | "opentype" => TtfFormat,
+ "svg" => SvgFormat,
+ _ => UnknownFormat,
+ };
+ source.format_hints.push(hint);
+ },
+ _ => {
+ log_css_error(location, "Unexpected token");
+ syntax_error = true;
+ break 'outer;
+ }
+ }
+
+ let comma_token = format_iter.next();
+ match comma_token {
+ Some(&Comma) => {},
+ None => {
+ break;
+ }
+ _ => {
+ log_css_error(location, "Unexpected token");
+ syntax_error = true;
+ break 'outer;
+ }
+ }
+ }
+ },
+ _ => {
+ log_css_error(location,
+ format!("Unsupported token {}", string_value).as_slice());
+ syntax_error = true;
+ break;
+ }
+ }
+ next_token = iter.next();
+ },
+ _ => {}
+ }
+
+ sources.push(source);
+ },
+ None => {},
+ }
+
+ // after url or optional format, comes comma or end
+ match next_token {
+ Some(&Comma) => {},
+ None => break,
+ _ => {
+ log_css_error(location, "Unexpected token type");
+ syntax_error = true;
+ break;
+ }
+ }
+ }
+
+ if !syntax_error && sources.len() > 0 {
+ let source_line = FontFaceSourceLine {
+ sources: sources
+ };
+ source_lines.push(source_line);
+ }
+ },
+ _ => {
+ log_css_error(location, format!("Unsupported declaration {:s}", name).as_slice());
+ }
+ }
+ }
+ }
+ }
+
+ if maybe_family.is_some() && source_lines.len() > 0 {
+ let font_face_rule = FontFaceRule {
+ family: maybe_family.unwrap(),
+ source_lines: source_lines,
+ };
+ parent_rules.push(CSSFontFaceRule(font_face_rule));
+ }
+}
diff --git a/src/components/style/style.rs b/src/components/style/style.rs
index 3d67eb761a1..f4c5ba56e7e 100644
--- a/src/components/style/style.rs
+++ b/src/components/style/style.rs
@@ -30,7 +30,7 @@ extern crate servo_util = "util";
// Public API
-pub use stylesheets::{Stylesheet, CSSRule, StyleRule};
+pub use stylesheets::{Stylesheet, CSSRule, StyleRule, CSSFontFaceRule};
pub use selector_matching::{Stylist, StylesheetOrigin, UserAgentOrigin, AuthorOrigin, UserOrigin};
pub use selector_matching::{MatchedProperty, matches_compound_selector};
pub use properties::{cascade, cascade_anonymous};
@@ -45,6 +45,7 @@ pub use selectors::{NamespaceConstraint, Selector, CompoundSelector, SimpleSelec
pub use selectors::{parse_selector_list};
pub use namespaces::NamespaceMap;
pub use media_queries::{MediaRule, MediaQueryList, MediaQuery, Device, MediaType, MediaQueryType};
+pub use font_face::{FontFaceFormat, FontFaceRule, FontFaceSource,FontFaceSourceLine, TtfFormat};
mod stylesheets;
mod errors;
@@ -55,3 +56,4 @@ mod namespaces;
mod node;
mod media_queries;
mod parsing_utils;
+mod font_face;
diff --git a/src/components/style/stylesheets.rs b/src/components/style/stylesheets.rs
index 8992477de00..a1e78bc2a18 100644
--- a/src/components/style/stylesheets.rs
+++ b/src/components/style/stylesheets.rs
@@ -16,6 +16,7 @@ use errors::{ErrorLoggerIterator, log_css_error};
use namespaces::{NamespaceMap, parse_namespace_rule};
use media_queries::{MediaRule, parse_media_rule};
use media_queries;
+use font_face::{FontFaceRule, parse_font_face_rule};
pub struct Stylesheet {
@@ -28,6 +29,7 @@ pub struct Stylesheet {
pub enum CSSRule {
CSSStyleRule(StyleRule),
CSSMediaRule(MediaRule),
+ CSSFontFaceRule(FontFaceRule),
}
@@ -143,6 +145,7 @@ pub fn parse_nested_at_rule(lower_name: &str, rule: AtRule,
parent_rules: &mut Vec<CSSRule>, namespaces: &NamespaceMap, base_url: &Url) {
match lower_name {
"media" => parse_media_rule(rule, parent_rules, namespaces, base_url),
+ "font-face" => parse_font_face_rule(rule, parent_rules, base_url),
_ => log_css_error(rule.location,
format!("Unsupported at-rule: @{:s}", lower_name).as_slice())
}
@@ -156,7 +159,8 @@ pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
CSSStyleRule(ref rule) => callback(rule),
CSSMediaRule(ref rule) => if rule.media_queries.evaluate(device) {
iter_style_rules(rule.rules.as_slice(), device, |s| callback(s))
- }
+ },
+ CSSFontFaceRule(_) => {},
}
}
}