From b97c7a8c4d95a63e1b967f29789cdcb9261274e1 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 10 Jun 2016 12:41:24 +0200 Subject: [PATCH] Don't load all font faces sources We stop at the first one we manage to load. --- components/gfx/font_cache_thread.rs | 182 +++++++++++++++------------- components/layout/layout_thread.rs | 22 ++-- components/style/font_face.rs | 24 ++-- tests/unit/gfx/font_cache_thread.rs | 20 +-- 4 files changed, 131 insertions(+), 117 deletions(-) diff --git a/components/gfx/font_cache_thread.rs b/components/gfx/font_cache_thread.rs index 2a1a1e7764c..b0a156c4a17 100644 --- a/components/gfx/font_cache_thread.rs +++ b/components/gfx/font_cache_thread.rs @@ -21,7 +21,7 @@ use std::ops::Deref; use std::sync::{Arc, Mutex}; use std::u32; use string_cache::Atom; -use style::font_face::Source; +use style::font_face::{EffectiveSources, Source}; use style::properties::longhands::font_family::computed_value::FontFamily; use url::Url; use util::prefs; @@ -105,8 +105,8 @@ impl FontTemplates { pub enum Command { GetFontTemplate(FontFamily, FontTemplateDescriptor, IpcSender), GetLastResortFontTemplate(FontTemplateDescriptor, IpcSender), - AddWebFont(FontFamily, Source, IpcSender<()>), - AddDownloadedWebFont(FontFamily, Url, Vec, IpcSender<()>), + AddWebFont(LowercaseString, EffectiveSources, IpcSender<()>), + AddDownloadedWebFont(LowercaseString, Url, Vec, IpcSender<()>), Exit(IpcSender<()>), } @@ -171,87 +171,10 @@ impl FontCache { let font_template = self.last_resort_font_template(&descriptor); result.send(Reply::GetFontTemplateReply(Some(font_template))).unwrap(); } - Command::AddWebFont(family, src, result) => { - let family_name = LowercaseString::new(family.name()); - if !self.web_families.contains_key(&family_name) { - let templates = FontTemplates::new(); - self.web_families.insert(family_name.clone(), templates); - } - - match src { - Source::Url(ref url_source) => { - let url = &url_source.url; - let load = PendingAsyncLoad::new(LoadContext::Font, - self.core_resource_thread.clone(), - url.clone(), - None, - None, - None, - RequestSource::None); - let (data_sender, data_receiver) = ipc::channel().unwrap(); - let data_target = AsyncResponseTarget { - sender: data_sender, - }; - load.load_async(data_target); - let channel_to_self = self.channel_to_self.clone(); - let url = (*url).clone(); - let bytes = Mutex::new(Vec::new()); - let response_valid = Mutex::new(false); - ROUTER.add_route(data_receiver.to_opaque(), box move |message| { - let response: ResponseAction = message.to().unwrap(); - match response { - ResponseAction::HeadersAvailable(meta_result) => { - let is_response_valid = match meta_result { - Ok(ref metadata) => { - metadata.content_type.as_ref().map_or(false, |content_type| { - let mime = &content_type.0; - is_supported_font_type(&mime.0, &mime.1) - }) - } - Err(_) => false, - }; - - info!("{} font with MIME type {}", - if is_response_valid { "Loading" } else { "Ignoring" }, - meta_result.map(|ref meta| format!("{:?}", meta.content_type)) - .unwrap_or(format!(""))); - *response_valid.lock().unwrap() = is_response_valid; - } - ResponseAction::DataAvailable(new_bytes) => { - if *response_valid.lock().unwrap() { - bytes.lock().unwrap().extend(new_bytes.into_iter()) - } - } - ResponseAction::ResponseComplete(response) => { - if response.is_err() || !*response_valid.lock().unwrap() { - drop(result.send(())); - return; - } - let mut bytes = bytes.lock().unwrap(); - let bytes = mem::replace(&mut *bytes, Vec::new()); - let command = - Command::AddDownloadedWebFont(family.clone(), - url.clone(), - bytes, - result.clone()); - channel_to_self.send(command).unwrap(); - } - } - }); - } - Source::Local(ref font) => { - let font_face_name = LowercaseString::new(font.name()); - let templates = &mut self.web_families.get_mut(&family_name).unwrap(); - for_each_variation(&font_face_name, |path| { - templates.add_template(Atom::from(&*path), None); - }); - result.send(()).unwrap(); - } - } + Command::AddWebFont(family_name, sources, result) => { + self.handle_add_web_font(family_name, sources, result); } - Command::AddDownloadedWebFont(family, url, bytes, result) => { - let family_name = LowercaseString::new(family.name()); - + Command::AddDownloadedWebFont(family_name, url, bytes, result) => { let templates = &mut self.web_families.get_mut(&family_name).unwrap(); templates.add_template(Atom::from(url.to_string()), Some(bytes)); drop(result.send(())); @@ -264,6 +187,95 @@ impl FontCache { } } + fn handle_add_web_font(&mut self, + family_name: LowercaseString, + mut sources: EffectiveSources, + sender: IpcSender<()>) { + let src = if let Some(src) = sources.next() { + src + } else { + sender.send(()).unwrap(); + return; + }; + + if !self.web_families.contains_key(&family_name) { + let templates = FontTemplates::new(); + self.web_families.insert(family_name.clone(), templates); + } + + match src { + Source::Url(ref url_source) => { + let url = &url_source.url; + let load = PendingAsyncLoad::new(LoadContext::Font, + self.core_resource_thread.clone(), + url.clone(), + None, + None, + None, + RequestSource::None); + let (data_sender, data_receiver) = ipc::channel().unwrap(); + let data_target = AsyncResponseTarget { + sender: data_sender, + }; + load.load_async(data_target); + let channel_to_self = self.channel_to_self.clone(); + let url = (*url).clone(); + let bytes = Mutex::new(Vec::new()); + let response_valid = Mutex::new(false); + ROUTER.add_route(data_receiver.to_opaque(), box move |message| { + let response: ResponseAction = message.to().unwrap(); + match response { + ResponseAction::HeadersAvailable(meta_result) => { + let is_response_valid = match meta_result { + Ok(ref metadata) => { + metadata.content_type.as_ref().map_or(false, |content_type| { + let mime = &content_type.0; + is_supported_font_type(&mime.0, &mime.1) + }) + } + Err(_) => false, + }; + + info!("{} font with MIME type {}", + if is_response_valid { "Loading" } else { "Ignoring" }, + meta_result.map(|ref meta| format!("{:?}", meta.content_type)) + .unwrap_or(format!(""))); + *response_valid.lock().unwrap() = is_response_valid; + } + ResponseAction::DataAvailable(new_bytes) => { + if *response_valid.lock().unwrap() { + bytes.lock().unwrap().extend(new_bytes.into_iter()) + } + } + ResponseAction::ResponseComplete(response) => { + if response.is_err() || !*response_valid.lock().unwrap() { + let msg = Command::AddWebFont(family_name.clone(), sources.clone(), sender.clone()); + channel_to_self.send(msg).unwrap(); + return; + } + let mut bytes = bytes.lock().unwrap(); + let bytes = mem::replace(&mut *bytes, Vec::new()); + let command = + Command::AddDownloadedWebFont(family_name.clone(), + url.clone(), + bytes, + sender.clone()); + channel_to_self.send(command).unwrap(); + } + } + }); + } + Source::Local(ref font) => { + let font_face_name = LowercaseString::new(font.name()); + let templates = &mut self.web_families.get_mut(&family_name).unwrap(); + for_each_variation(&font_face_name, |path| { + templates.add_template(Atom::from(&*path), None); + }); + sender.send(()).unwrap(); + } + } + } + fn refresh_local_families(&mut self) { self.local_families.clear(); for_each_available_family(|family_name| { @@ -431,8 +443,8 @@ impl FontCacheThread { } } - pub fn add_web_font(&self, family: FontFamily, src: Source, sender: IpcSender<()>) { - self.chan.send(Command::AddWebFont(family, src, sender)).unwrap(); + pub fn add_web_font(&self, family: FontFamily, sources: EffectiveSources, sender: IpcSender<()>) { + self.chan.send(Command::AddWebFont(LowercaseString::new(family.name()), sources, sender)).unwrap(); } pub fn exit(&self) { diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index 5bef2050932..e858ac5fcee 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -358,21 +358,19 @@ fn add_font_face_rules(stylesheet: &Stylesheet, if opts::get().load_webfonts_synchronously { let (sender, receiver) = ipc::channel().unwrap(); for font_face in stylesheet.effective_rules(&device).font_face() { - for source in font_face.effective_sources() { - font_cache_thread.add_web_font(font_face.family.clone(), - (*source).clone(), - sender.clone()); - receiver.recv().unwrap(); - } + let effective_sources = font_face.effective_sources(); + font_cache_thread.add_web_font(font_face.family.clone(), + effective_sources, + sender.clone()); + receiver.recv().unwrap(); } } else { for font_face in stylesheet.effective_rules(&device).font_face() { - for source in font_face.effective_sources() { - outstanding_web_fonts_counter.fetch_add(1, Ordering::SeqCst); - font_cache_thread.add_web_font(font_face.family.clone(), - (*source).clone(), - (*font_cache_sender).clone()); - } + let effective_sources = font_face.effective_sources(); + outstanding_web_fonts_counter.fetch_add(1, Ordering::SeqCst); + font_cache_thread.add_web_font(font_face.family.clone(), + effective_sources, + (*font_cache_sender).clone()); } } } diff --git a/components/style/font_face.rs b/components/style/font_face.rs index 6db70a86e25..f3876210478 100644 --- a/components/style/font_face.rs +++ b/components/style/font_face.rs @@ -7,7 +7,6 @@ use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser}; use parser::{ParserContext, log_css_error}; use properties::longhands::font_family::parse_one_family; use std::iter; -use std::slice; use url::Url; #[derive(Clone, Debug, HeapSizeOf, PartialEq, Eq, Deserialize, Serialize)] @@ -60,21 +59,15 @@ pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser) } } -pub struct EffectiveSourcesIter<'a>(slice::Iter<'a, Source>); +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct EffectiveSources(Vec); impl FontFaceRule { /// Returns the list of effective sources for that font-face, that is the /// sources which don't list any format hint, or the ones which list at /// least "truetype" or "opentype". - pub fn effective_sources(&self) -> EffectiveSourcesIter { - EffectiveSourcesIter(self.sources.iter()) - } -} - -impl<'a> iter::Iterator for EffectiveSourcesIter<'a> { - type Item = &'a Source; - fn next(&mut self) -> Option<&'a Source> { - self.0.find(|source| { + pub fn effective_sources(&self) -> EffectiveSources { + EffectiveSources(self.sources.iter().rev().filter(|source| { if let Source::Url(ref url_source) = **source { let hints = &url_source.format_hints; // We support only opentype fonts and truetype is an alias for @@ -86,7 +79,14 @@ impl<'a> iter::Iterator for EffectiveSourcesIter<'a> { } else { true } - }) + }).cloned().collect()) + } +} + +impl iter::Iterator for EffectiveSources { + type Item = Source; + fn next(&mut self) -> Option { + self.0.pop() } } diff --git a/tests/unit/gfx/font_cache_thread.rs b/tests/unit/gfx/font_cache_thread.rs index 035ad7e8365..7020679893a 100644 --- a/tests/unit/gfx/font_cache_thread.rs +++ b/tests/unit/gfx/font_cache_thread.rs @@ -5,17 +5,21 @@ use gfx::font_cache_thread::FontCacheThread; use ipc_channel::ipc; use style::computed_values::font_family::FontFamily; -use style::font_face::Source; +use style::font_face::{FontFaceRule, Source}; #[test] fn test_local_web_font() { - let (inp_chan, _) = ipc::channel().unwrap(); - let (out_chan, out_receiver) = ipc::channel().unwrap(); - let font_cache_thread = FontCacheThread::new(inp_chan, None); - let family_name = FontFamily::FamilyName(From::from("test family")); - let variant_name = FontFamily::FamilyName(From::from("test font face")); + let (inp_chan, _) = ipc::channel().unwrap(); + let (out_chan, out_receiver) = ipc::channel().unwrap(); + let font_cache_thread = FontCacheThread::new(inp_chan, None); + let family_name = FontFamily::FamilyName(From::from("test family")); + let variant_name = FontFamily::FamilyName(From::from("test font face")); + let font_face_rule = FontFaceRule { + family: family_name.clone(), + sources: vec![Source::Local(variant_name)], + }; - font_cache_thread.add_web_font(family_name, Source::Local(variant_name), out_chan); + font_cache_thread.add_web_font(family_name, font_face_rule.effective_sources(), out_chan); - assert_eq!(out_receiver.recv().unwrap(), ()); + assert_eq!(out_receiver.recv().unwrap(), ()); }