diff --git a/components/gfx/font_cache_task.rs b/components/gfx/font_cache_task.rs index 59fcd4146b9..1f1e6a110cc 100644 --- a/components/gfx/font_cache_task.rs +++ b/components/gfx/font_cache_task.rs @@ -71,13 +71,14 @@ impl FontFamily { /// Commands that the FontContext sends to the font cache task. pub enum Command { GetFontTemplate(String, FontTemplateDescriptor, Sender), + GetLastResortFontTemplate(FontTemplateDescriptor, Sender), AddWebFont(String, Url, Sender<()>), Exit(Sender<()>), } /// Reply messages sent from the font cache task to the FontContext caller. pub enum Reply { - GetFontTemplateReply(Arc), + GetFontTemplateReply(Option>), } /// The font cache task itself. It maintains a list of reference counted @@ -109,12 +110,11 @@ 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), - }; - - result.send(GetFontTemplateReply(font_template)); + result.send(GetFontTemplateReply(maybe_font_template)); + } + GetLastResortFontTemplate(descriptor, result) => { + let font_template = self.get_last_resort_font_template(&descriptor); + result.send(GetFontTemplateReply(Some(font_template))); } AddWebFont(family_name, url, result) => { let maybe_resource = load_whole_resource(&self.resource_task, url.clone()); @@ -197,7 +197,8 @@ impl FontCache { } } - fn get_font_template(&mut self, family: &String, desc: &FontTemplateDescriptor) -> Option> { + fn get_font_template(&mut self, family: &String, desc: &FontTemplateDescriptor) + -> Option> { let transformed_family_name = self.transform_family(family); let mut maybe_template = self.find_font_in_web_family(&transformed_family_name, desc); if maybe_template.is_none() { @@ -206,7 +207,8 @@ impl FontCache { maybe_template } - fn get_last_resort_template(&mut self, desc: &FontTemplateDescriptor) -> Arc { + fn get_last_resort_font_template(&mut self, desc: &FontTemplateDescriptor) + -> Arc { let last_resort = get_last_resort_font_families(); for family in last_resort.iter() { @@ -259,7 +261,7 @@ impl FontCacheTask { } pub fn get_font_template(&self, family: String, desc: FontTemplateDescriptor) - -> Arc { + -> Option> { let (response_chan, response_port) = channel(); self.chan.send(GetFontTemplate(family, desc, response_chan)); @@ -273,6 +275,21 @@ impl FontCacheTask { } } + pub fn get_last_resort_font_template(&self, desc: FontTemplateDescriptor) + -> Arc { + + let (response_chan, response_port) = channel(); + self.chan.send(GetLastResortFontTemplate(desc, response_chan)); + + let reply = response_port.recv(); + + match reply { + GetFontTemplateReply(data) => { + data.unwrap() + } + } + } + pub fn add_web_font(&self, family: String, url: Url) { let (response_chan, response_port) = channel(); self.chan.send(AddWebFont(family, url, response_chan)); diff --git a/components/gfx/font_context.rs b/components/gfx/font_context.rs index 42a67cf0151..261323b6df0 100644 --- a/components/gfx/font_context.rs +++ b/components/gfx/font_context.rs @@ -45,6 +45,10 @@ struct LayoutFontCacheEntry { font: Rc>, } +struct FallbackFontCacheEntry { + font: Rc>, +} + /// A cached azure font (per render task) that /// can be shared by multiple text runs. struct RenderFontCacheEntry { @@ -63,6 +67,7 @@ pub struct FontContext { /// TODO: See bug https://github.com/servo/servo/issues/3300. layout_font_cache: Vec, + fallback_font_cache: Vec, /// Strong reference as the render FontContext is (for now) recycled /// per frame. TODO: Make this weak when incremental redraw is done. @@ -76,6 +81,7 @@ impl FontContext { platform_handle: handle, font_cache_task: font_cache_task, layout_font_cache: vec!(), + fallback_font_cache: vec!(), render_font_cache: vec!(), } } @@ -116,11 +122,10 @@ impl FontContext { // TODO: The font context holds a strong ref to the cached fonts // so they will never be released. Find out a good time to drop them. + let desc = FontTemplateDescriptor::new(style.weight, style.style == font_style::italic); let mut fonts: Vec>> = vec!(); for family in style.families.iter() { - let desc = FontTemplateDescriptor::new(style.weight, style.style == font_style::italic); - // GWTODO: Check on real pages if this is faster as Vec() or HashMap(). let mut cache_hit = false; for cached_font_entry in self.layout_font_cache.iter() { @@ -138,10 +143,47 @@ impl FontContext { if !cache_hit { let font_template = self.font_cache_task.get_font_template(family.clone(), desc.clone()); - let layout_font = Rc::new(RefCell::new(self.create_layout_font(font_template, - desc.clone(), style.pt_size, style.variant))); - self.layout_font_cache.push(LayoutFontCacheEntry { - family: family.clone(), + match font_template { + Some(font_template) => { + let layout_font = self.create_layout_font(font_template, + desc.clone(), + style.pt_size, + style.variant); + let layout_font = Rc::new(RefCell::new(layout_font)); + self.layout_font_cache.push(LayoutFontCacheEntry { + family: family.clone(), + font: layout_font.clone(), + }); + fonts.push(layout_font); + } + None => {} + } + } + } + + // If unable to create any of the specified fonts, create one from the + // list of last resort fonts for this platform. + if fonts.len() == 0 { + let mut cache_hit = false; + for cached_font_entry in self.fallback_font_cache.iter() { + let cached_font = cached_font_entry.font.borrow(); + if cached_font.descriptor == desc && + cached_font.requested_pt_size == style.pt_size && + cached_font.variant == style.variant { + fonts.push(cached_font_entry.font.clone()); + cache_hit = true; + break; + } + } + + if !cache_hit { + let font_template = self.font_cache_task.get_last_resort_font_template(desc.clone()); + let layout_font = self.create_layout_font(font_template, + desc.clone(), + style.pt_size, + style.variant); + let layout_font = Rc::new(RefCell::new(layout_font)); + self.fallback_font_cache.push(FallbackFontCacheEntry { font: layout_font.clone(), }); fonts.push(layout_font);