aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/gfx/font_context.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/gfx/font_context.rs')
-rw-r--r--src/components/gfx/font_context.rs286
1 files changed, 105 insertions, 181 deletions
diff --git a/src/components/gfx/font_context.rs b/src/components/gfx/font_context.rs
index 9437e44299f..a9cccae61fb 100644
--- a/src/components/gfx/font_context.rs
+++ b/src/components/gfx/font_context.rs
@@ -2,223 +2,147 @@
* 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 font::{Font, FontDescriptor, FontGroup, FontHandleMethods, SelectorPlatformIdentifier};
-use font::{SpecifiedFontStyle, UsedFontStyle};
-use font_list::FontList;
-use platform::font::FontHandle;
+use font::{Font, FontGroup};
+use font::SpecifiedFontStyle;
use platform::font_context::FontContextHandle;
+use style::computed_values::font_style;
-use azure::azure_hl::BackendType;
-use std::collections::hashmap::HashMap;
-use servo_util::cache::{Cache, LRUCache};
-use servo_util::time::TimeProfilerChan;
+use font_cache_task::FontCacheTask;
+use font_template::FontTemplateDescriptor;
+use platform::font_template::FontTemplateData;
+use font::FontHandleMethods;
+use platform::font::FontHandle;
+use servo_util::cache::HashCache;
-use std::rc::Rc;
+use std::rc::{Rc, Weak};
use std::cell::RefCell;
+use sync::Arc;
-/// Information needed to create a font context.
-#[deriving(Clone)]
-pub struct FontContextInfo {
- /// The painting backend we're using.
- pub backend: BackendType,
+use azure::AzFloat;
+use azure::azure_hl::BackendType;
+use azure::scaled_font::ScaledFont;
+
+#[cfg(target_os="linux")]
+#[cfg(target_os="android")]
+use azure::scaled_font::FontData;
- /// Whether we need a font list.
- pub needs_font_list: bool,
+#[cfg(target_os="linux")]
+#[cfg(target_os="android")]
+fn create_scaled_font(backend: BackendType, template: &Arc<FontTemplateData>, pt_size: f64) -> ScaledFont {
+ ScaledFont::new(backend, FontData(&template.bytes), pt_size as AzFloat)
+}
- /// A channel up to the time profiler.
- pub time_profiler_chan: TimeProfilerChan,
+#[cfg(target_os="macos")]
+fn create_scaled_font(backend: BackendType, template: &Arc<FontTemplateData>, pt_size: f64) -> ScaledFont {
+ let cgfont = template.ctfont.copy_to_CGFont();
+ ScaledFont::new(backend, &cgfont, pt_size as AzFloat)
}
-pub trait FontContextHandleMethods {
- fn create_font_from_identifier(&self, &str, Option<&UsedFontStyle>) -> Result<FontHandle, ()>;
+/// A cached azure font (per render task) that
+/// can be shared by multiple text runs.
+struct RenderFontCacheEntry {
+ pt_size: f64,
+ identifier: String,
+ font: Rc<RefCell<ScaledFont>>,
}
+/// The FontContext represents the per-thread/task state necessary for
+/// working with fonts. It is the public API used by the layout and
+/// render code. It talks directly to the font cache task where
+/// required.
pub struct FontContext {
- pub instance_cache: LRUCache<FontDescriptor, Rc<RefCell<Font>>>,
- pub font_list: Option<FontList>, // only needed by layout
- pub group_cache: LRUCache<SpecifiedFontStyle, Rc<RefCell<FontGroup>>>,
- pub handle: FontContextHandle,
- pub backend: BackendType,
- pub generic_fonts: HashMap<String,String>,
- pub time_profiler_chan: TimeProfilerChan,
+ platform_handle: FontContextHandle,
+ font_cache_task: FontCacheTask,
+
+ /// Weak reference as the layout FontContext is persistent.
+ layout_font_cache: Vec<Weak<RefCell<Font>>>,
+
+ /// Strong reference as the render FontContext is (for now) recycled
+ /// per frame. TODO: Make this weak when incremental redraw is done.
+ render_font_cache: Vec<RenderFontCacheEntry>,
}
impl FontContext {
- pub fn new(info: FontContextInfo) -> FontContext {
+ pub fn new(font_cache_task: FontCacheTask) -> FontContext {
let handle = FontContextHandle::new();
- let font_list = if info.needs_font_list {
- Some(FontList::new(&handle, info.time_profiler_chan.clone()))
- } else {
- None
- };
-
- // TODO: Allow users to specify these.
- let mut generic_fonts = HashMap::with_capacity(5);
- generic_fonts.insert("serif".to_string(), "Times New Roman".to_string());
- generic_fonts.insert("sans-serif".to_string(), "Arial".to_string());
- generic_fonts.insert("cursive".to_string(), "Apple Chancery".to_string());
- generic_fonts.insert("fantasy".to_string(), "Papyrus".to_string());
- generic_fonts.insert("monospace".to_string(), "Menlo".to_string());
-
FontContext {
- instance_cache: LRUCache::new(10),
- font_list: font_list,
- group_cache: LRUCache::new(10),
- handle: handle,
- backend: info.backend,
- generic_fonts: generic_fonts,
- time_profiler_chan: info.time_profiler_chan.clone(),
+ platform_handle: handle,
+ font_cache_task: font_cache_task,
+ layout_font_cache: vec!(),
+ render_font_cache: vec!(),
}
}
- pub fn get_resolved_font_for_style(&mut self, style: &SpecifiedFontStyle)
- -> Rc<RefCell<FontGroup>> {
- match self.group_cache.find(style) {
- Some(fg) => {
- debug!("font group cache hit");
- fg
- },
- None => {
- debug!("font group cache miss");
- let fg = self.create_font_group(style);
- self.group_cache.insert(style.clone(), fg.clone());
- fg
- }
- }
- }
+ /// Create a font for use in layout calculations.
+ fn create_layout_font(&self, template: Arc<FontTemplateData>,
+ descriptor: FontTemplateDescriptor, pt_size: f64) -> Font {
- pub fn get_font_by_descriptor(&mut self, desc: &FontDescriptor)
- -> Result<Rc<RefCell<Font>>, ()> {
- match self.instance_cache.find(desc) {
- Some(f) => {
- debug!("font cache hit");
- Ok(f)
- },
- None => {
- debug!("font cache miss");
- let result = self.create_font_instance(desc);
- match result.clone() {
- Ok(ref font) => {
- self.instance_cache.insert(desc.clone(), font.clone());
- }, _ => {}
- };
- result
- }
- }
- }
+ let handle: FontHandle = FontHandleMethods::new_from_template(&self.platform_handle, template, Some(pt_size)).unwrap();
+ let metrics = handle.get_metrics();
- fn transform_family(&self, family: &String) -> String {
- debug!("(transform family) searching for `{:s}`", family.as_slice());
- match self.generic_fonts.find(family) {
- None => family.to_string(),
- Some(mapped_family) => (*mapped_family).clone()
+ Font {
+ handle: handle,
+ shaper: None,
+ descriptor: descriptor,
+ pt_size: pt_size,
+ metrics: metrics,
+ shape_cache: HashCache::new(),
+ glyph_advance_cache: HashCache::new(),
}
}
- fn create_font_group(&mut self, style: &SpecifiedFontStyle) -> Rc<RefCell<FontGroup>> {
- let mut fonts = vec!();
+ /// Create a group of fonts for use in layout calculations. May return
+ /// a cached font if this font instance has already been used by
+ /// this context.
+ pub fn get_layout_font_group_for_style(&mut self, style: &SpecifiedFontStyle) -> FontGroup {
+ // Remove all weak pointers that have been dropped.
+ self.layout_font_cache.retain(|maybe_font| {
+ maybe_font.upgrade().is_some()
+ });
- debug!("(create font group) --- starting ---");
+ let mut fonts: Vec<Rc<RefCell<Font>>> = vec!();
- // TODO(Issue #193): make iteration over 'font-family' more robust.
for family in style.families.iter() {
- let transformed_family_name = self.transform_family(family);
- debug!("(create font group) transformed family is `{:s}`", transformed_family_name);
- let mut found = false;
-
- let result = match self.font_list {
- Some(ref mut fl) => {
- let font_in_family = fl.find_font_in_family(&self.handle, &transformed_family_name, style);
- match font_in_family {
- Some(font_entry) => {
- let font_id =
- SelectorPlatformIdentifier(font_entry.handle.face_identifier());
- let font_desc = FontDescriptor::new((*style).clone(), font_id);
- Some(font_desc)
- },
- None => {
- None
- }
- }
+ 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 maybe_cached_font in self.layout_font_cache.iter() {
+ let cached_font = maybe_cached_font.upgrade().unwrap();
+ if cached_font.borrow().descriptor == desc {
+ fonts.push(cached_font.clone());
+ cache_hit = true;
+ break;
}
- None => None,
- };
-
- match result {
- Some(ref result) => {
- found = true;
- let instance = self.get_font_by_descriptor(result);
- let _ = instance.map(|font| fonts.push(font.clone()));
- },
- _ => {}
}
- if !found {
- debug!("(create font group) didn't find `{:s}`", transformed_family_name);
+ 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)));
+ self.layout_font_cache.push(layout_font.downgrade());
+ fonts.push(layout_font);
}
}
- if fonts.len() == 0 {
- let last_resort = FontList::get_last_resort_font_families();
- for family in last_resort.iter() {
- let font_desc = match self.font_list {
- Some(ref mut font_list) => {
- let font_desc = {
- let font_entry = font_list.find_font_in_family(&self.handle, family, style);
- match font_entry {
- Some(v) => {
- let font_id =
- SelectorPlatformIdentifier(v.handle.face_identifier());
- Some(FontDescriptor::new((*style).clone(), font_id))
- },
- None => {
- None
- }
- }
- };
- font_desc
- },
- None => {
- None
- }
- };
-
- match font_desc {
- Some(ref fd) => {
- let instance = self.get_font_by_descriptor(fd);
- let _ = instance.map(|font| fonts.push(font.clone()));
- },
- None => { }
- };
- }
- }
- assert!(fonts.len() > 0, "No matching font(s), are the appropriate fonts installed?");
- // TODO(Issue #179): Split FontStyle into specified and used styles
- let used_style = (*style).clone();
-
- debug!("(create font group) --- finished ---");
-
- Rc::new(
- RefCell::new(
- FontGroup::new(style.families.clone(), &used_style, fonts)))
+ FontGroup::new(fonts)
}
- fn create_font_instance(&self, desc: &FontDescriptor) -> Result<Rc<RefCell<Font>>, ()> {
- return match &desc.selector {
- // TODO(Issue #174): implement by-platform-name font selectors.
- &SelectorPlatformIdentifier(ref identifier) => {
- let result_handle = self.handle.create_font_from_identifier(identifier.as_slice(),
- Some(&desc.style));
- result_handle.and_then(|handle| {
- Ok(
- Rc::new(
- RefCell::new(
- Font::new_from_adopted_handle(self,
- handle,
- &desc.style,
- self.backend))))
- })
+ /// Create a render font for use with azure. May return a cached
+ /// reference if already used by this font context.
+ pub fn get_render_font_from_template(&mut self, template: &Arc<FontTemplateData>, pt_size: f64, backend: BackendType) -> Rc<RefCell<ScaledFont>> {
+ for cached_font in self.render_font_cache.iter() {
+ if cached_font.pt_size == pt_size &&
+ cached_font.identifier == template.identifier {
+ return cached_font.font.clone();
}
- };
+ }
+
+ let render_font = Rc::new(RefCell::new(create_scaled_font(backend, template, pt_size)));
+ self.render_font_cache.push(RenderFontCacheEntry{
+ font: render_font.clone(),
+ pt_size: pt_size,
+ identifier: template.identifier.clone(),
+ });
+ render_font
}
}