aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/components/compositing/constellation.rs10
-rw-r--r--src/components/compositing/pipeline.rs7
-rw-r--r--src/components/gfx/display_list/mod.rs110
-rw-r--r--src/components/gfx/font.rs352
-rw-r--r--src/components/gfx/font_cache_task.rs213
-rw-r--r--src/components/gfx/font_context.rs286
-rw-r--r--src/components/gfx/font_list.rs162
-rw-r--r--src/components/gfx/font_template.rs115
-rw-r--r--src/components/gfx/gfx.rs9
-rw-r--r--src/components/gfx/platform/android/font.rs78
-rw-r--r--src/components/gfx/platform/android/font_context.rs13
-rw-r--r--src/components/gfx/platform/android/font_list.rs2
-rw-r--r--src/components/gfx/platform/android/font_template.rs28
-rw-r--r--src/components/gfx/platform/linux/font.rs76
-rw-r--r--src/components/gfx/platform/linux/font_context.rs13
-rw-r--r--src/components/gfx/platform/linux/font_list.rs2
-rw-r--r--src/components/gfx/platform/linux/font_template.rs28
-rw-r--r--src/components/gfx/platform/macos/font.rs61
-rw-r--r--src/components/gfx/platform/macos/font_context.rs22
-rw-r--r--src/components/gfx/platform/macos/font_list.rs2
-rw-r--r--src/components/gfx/platform/macos/font_template.rs25
-rw-r--r--src/components/gfx/platform/mod.rs9
-rw-r--r--src/components/gfx/render_task.rs12
-rw-r--r--src/components/gfx/text/shaping/harfbuzz.rs2
-rw-r--r--src/components/gfx/text/text_run.rs14
-rw-r--r--src/components/layout/context.rs11
-rw-r--r--src/components/layout/layout_task.rs20
-rw-r--r--src/components/layout/text.rs12
-rw-r--r--src/components/main/servo.rs5
29 files changed, 806 insertions, 893 deletions
diff --git a/src/components/compositing/constellation.rs b/src/components/compositing/constellation.rs
index f6d12ebcedd..a243bf4f3ee 100644
--- a/src/components/compositing/constellation.rs
+++ b/src/components/compositing/constellation.rs
@@ -22,6 +22,7 @@ use servo_msg::constellation_msg::{NavigationType, PipelineId, RendererReadyMsg,
use servo_msg::constellation_msg::{SubpageId, WindowSizeData};
use servo_msg::constellation_msg;
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
+use gfx::font_cache_task::FontCacheTask;
use servo_net::resource_task::ResourceTask;
use servo_net::resource_task;
use servo_util::geometry::PagePx;
@@ -43,6 +44,7 @@ pub struct Constellation {
pub resource_task: ResourceTask,
pub image_cache_task: ImageCacheTask,
pipelines: HashMap<PipelineId, Rc<Pipeline>>,
+ font_cache_task: FontCacheTask,
navigation_context: NavigationContext,
next_pipeline_id: PipelineId,
pending_frames: Vec<FrameChange>,
@@ -243,6 +245,7 @@ impl Constellation {
opts: &Opts,
resource_task: ResourceTask,
image_cache_task: ImageCacheTask,
+ font_cache_task: FontCacheTask,
time_profiler_chan: TimeProfilerChan)
-> ConstellationChan {
let (constellation_port, constellation_chan) = ConstellationChan::new();
@@ -255,6 +258,7 @@ impl Constellation {
compositor_chan: compositor_chan,
resource_task: resource_task,
image_cache_task: image_cache_task,
+ font_cache_task: font_cache_task,
pipelines: HashMap::new(),
navigation_context: NavigationContext::new(),
next_pipeline_id: PipelineId(0),
@@ -368,6 +372,7 @@ impl Constellation {
}
self.image_cache_task.exit();
self.resource_task.send(resource_task::Exit);
+ self.font_cache_task.exit();
self.compositor_chan.send(ShutdownComplete);
}
@@ -422,6 +427,7 @@ impl Constellation {
self.chan.clone(),
self.compositor_chan.clone(),
self.image_cache_task.clone(),
+ self.font_cache_task.clone(),
self.resource_task.clone(),
self.time_profiler_chan.clone(),
self.window_size,
@@ -449,6 +455,7 @@ impl Constellation {
self.chan.clone(),
self.compositor_chan.clone(),
self.image_cache_task.clone(),
+ self.font_cache_task.clone(),
self.resource_task.clone(),
self.time_profiler_chan.clone(),
self.window_size,
@@ -575,6 +582,7 @@ impl Constellation {
self.chan.clone(),
self.compositor_chan.clone(),
self.image_cache_task.clone(),
+ self.font_cache_task.clone(),
self.time_profiler_chan.clone(),
self.opts.clone(),
source_pipeline.clone(),
@@ -587,6 +595,7 @@ impl Constellation {
self.chan.clone(),
self.compositor_chan.clone(),
self.image_cache_task.clone(),
+ self.font_cache_task.clone(),
self.resource_task.clone(),
self.time_profiler_chan.clone(),
self.window_size,
@@ -643,6 +652,7 @@ impl Constellation {
self.chan.clone(),
self.compositor_chan.clone(),
self.image_cache_task.clone(),
+ self.font_cache_task.clone(),
self.resource_task.clone(),
self.time_profiler_chan.clone(),
self.window_size,
diff --git a/src/components/compositing/pipeline.rs b/src/components/compositing/pipeline.rs
index cabf2984b15..dbd054feb55 100644
--- a/src/components/compositing/pipeline.rs
+++ b/src/components/compositing/pipeline.rs
@@ -14,6 +14,7 @@ use script::script_task;
use servo_msg::constellation_msg::{ConstellationChan, Failure, PipelineId, SubpageId};
use servo_msg::constellation_msg::WindowSizeData;
use servo_net::image_cache_task::ImageCacheTask;
+use gfx::font_cache_task::FontCacheTask;
use servo_net::resource_task::ResourceTask;
use servo_util::opts::Opts;
use servo_util::time::TimeProfilerChan;
@@ -49,6 +50,7 @@ impl Pipeline {
constellation_chan: ConstellationChan,
compositor_chan: CompositorChan,
image_cache_task: ImageCacheTask,
+ font_cache_task: FontCacheTask,
time_profiler_chan: TimeProfilerChan,
opts: Opts,
script_pipeline: Rc<Pipeline>,
@@ -68,6 +70,7 @@ impl Pipeline {
render_port,
compositor_chan.clone(),
constellation_chan.clone(),
+ font_cache_task.clone(),
failure.clone(),
opts.clone(),
time_profiler_chan.clone(),
@@ -81,6 +84,7 @@ impl Pipeline {
script_pipeline.script_chan.clone(),
render_chan.clone(),
image_cache_task.clone(),
+ font_cache_task.clone(),
opts.clone(),
time_profiler_chan,
layout_shutdown_chan);
@@ -110,6 +114,7 @@ impl Pipeline {
constellation_chan: ConstellationChan,
compositor_chan: CompositorChan,
image_cache_task: ImageCacheTask,
+ font_cache_task: FontCacheTask,
resource_task: ResourceTask,
time_profiler_chan: TimeProfilerChan,
window_size: WindowSizeData,
@@ -150,6 +155,7 @@ impl Pipeline {
render_port,
compositor_chan.clone(),
constellation_chan.clone(),
+ font_cache_task.clone(),
failure.clone(),
opts.clone(),
time_profiler_chan.clone(),
@@ -163,6 +169,7 @@ impl Pipeline {
script_chan.clone(),
render_chan.clone(),
image_cache_task,
+ font_cache_task,
opts.clone(),
time_profiler_chan,
layout_shutdown_chan);
diff --git a/src/components/gfx/display_list/mod.rs b/src/components/gfx/display_list/mod.rs
index 15d39896051..355eab40223 100644
--- a/src/components/gfx/display_list/mod.rs
+++ b/src/components/gfx/display_list/mod.rs
@@ -32,6 +32,12 @@ use std::mem;
use std::slice::Items;
use style::computed_values::border_style;
use sync::Arc;
+use std::num::Zero;
+use std::ptr;
+
+use azure::AzFloat;
+use azure::scaled_font::ScaledFont;
+use azure::azure_hl::ColorPattern;
pub mod optimizer;
@@ -52,6 +58,80 @@ impl OpaqueNode {
}
}
+trait ScaledFontExtensionMethods {
+ fn draw_text_into_context(&self,
+ rctx: &RenderContext,
+ run: &Box<TextRun>,
+ range: &Range<CharIndex>,
+ baseline_origin: Point2D<Au>,
+ color: Color);
+}
+
+impl ScaledFontExtensionMethods for ScaledFont {
+ fn draw_text_into_context(&self,
+ rctx: &RenderContext,
+ run: &Box<TextRun>,
+ range: &Range<CharIndex>,
+ baseline_origin: Point2D<Au>,
+ color: Color) {
+ use libc::types::common::c99::{uint16_t, uint32_t};
+ use azure::{struct__AzDrawOptions,
+ struct__AzGlyph,
+ struct__AzGlyphBuffer,
+ struct__AzPoint};
+ use azure::azure::{AzDrawTargetFillGlyphs};
+
+ let target = rctx.get_draw_target();
+ let pattern = ColorPattern::new(color);
+ let azure_pattern = pattern.azure_color_pattern;
+ assert!(azure_pattern.is_not_null());
+
+ let options = struct__AzDrawOptions {
+ mAlpha: 1f64 as AzFloat,
+ fields: 0x0200 as uint16_t
+ };
+
+ let mut origin = baseline_origin.clone();
+ let mut azglyphs = vec!();
+ azglyphs.reserve(range.length().to_uint());
+
+ for (glyphs, _offset, slice_range) in run.iter_slices_for_range(range) {
+ for (_i, glyph) in glyphs.iter_glyphs_for_char_range(&slice_range) {
+ let glyph_advance = glyph.advance();
+ let glyph_offset = glyph.offset().unwrap_or(Zero::zero());
+
+ let azglyph = struct__AzGlyph {
+ mIndex: glyph.id() as uint32_t,
+ mPosition: struct__AzPoint {
+ x: (origin.x + glyph_offset.x).to_nearest_px() as AzFloat,
+ y: (origin.y + glyph_offset.y).to_nearest_px() as AzFloat
+ }
+ };
+ origin = Point2D(origin.x + glyph_advance, origin.y);
+ azglyphs.push(azglyph)
+ };
+ }
+
+ let azglyph_buf_len = azglyphs.len();
+ if azglyph_buf_len == 0 { return; } // Otherwise the Quartz backend will assert.
+
+ let glyphbuf = struct__AzGlyphBuffer {
+ mGlyphs: azglyphs.as_ptr(),
+ mNumGlyphs: azglyph_buf_len as uint32_t
+ };
+
+ unsafe {
+ // TODO(Issue #64): this call needs to move into azure_hl.rs
+ AzDrawTargetFillGlyphs(target.azure_draw_target,
+ self.get_ref(),
+ &glyphbuf,
+ azure_pattern,
+ &options,
+ ptr::null());
+ }
+ }
+}
+
/// "Steps" as defined by CSS 2.1 § E.2.
#[deriving(Clone, PartialEq)]
pub enum StackingLevel {
@@ -510,25 +590,27 @@ impl DisplayItem {
// FIXME(pcwalton): Allocating? Why?
let text_run = text.text_run.clone();
- let font = render_context.font_ctx.get_font_by_descriptor(&text_run.font_descriptor).unwrap();
- let font_metrics = {
- font.borrow().metrics.clone()
- };
+ let font = render_context.font_ctx.get_render_font_from_template(
+ &text_run.font_template,
+ text_run.pt_size,
+ render_context.opts.render_backend);
+ let font = font.borrow();
+
let origin = text.base.bounds.origin;
- let baseline_origin = Point2D(origin.x, origin.y + font_metrics.ascent);
+ let baseline_origin = Point2D(origin.x, origin.y + text_run.font_metrics.ascent);
{
- font.borrow_mut().draw_text_into_context(render_context,
- &*text.text_run,
- &text.range,
- baseline_origin,
- text.text_color);
+ font.draw_text_into_context(render_context,
+ &*text.text_run,
+ &text.range,
+ baseline_origin,
+ text.text_color);
}
let width = text.base.bounds.size.width;
- let underline_size = font_metrics.underline_size;
- let underline_offset = font_metrics.underline_offset;
- let strikeout_size = font_metrics.strikeout_size;
- let strikeout_offset = font_metrics.strikeout_offset;
+ let underline_size = text_run.font_metrics.underline_size;
+ let underline_offset = text_run.font_metrics.underline_offset;
+ let strikeout_size = text_run.font_metrics.strikeout_size;
+ let strikeout_offset = text_run.font_metrics.strikeout_offset;
for underline_color in text.text_decorations.underline.iter() {
let underline_y = baseline_origin.y - underline_offset;
diff --git a/src/components/gfx/font.rs b/src/components/gfx/font.rs
index 98c356514eb..2630b018190 100644
--- a/src/components/gfx/font.rs
+++ b/src/components/gfx/font.rs
@@ -2,34 +2,23 @@
* 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 azure::{AzFloat, AzScaledFontRef};
-use azure::azure_hl::{BackendType, ColorPattern};
-use azure::scaled_font::ScaledFont;
use geom::{Point2D, Rect, Size2D};
use std::mem;
-use std::num::Zero;
-use std::ptr;
use std::str;
use std::rc::Rc;
use std::cell::RefCell;
use servo_util::cache::{Cache, HashCache};
-use servo_util::range::Range;
use style::computed_values::{text_decoration, font_weight, font_style};
use sync::Arc;
-use color::Color;
-use font_context::FontContext;
use servo_util::geometry::Au;
use platform::font_context::FontContextHandle;
use platform::font::{FontHandle, FontTable};
-use render_context::RenderContext;
-use text::glyph::{CharIndex, GlyphStore, GlyphId};
+use text::glyph::{GlyphStore, GlyphId};
use text::shaping::ShaperMethods;
use text::{Shaper, TextRun};
-
-#[cfg(target_os="linux")]
-#[cfg(target_os="android")]
-use azure::scaled_font::NativeFont;
+use font_template::FontTemplateDescriptor;
+use platform::font_template::FontTemplateData;
// FontHandle encapsulates access to the platform's font API,
// e.g. quartz, FreeType. It provides access to metrics and tables
@@ -37,11 +26,9 @@ use azure::scaled_font::NativeFont;
// resources needed by the graphics layer to draw glyphs.
pub trait FontHandleMethods {
- fn new_from_buffer(fctx: &FontContextHandle, buf: Vec<u8>, style: &SpecifiedFontStyle)
+ fn new_from_template(fctx: &FontContextHandle, template: Arc<FontTemplateData>, pt_size: Option<f64>)
-> Result<Self,()>;
-
- // an identifier usable by FontContextHandle to recreate this FontHandle.
- fn face_identifier(&self) -> String;
+ fn get_template(&self) -> Arc<FontTemplateData>;
fn family_name(&self) -> String;
fn face_name(&self) -> String;
fn is_italic(&self) -> bool;
@@ -110,152 +97,30 @@ pub struct FontStyle {
pub type SpecifiedFontStyle = FontStyle;
pub type UsedFontStyle = FontStyle;
-// FontDescriptor serializes a specific font and used font style
-// options, such as point size.
-
-// It's used to swizzle/unswizzle gfx::Font instances when
-// communicating across tasks, such as the display list between layout
-// and render tasks.
-#[deriving(Clone, PartialEq)]
-pub struct FontDescriptor {
- pub style: UsedFontStyle,
- pub selector: FontSelector,
-}
-
-impl FontDescriptor {
- pub fn new(style: UsedFontStyle, selector: FontSelector) -> FontDescriptor {
- FontDescriptor {
- style: style,
- selector: selector,
- }
- }
-}
-
-// A FontSelector is a platform-specific strategy for serializing face names.
-#[deriving(Clone, PartialEq)]
-pub enum FontSelector {
- SelectorPlatformIdentifier(String),
-}
-
-// This struct is the result of mapping a specified FontStyle into the
-// available fonts on the system. It contains an ordered list of font
-// instances to be used in case the prior font cannot be used for
-// rendering the specified language.
-
-// The ordering of font instances is mainly decided by the CSS
-// 'font-family' property. The last font is a system fallback font.
-pub struct FontGroup {
- pub families: Vec<String>,
- // style of the first western font in group, which is
- // used for purposes of calculating text run metrics.
- pub style: UsedFontStyle,
- pub fonts: Vec<Rc<RefCell<Font>>>
-}
-
-impl FontGroup {
- pub fn new(families: Vec<String>, style: &UsedFontStyle, fonts: Vec<Rc<RefCell<Font>>>) -> FontGroup {
- FontGroup {
- families: families,
- style: (*style).clone(),
- fonts: fonts,
- }
- }
-
- pub fn create_textrun(&self, text: String, decoration: text_decoration::T) -> TextRun {
- assert!(self.fonts.len() > 0);
-
- // TODO(Issue #177): Actually fall back through the FontGroup when a font is unsuitable.
- TextRun::new(&mut *self.fonts.get(0).borrow_mut(), text.clone(), decoration)
- }
-}
-
-pub struct RunMetrics {
- // may be negative due to negative width (i.e., kerning of '.' in 'P.T.')
- pub advance_width: Au,
- pub ascent: Au, // nonzero
- pub descent: Au, // nonzero
- // this bounding box is relative to the left origin baseline.
- // so, bounding_box.position.y = -ascent
- pub bounding_box: Rect<Au>
-}
-
-impl RunMetrics {
- pub fn new(advance: Au, ascent: Au, descent: Au) -> RunMetrics {
- let bounds = Rect(Point2D(Au(0), -ascent),
- Size2D(advance, ascent + descent));
-
- // TODO(Issue #125): support loose and tight bounding boxes; using the
- // ascent+descent and advance is sometimes too generous and
- // looking at actual glyph extents can yield a tighter box.
-
- RunMetrics {
- advance_width: advance,
- bounding_box: bounds,
- ascent: ascent,
- descent: descent,
- }
- }
-}
-
-/**
-A font instance. Layout can use this to calculate glyph metrics
-and the renderer can use it to render text.
-*/
pub struct Font {
pub handle: FontHandle,
- pub azure_font: Option<ScaledFont>,
- pub shaper: Option<Shaper>,
- pub style: UsedFontStyle,
pub metrics: FontMetrics,
- pub backend: BackendType,
+ pub descriptor: FontTemplateDescriptor,
+ pub pt_size: f64,
+ pub shaper: Option<Shaper>,
pub shape_cache: HashCache<String, Arc<GlyphStore>>,
pub glyph_advance_cache: HashCache<u32, FractionalPixel>,
}
-impl<'a> Font {
- pub fn new_from_buffer(ctx: &FontContext,
- buffer: Vec<u8>,
- style: &SpecifiedFontStyle,
- backend: BackendType)
- -> Result<Rc<RefCell<Font>>, ()> {
- let handle = FontHandleMethods::new_from_buffer(&ctx.handle, buffer, style);
- let handle: FontHandle = match handle {
- Ok(handle) => handle,
- Err(()) => return Err(()),
- };
-
- let metrics = handle.get_metrics();
-
- return Ok(Rc::new(RefCell::new(Font {
- handle: handle,
- azure_font: None,
- shaper: None,
- style: (*style).clone(),
- metrics: metrics,
- backend: backend,
- shape_cache: HashCache::new(),
- glyph_advance_cache: HashCache::new(),
- })));
- }
-
- pub fn new_from_adopted_handle(_fctx: &FontContext, handle: FontHandle,
- style: &SpecifiedFontStyle, backend: BackendType)
- -> Font {
- let metrics = handle.get_metrics();
+impl Font {
+ pub fn shape_text(&mut self, text: String, is_whitespace: bool) -> Arc<GlyphStore> {
- Font {
- handle: handle,
- azure_font: None,
- shaper: None,
- style: (*style).clone(),
- metrics: metrics,
- backend: backend,
- shape_cache: HashCache::new(),
- glyph_advance_cache: HashCache::new(),
- }
+ //FIXME (ksh8281)
+ self.make_shaper();
+ let shaper = &self.shaper;
+ self.shape_cache.find_or_create(&text, |txt| {
+ let mut glyphs = GlyphStore::new(text.as_slice().char_len() as int, is_whitespace);
+ shaper.get_ref().shape_text(txt.as_slice(), &mut glyphs);
+ Arc::new(glyphs)
+ })
}
- fn make_shaper(&'a mut self) -> &'a Shaper {
+ fn make_shaper<'a>(&'a mut self) -> &'a Shaper {
// fast path: already created a shaper
match self.shaper {
Some(ref shaper) => {
@@ -281,155 +146,64 @@ impl<'a> Font {
return result;
}
- // TODO: this should return a borrowed pointer, but I can't figure
- // out why borrowck doesn't like my implementation.
-
- fn get_azure_font(&mut self) -> AzScaledFontRef {
- // fast path: we've already created the azure font resource
- match self.azure_font {
- Some(ref azfont) => return azfont.get_ref(),
- None => {}
- }
-
- let scaled_font = self.create_azure_font();
- self.azure_font = Some(scaled_font);
- // try again.
- return self.get_azure_font();
- }
-
- #[cfg(target_os="macos")]
- fn create_azure_font(&mut self) -> ScaledFont {
- let cg_font = self.handle.get_CGFont();
- let size = self.style.pt_size as AzFloat;
- ScaledFont::new(self.backend, &cg_font, size)
+ pub fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
+ self.handle.glyph_index(codepoint)
}
- #[cfg(target_os="linux")]
- #[cfg(target_os="android")]
- fn create_azure_font(&self) -> ScaledFont {
- let freetype_font = self.handle.face;
- let size = self.style.pt_size as AzFloat;
- ScaledFont::new(self.backend, NativeFont(freetype_font), size)
+ pub fn glyph_h_advance(&mut self, glyph: GlyphId) -> FractionalPixel {
+ let handle = &self.handle;
+ self.glyph_advance_cache.find_or_create(&glyph, |glyph| {
+ match handle.glyph_h_advance(*glyph) {
+ Some(adv) => adv,
+ None => 10f64 as FractionalPixel // FIXME: Need fallback strategy
+ }
+ })
}
}
+pub struct FontGroup {
+ pub fonts: Vec<Rc<RefCell<Font>>>,
+}
-impl Font {
- pub fn draw_text_into_context(&mut self,
- rctx: &RenderContext,
- run: &Box<TextRun>,
- range: &Range<CharIndex>,
- baseline_origin: Point2D<Au>,
- color: Color) {
- use libc::types::common::c99::{uint16_t, uint32_t};
- use azure::{struct__AzDrawOptions,
- struct__AzGlyph,
- struct__AzGlyphBuffer,
- struct__AzPoint};
- use azure::azure::{AzDrawTargetFillGlyphs};
-
- let target = rctx.get_draw_target();
- let azfontref = self.get_azure_font();
- let pattern = ColorPattern::new(color);
- let azure_pattern = pattern.azure_color_pattern;
- assert!(azure_pattern.is_not_null());
-
- let options = struct__AzDrawOptions {
- mAlpha: 1f64 as AzFloat,
- fields: 0x0200 as uint16_t
- };
-
- let mut origin = baseline_origin.clone();
- let mut azglyphs = vec!();
- azglyphs.reserve(range.length().to_uint());
-
- for (glyphs, _offset, slice_range) in run.iter_slices_for_range(range) {
- for (_i, glyph) in glyphs.iter_glyphs_for_char_range(&slice_range) {
- let glyph_advance = glyph.advance();
- let glyph_offset = glyph.offset().unwrap_or(Zero::zero());
-
- let azglyph = struct__AzGlyph {
- mIndex: glyph.id() as uint32_t,
- mPosition: struct__AzPoint {
- x: (origin.x + glyph_offset.x).to_nearest_px() as AzFloat,
- y: (origin.y + glyph_offset.y).to_nearest_px() as AzFloat
- }
- };
- origin = Point2D(origin.x + glyph_advance, origin.y);
- azglyphs.push(azglyph)
- };
- }
-
- let azglyph_buf_len = azglyphs.len();
- if azglyph_buf_len == 0 { return; } // Otherwise the Quartz backend will assert.
-
- let glyphbuf = struct__AzGlyphBuffer {
- mGlyphs: azglyphs.as_ptr(),
- mNumGlyphs: azglyph_buf_len as uint32_t
- };
-
- unsafe {
- // TODO(Issue #64): this call needs to move into azure_hl.rs
- AzDrawTargetFillGlyphs(target.azure_draw_target,
- azfontref,
- &glyphbuf,
- azure_pattern,
- &options,
- ptr::null());
+impl FontGroup {
+ pub fn new(fonts: Vec<Rc<RefCell<Font>>>) -> FontGroup {
+ FontGroup {
+ fonts: fonts
}
}
- pub fn measure_text(&self, run: &TextRun, range: &Range<CharIndex>) -> RunMetrics {
- // TODO(Issue #199): alter advance direction for RTL
- // TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text
- let mut advance = Au(0);
- for (glyphs, _offset, slice_range) in run.iter_slices_for_range(range) {
- for (_i, glyph) in glyphs.iter_glyphs_for_char_range(&slice_range) {
- advance = advance + glyph.advance();
- }
- }
- RunMetrics::new(advance, self.metrics.ascent, self.metrics.descent)
- }
+ pub fn create_textrun(&self, text: String, decoration: text_decoration::T) -> TextRun {
+ assert!(self.fonts.len() > 0);
- pub fn measure_text_for_slice(&self,
- glyphs: &GlyphStore,
- slice_range: &Range<CharIndex>)
- -> RunMetrics {
- let mut advance = Au(0);
- for (_i, glyph) in glyphs.iter_glyphs_for_char_range(slice_range) {
- advance = advance + glyph.advance();
- }
- RunMetrics::new(advance, self.metrics.ascent, self.metrics.descent)
+ // TODO(Issue #177): Actually fall back through the FontGroup when a font is unsuitable.
+ TextRun::new(&mut *self.fonts.get(0).borrow_mut(), text.clone(), decoration)
}
+}
- pub fn shape_text(&mut self, text: String, is_whitespace: bool) -> Arc<GlyphStore> {
-
- //FIXME (ksh8281)
- self.make_shaper();
- let shaper = &self.shaper;
- self.shape_cache.find_or_create(&text, |txt| {
- let mut glyphs = GlyphStore::new(text.as_slice().char_len() as int, is_whitespace);
- shaper.get_ref().shape_text(txt.as_slice(), &mut glyphs);
- Arc::new(glyphs)
- })
- }
+pub struct RunMetrics {
+ // may be negative due to negative width (i.e., kerning of '.' in 'P.T.')
+ pub advance_width: Au,
+ pub ascent: Au, // nonzero
+ pub descent: Au, // nonzero
+ // this bounding box is relative to the left origin baseline.
+ // so, bounding_box.position.y = -ascent
+ pub bounding_box: Rect<Au>
+}
- pub fn get_descriptor(&self) -> FontDescriptor {
- FontDescriptor::new(self.style.clone(), SelectorPlatformIdentifier(self.handle.face_identifier()))
- }
+impl RunMetrics {
+ pub fn new(advance: Au, ascent: Au, descent: Au) -> RunMetrics {
+ let bounds = Rect(Point2D(Au(0), -ascent),
+ Size2D(advance, ascent + descent));
- pub fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
- self.handle.glyph_index(codepoint)
- }
+ // TODO(Issue #125): support loose and tight bounding boxes; using the
+ // ascent+descent and advance is sometimes too generous and
+ // looking at actual glyph extents can yield a tighter box.
- pub fn glyph_h_advance(&mut self, glyph: GlyphId) -> FractionalPixel {
- let handle = &self.handle;
- self.glyph_advance_cache.find_or_create(&glyph, |glyph| {
- match handle.glyph_h_advance(*glyph) {
- Some(adv) => adv,
- None => /* FIXME: Need fallback strategy */ 10f64 as FractionalPixel
- }
- })
+ RunMetrics {
+ advance_width: advance,
+ bounding_box: bounds,
+ ascent: ascent,
+ descent: descent,
+ }
}
}
-
diff --git a/src/components/gfx/font_cache_task.rs b/src/components/gfx/font_cache_task.rs
new file mode 100644
index 00000000000..55e2dad003e
--- /dev/null
+++ b/src/components/gfx/font_cache_task.rs
@@ -0,0 +1,213 @@
+/* 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 platform::font_list::get_available_families;
+use platform::font_list::get_variations_for_family;
+use platform::font_list::get_last_resort_font_families;
+use platform::font_context::FontContextHandle;
+
+use std::collections::HashMap;
+use sync::Arc;
+use font_template::{FontTemplate, FontTemplateDescriptor};
+use platform::font_template::FontTemplateData;
+
+/// A list of font templates that make up a given font family.
+struct FontFamily {
+ templates: Vec<FontTemplate>,
+}
+
+impl FontFamily {
+ fn new() -> FontFamily {
+ FontFamily {
+ templates: vec!(),
+ }
+ }
+
+ /// Find a font in this family that matches a given desriptor.
+ fn find_font_for_style<'a>(&'a mut self, desc: &FontTemplateDescriptor, fctx: &FontContextHandle)
+ -> Option<Arc<FontTemplateData>> {
+ // TODO(Issue #189): optimize lookup for
+ // regular/bold/italic/bolditalic with fixed offsets and a
+ // static decision table for fallback between these values.
+
+ // TODO(Issue #190): if not in the fast path above, do
+ // expensive matching of weights, etc.
+ for template in self.templates.mut_iter() {
+ let maybe_template = template.get_if_matches(fctx, desc);
+ if maybe_template.is_some() {
+ return maybe_template;
+ }
+ }
+
+ None
+ }
+}
+
+/// Commands that the FontContext sends to the font cache task.
+pub enum Command {
+ GetFontTemplate(String, FontTemplateDescriptor, Sender<Reply>),
+ Exit(Sender<()>),
+}
+
+/// Reply messages sent from the font cache task to the FontContext caller.
+pub enum Reply {
+ GetFontTemplateReply(Arc<FontTemplateData>),
+}
+
+/// The font cache task itself. It maintains a list of reference counted
+/// font templates that are currently in use.
+struct FontCache {
+ port: Receiver<Command>,
+ generic_fonts: HashMap<String, String>,
+ local_families: HashMap<String, FontFamily>,
+ font_context: FontContextHandle,
+}
+
+impl FontCache {
+ fn run(&mut self) {
+ loop {
+ let msg = self.port.recv();
+
+ 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));
+ }
+ Exit(result) => {
+ result.send(());
+ break;
+ }
+ }
+ }
+ }
+
+ fn refresh_local_families(&mut self) {
+ self.local_families.clear();
+ get_available_families(|family_name| {
+ if !self.local_families.contains_key(&family_name) {
+ let family = FontFamily::new();
+ self.local_families.insert(family_name, family);
+ }
+ });
+ }
+
+ fn transform_family(&self, family: &String) -> String {
+ match self.generic_fonts.find(family) {
+ None => family.to_string(),
+ Some(mapped_family) => (*mapped_family).clone()
+ }
+ }
+
+ fn find_font_in_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) {
+ debug!("FontList: Found font family with name={:s}", family_name.to_str());
+ let s = self.local_families.get_mut(family_name);
+
+ 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);
+ });
+ }
+
+ // TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
+ // if such family exists, try to match style to a font
+ let result = s.find_font_for_style(desc, &self.font_context);
+ if result.is_some() {
+ return result;
+ }
+
+ None
+ } else {
+ debug!("FontList: Couldn't find font family with name={:s}", family_name.to_str());
+ 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)
+ }
+
+ 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);
+ if maybe_font_in_family.is_some() {
+ return maybe_font_in_family.unwrap();
+ }
+ }
+
+ fail!("Unable to find any fonts that match (do you have fallback fonts installed?)");
+ }
+}
+
+/// The public interface to the font cache task, used exclusively by
+/// the per-thread/task FontContext structures.
+#[deriving(Clone)]
+pub struct FontCacheTask {
+ chan: Sender<Command>,
+}
+
+impl FontCacheTask {
+ pub fn new() -> FontCacheTask {
+ let (chan, port) = channel();
+
+ spawn(proc() {
+ // 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());
+
+ let mut cache = FontCache {
+ port: port,
+ generic_fonts: generic_fonts,
+ local_families: HashMap::new(),
+ font_context: FontContextHandle::new(),
+ };
+
+ cache.refresh_local_families();
+ cache.run();
+ });
+
+ FontCacheTask {
+ chan: chan,
+ }
+ }
+
+ pub fn get_font_template(&mut self, family: String, desc: FontTemplateDescriptor)
+ -> Arc<FontTemplateData> {
+
+ let (response_chan, response_port) = channel();
+ self.chan.send(GetFontTemplate(family, desc, response_chan));
+
+ let reply = response_port.recv();
+
+ match reply {
+ GetFontTemplateReply(data) => {
+ data
+ }
+ }
+ }
+
+ pub fn exit(&self) {
+ let (response_chan, response_port) = channel();
+ self.chan.send(Exit(response_chan));
+ response_port.recv();
+ }
+}
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
}
}
diff --git a/src/components/gfx/font_list.rs b/src/components/gfx/font_list.rs
deleted file mode 100644
index 3180e5e710c..00000000000
--- a/src/components/gfx/font_list.rs
+++ /dev/null
@@ -1,162 +0,0 @@
-/* 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 std::collections::hashmap::HashMap;
-use font::SpecifiedFontStyle;
-use font_context::FontContextHandleMethods;
-use gfx_font::FontHandleMethods;
-use platform::font::FontHandle;
-use platform::font_context::FontContextHandle;
-use platform::font_list;
-use style::computed_values::{font_weight, font_style};
-
-use servo_util::time::{TimeProfilerChan, profile};
-use servo_util::time;
-
-pub type FontFamilyMap = HashMap<String, FontFamily>;
-
-/// The platform-independent font list abstraction.
-pub struct FontList {
- family_map: FontFamilyMap,
- time_profiler_chan: TimeProfilerChan,
-}
-
-impl FontList {
- pub fn new(fctx: &FontContextHandle,
- time_profiler_chan: TimeProfilerChan)
- -> FontList {
- let mut list = FontList {
- family_map: HashMap::new(),
- time_profiler_chan: time_profiler_chan.clone(),
- };
- list.refresh(fctx);
- list
- }
-
- fn refresh(&mut self, _: &FontContextHandle) {
- // TODO(Issue #186): don't refresh unless something actually
- // changed. Does OSX have a notification for this event?
- //
- // Should font families with entries be invalidated/refreshed too?
- profile(time::GfxRegenAvailableFontsCategory, self.time_profiler_chan.clone(), || {
- self.family_map.clear();
- font_list::get_available_families(|family_name| {
- debug!("Creating new FontFamily for family: {:s}", family_name);
- let new_family = FontFamily::new(family_name.as_slice());
- self.family_map.insert(family_name, new_family);
- });
- });
- }
-
- pub fn find_font_in_family<'a>(&'a mut self, fctx: &FontContextHandle,
- family_name: &String,
- style: &SpecifiedFontStyle) -> Option<&'a FontEntry> {
- // TODO(Issue #188): look up localized font family names if canonical name not found
- // look up canonical name
- if self.family_map.contains_key(family_name) {
- //FIXME call twice!(ksh8281)
- debug!("FontList: Found font family with name={:s}", family_name.to_str());
- let s: &'a mut FontFamily = self.family_map.get_mut(family_name);
- // TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
- // if such family exists, try to match style to a font
- let result = s.find_font_for_style(fctx, style);
- if result.is_some() {
- return result;
- }
-
- None
- } else {
- debug!("FontList: Couldn't find font family with name={:s}", family_name.to_str());
- None
- }
- }
-
- pub fn get_last_resort_font_families() -> Vec<String> {
- font_list::get_last_resort_font_families()
- }
-}
-
-// Holds a specific font family, and the various
-pub struct FontFamily {
- pub family_name: String,
- pub entries: Vec<FontEntry>,
-}
-
-impl FontFamily {
- pub fn new(family_name: &str) -> FontFamily {
- FontFamily {
- family_name: family_name.to_str(),
- entries: vec!(),
- }
- }
-
- fn load_family_variations(&mut self, fctx: &FontContextHandle) {
- if self.entries.len() > 0 {
- return
- }
- let mut entries = vec!();
- font_list::load_variations_for_family(self.family_name.as_slice(), |file_path| {
- let font_handle = fctx.create_font_from_identifier(file_path.as_slice(), None).unwrap();
- debug!("Creating new FontEntry for face: {:s}", font_handle.face_name());
- let entry = FontEntry::new(font_handle);
- entries.push(entry);
- });
- self.entries = entries;
- assert!(self.entries.len() > 0)
- }
-
- pub fn find_font_for_style<'a>(&'a mut self, fctx: &FontContextHandle, style: &SpecifiedFontStyle)
- -> Option<&'a FontEntry> {
- self.load_family_variations(fctx);
-
- // TODO(Issue #189): optimize lookup for
- // regular/bold/italic/bolditalic with fixed offsets and a
- // static decision table for fallback between these values.
-
- // TODO(Issue #190): if not in the fast path above, do
- // expensive matching of weights, etc.
- for entry in self.entries.iter() {
- if (style.weight.is_bold() == entry.is_bold()) &&
- ((style.style == font_style::italic) == entry.is_italic()) {
-
- return Some(entry);
- }
- }
-
- None
- }
-}
-
-/// This struct summarizes an available font's features. In the future, this will include fiddly
-/// settings such as special font table handling.
-///
-/// In the common case, each FontFamily will have a singleton FontEntry, or it will have the
-/// standard four faces: Normal, Bold, Italic, BoldItalic.
-pub struct FontEntry {
- pub face_name: String,
- weight: font_weight::T,
- italic: bool,
- pub handle: FontHandle,
- // TODO: array of OpenType features, etc.
-}
-
-impl FontEntry {
- pub fn new(handle: FontHandle) -> FontEntry {
- FontEntry {
- face_name: handle.face_name(),
- weight: handle.boldness(),
- italic: handle.is_italic(),
- handle: handle
- }
- }
-
- pub fn is_bold(&self) -> bool {
- self.weight.is_bold()
- }
-
- pub fn is_italic(&self) -> bool {
- self.italic
- }
-}
-
diff --git a/src/components/gfx/font_template.rs b/src/components/gfx/font_template.rs
new file mode 100644
index 00000000000..3ca9aff4e45
--- /dev/null
+++ b/src/components/gfx/font_template.rs
@@ -0,0 +1,115 @@
+/* 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 style::computed_values::font_weight;
+use platform::font_context::FontContextHandle;
+use platform::font::FontHandle;
+use platform::font_template::FontTemplateData;
+
+use sync::{Arc, Weak};
+use font::FontHandleMethods;
+
+/// Describes how to select a font from a given family.
+/// This is very basic at the moment and needs to be
+/// expanded or refactored when we support more of the
+/// font styling parameters.
+#[deriving(Clone)]
+pub struct FontTemplateDescriptor {
+ pub weight: font_weight::T,
+ pub italic: bool,
+}
+
+impl FontTemplateDescriptor {
+ pub fn new(weight: font_weight::T, italic: bool) -> FontTemplateDescriptor {
+ FontTemplateDescriptor {
+ weight: weight,
+ italic: italic,
+ }
+ }
+}
+
+impl PartialEq for FontTemplateDescriptor {
+ fn eq(&self, other: &FontTemplateDescriptor) -> bool {
+ self.weight.is_bold() == other.weight.is_bold() &&
+ self.italic == other.italic
+ }
+}
+
+/// This describes all the information needed to create
+/// font instance handles. It contains a unique that is
+/// platform specific.
+pub struct FontTemplate {
+ identifier: String,
+ descriptor: Option<FontTemplateDescriptor>,
+ data: Option<Weak<FontTemplateData>>,
+}
+
+/// 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 {
+ FontTemplate {
+ identifier: identifier.to_string(),
+ descriptor: None,
+ data: None,
+ }
+ }
+
+ /// 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>> {
+ // The font template data can be unloaded when nothing is referencing
+ // it (via the Weak reference to the Arc above). However, if we have
+ // already loaded a font, store the style information about it separately,
+ // so that we can do font matching against it again in the future
+ // without having to reload the font (unless it is an actual match).
+ match self.descriptor {
+ Some(actual_desc) => {
+ if *requested_desc == actual_desc {
+ Some(self.get_data())
+ } else {
+ None
+ }
+ },
+ 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)
+ } else {
+ 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 {
+ Some(ref data) => data.upgrade(),
+ None => None,
+ };
+
+ match maybe_data {
+ Some(data) => data,
+ None => {
+ let template_data = Arc::new(FontTemplateData::new(self.identifier.as_slice()));
+ self.data = Some(template_data.downgrade());
+ template_data
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/components/gfx/gfx.rs b/src/components/gfx/gfx.rs
index dd7d58c7616..4a7c4e217b2 100644
--- a/src/components/gfx/gfx.rs
+++ b/src/components/gfx/gfx.rs
@@ -45,12 +45,6 @@ extern crate harfbuzz;
#[cfg(target_os="macos")] extern crate core_graphics;
#[cfg(target_os="macos")] extern crate core_text;
-pub use gfx_font = font;
-pub use gfx_font_context = font_context;
-pub use gfx_font_list = font_list;
-pub use servo_gfx_font = font;
-pub use servo_gfx_font_list = font_list;
-
pub use render_context::RenderContext;
// Private rendering modules
@@ -65,7 +59,8 @@ pub mod render_task;
// Fonts
pub mod font;
pub mod font_context;
-pub mod font_list;
+pub mod font_cache_task;
+pub mod font_template;
// Misc.
mod buffer_map;
diff --git a/src/components/gfx/platform/android/font.rs b/src/components/gfx/platform/android/font.rs
index e61d092ae07..3e060c0fb58 100644
--- a/src/components/gfx/platform/android/font.rs
+++ b/src/components/gfx/platform/android/font.rs
@@ -5,17 +5,18 @@
extern crate freetype;
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
-use font::{FontTableTag, FractionalPixel, SpecifiedFontStyle};
+use font::{FontTableTag, FractionalPixel};
use servo_util::geometry::Au;
use servo_util::geometry;
use platform::font_context::FontContextHandle;
use text::glyph::GlyphId;
use text::util::{float_to_fixed, fixed_to_float};
use style::computed_values::font_weight;
+use platform::font_template::FontTemplateData;
use freetype::freetype::{FT_Get_Char_Index, FT_Get_Postscript_Name};
use freetype::freetype::{FT_Load_Glyph, FT_Set_Char_Size};
-use freetype::freetype::{FT_New_Face, FT_Get_Sfnt_Table};
+use freetype::freetype::{FT_Get_Sfnt_Table};
use freetype::freetype::{FT_New_Memory_Face, FT_Done_Face};
use freetype::freetype::{FTErrorMethods, FT_F26Dot6, FT_Face, FT_FaceRec};
use freetype::freetype::{FT_GlyphSlot, FT_Library, FT_Long, FT_ULong};
@@ -28,6 +29,8 @@ use std::mem;
use std::ptr;
use std::str;
+use sync::Arc;
+
fn float_to_fixed_ft(f: f64) -> i32 {
float_to_fixed(6, f)
}
@@ -37,7 +40,7 @@ fn fixed_to_float_ft(f: i32) -> f64 {
}
pub struct FontTable {
- bogus: ()
+ _bogus: ()
}
impl FontTableMethods for FontTable {
@@ -46,15 +49,10 @@ impl FontTableMethods for FontTable {
}
}
-pub enum FontSource {
- FontSourceMem(Vec<u8>),
- FontSourceFile(String)
-}
-
pub struct FontHandle {
// The font binary. This must stay valid for the lifetime of the font,
// if the font is created using FT_Memory_Face.
- pub source: FontSource,
+ pub font_data: Arc<FontTemplateData>,
pub face: FT_Face,
pub handle: FontContextHandle
}
@@ -72,14 +70,15 @@ impl Drop for FontHandle {
}
impl FontHandleMethods for FontHandle {
- fn new_from_buffer(fctx: &FontContextHandle,
- buf: Vec<u8>,
- style: &SpecifiedFontStyle)
+ fn new_from_template(fctx: &FontContextHandle,
+ template: Arc<FontTemplateData>,
+ pt_size: Option<f64>)
-> Result<FontHandle, ()> {
let ft_ctx: FT_Library = fctx.ctx.ctx;
if ft_ctx.is_null() { return Err(()); }
- let face_result = create_face_from_buffer(ft_ctx, buf.as_ptr(), buf.len(), style.pt_size);
+ let bytes = &template.deref().bytes;
+ let face_result = create_face_from_buffer(ft_ctx, bytes.as_ptr(), bytes.len(), pt_size);
// TODO: this could be more simply written as result::chain
// and moving buf into the struct ctor, but cant' move out of
@@ -88,7 +87,7 @@ impl FontHandleMethods for FontHandle {
Ok(face) => {
let handle = FontHandle {
face: face,
- source: FontSourceMem(buf),
+ font_data: template.clone(),
handle: fctx.clone()
};
Ok(handle)
@@ -96,7 +95,7 @@ impl FontHandleMethods for FontHandle {
Err(()) => Err(())
};
- fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
+ fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: Option<f64>)
-> Result<FT_Face, ()> {
unsafe {
let mut face: FT_Face = ptr::null();
@@ -107,7 +106,11 @@ impl FontHandleMethods for FontHandle {
if !result.succeeded() || face.is_null() {
return Err(());
}
- if FontHandle::set_char_size(face, pt_size).is_ok() {
+ let is_ok = match pt_size {
+ Some(s) => FontHandle::set_char_size(face, s).is_ok(),
+ None => true,
+ };
+ if is_ok {
Ok(face)
} else {
Err(())
@@ -115,14 +118,8 @@ impl FontHandleMethods for FontHandle {
}
}
}
-
- // an identifier usable by FontContextHandle to recreate this FontHandle.
- fn face_identifier(&self) -> String {
- match self.source {
- FontSourceFile(ref path) => path.clone(),
- _ => unreachable!(), // This will be handled when the rest of the font
- // refactor is complete. For now, it can never be hit.
- }
+ fn get_template(&self) -> Arc<FontTemplateData> {
+ self.font_data.clone()
}
fn family_name(&self) -> String {
unsafe { str::raw::from_c_str((*self.face).family_name) }
@@ -265,39 +262,6 @@ impl<'a> FontHandle {
}
}
- pub fn new_from_file(fctx: &FontContextHandle, file: &str,
- maybe_style: Option<&SpecifiedFontStyle>) -> Result<FontHandle, ()> {
- unsafe {
- let ft_ctx: FT_Library = fctx.ctx.ctx;
- if ft_ctx.is_null() { return Err(()); }
-
- let mut face: FT_Face = ptr::null();
- let face_index = 0 as FT_Long;
- file.to_c_str().with_ref(|file_str| {
- FT_New_Face(ft_ctx, file_str,
- face_index, &mut face);
- });
- if face.is_null() {
- return Err(());
- }
-
- let ok = match maybe_style {
- Some(style) => FontHandle::set_char_size(face, style.pt_size).is_ok(),
- None => true,
- };
-
- if ok {
- Ok(FontHandle {
- source: FontSourceFile(file.to_str()),
- face: face,
- handle: fctx.clone()
- })
- } else {
- Err(())
- }
- }
- }
-
fn get_face_rec(&'a self) -> &'a FT_FaceRec {
unsafe {
&(*self.face)
diff --git a/src/components/gfx/platform/android/font_context.rs b/src/components/gfx/platform/android/font_context.rs
index 3196f25120e..97c1fdf698e 100644
--- a/src/components/gfx/platform/android/font_context.rs
+++ b/src/components/gfx/platform/android/font_context.rs
@@ -2,10 +2,6 @@
* 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::UsedFontStyle;
-use platform::font::FontHandle;
-use font_context::FontContextHandleMethods;
-
use freetype::freetype::FTErrorMethods;
use freetype::freetype::FT_Add_Default_Modules;
use freetype::freetype::FT_Done_FreeType;
@@ -84,12 +80,3 @@ impl FontContextHandle {
}
}
}
-
-impl FontContextHandleMethods for FontContextHandle {
- fn create_font_from_identifier(&self, name: &str, style: Option<&UsedFontStyle>)
- -> Result<FontHandle, ()> {
- debug!("Creating font handle for {:s}", name);
- FontHandle::new_from_file(self, name.as_slice(), style)
- }
-}
-
diff --git a/src/components/gfx/platform/android/font_list.rs b/src/components/gfx/platform/android/font_list.rs
index d96cd8cdd0f..1f53e1b93d2 100644
--- a/src/components/gfx/platform/android/font_list.rs
+++ b/src/components/gfx/platform/android/font_list.rs
@@ -40,7 +40,7 @@ pub fn get_available_families(callback: |String|) {
}
}
-pub fn load_variations_for_family(family_name: &str, callback: |String|) {
+pub fn get_variations_for_family(family_name: &str, callback: |String|) {
debug!("getting variations for {}", family_name);
unsafe {
let config = FcConfigGetCurrent();
diff --git a/src/components/gfx/platform/android/font_template.rs b/src/components/gfx/platform/android/font_template.rs
new file mode 100644
index 00000000000..d1a821a0bf3
--- /dev/null
+++ b/src/components/gfx/platform/android/font_template.rs
@@ -0,0 +1,28 @@
+/* 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 std::io;
+use std::io::File;
+
+/// Platform specific font representation for android.
+/// The identifier is an absolute path, and the bytes
+/// field is the loaded data that can be passed to
+/// freetype and azure directly.
+pub struct FontTemplateData {
+ pub bytes: Vec<u8>,
+ pub identifier: String,
+}
+
+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();
+
+ FontTemplateData {
+ bytes: bytes,
+ identifier: identifier.to_string(),
+ }
+ }
+}
diff --git a/src/components/gfx/platform/linux/font.rs b/src/components/gfx/platform/linux/font.rs
index 1299315ade2..3e060c0fb58 100644
--- a/src/components/gfx/platform/linux/font.rs
+++ b/src/components/gfx/platform/linux/font.rs
@@ -5,17 +5,18 @@
extern crate freetype;
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
-use font::{FontTableTag, FractionalPixel, SpecifiedFontStyle};
+use font::{FontTableTag, FractionalPixel};
use servo_util::geometry::Au;
use servo_util::geometry;
use platform::font_context::FontContextHandle;
use text::glyph::GlyphId;
use text::util::{float_to_fixed, fixed_to_float};
use style::computed_values::font_weight;
+use platform::font_template::FontTemplateData;
use freetype::freetype::{FT_Get_Char_Index, FT_Get_Postscript_Name};
use freetype::freetype::{FT_Load_Glyph, FT_Set_Char_Size};
-use freetype::freetype::{FT_New_Face, FT_Get_Sfnt_Table};
+use freetype::freetype::{FT_Get_Sfnt_Table};
use freetype::freetype::{FT_New_Memory_Face, FT_Done_Face};
use freetype::freetype::{FTErrorMethods, FT_F26Dot6, FT_Face, FT_FaceRec};
use freetype::freetype::{FT_GlyphSlot, FT_Library, FT_Long, FT_ULong};
@@ -28,6 +29,8 @@ use std::mem;
use std::ptr;
use std::str;
+use sync::Arc;
+
fn float_to_fixed_ft(f: f64) -> i32 {
float_to_fixed(6, f)
}
@@ -46,15 +49,10 @@ impl FontTableMethods for FontTable {
}
}
-pub enum FontSource {
- FontSourceMem(Vec<u8>),
- FontSourceFile(String)
-}
-
pub struct FontHandle {
// The font binary. This must stay valid for the lifetime of the font,
// if the font is created using FT_Memory_Face.
- pub source: FontSource,
+ pub font_data: Arc<FontTemplateData>,
pub face: FT_Face,
pub handle: FontContextHandle
}
@@ -72,14 +70,15 @@ impl Drop for FontHandle {
}
impl FontHandleMethods for FontHandle {
- fn new_from_buffer(fctx: &FontContextHandle,
- buf: Vec<u8>,
- style: &SpecifiedFontStyle)
+ fn new_from_template(fctx: &FontContextHandle,
+ template: Arc<FontTemplateData>,
+ pt_size: Option<f64>)
-> Result<FontHandle, ()> {
let ft_ctx: FT_Library = fctx.ctx.ctx;
if ft_ctx.is_null() { return Err(()); }
- let face_result = create_face_from_buffer(ft_ctx, buf.as_ptr(), buf.len(), style.pt_size);
+ let bytes = &template.deref().bytes;
+ let face_result = create_face_from_buffer(ft_ctx, bytes.as_ptr(), bytes.len(), pt_size);
// TODO: this could be more simply written as result::chain
// and moving buf into the struct ctor, but cant' move out of
@@ -88,7 +87,7 @@ impl FontHandleMethods for FontHandle {
Ok(face) => {
let handle = FontHandle {
face: face,
- source: FontSourceMem(buf),
+ font_data: template.clone(),
handle: fctx.clone()
};
Ok(handle)
@@ -96,7 +95,7 @@ impl FontHandleMethods for FontHandle {
Err(()) => Err(())
};
- fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
+ fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: Option<f64>)
-> Result<FT_Face, ()> {
unsafe {
let mut face: FT_Face = ptr::null();
@@ -107,7 +106,11 @@ impl FontHandleMethods for FontHandle {
if !result.succeeded() || face.is_null() {
return Err(());
}
- if FontHandle::set_char_size(face, pt_size).is_ok() {
+ let is_ok = match pt_size {
+ Some(s) => FontHandle::set_char_size(face, s).is_ok(),
+ None => true,
+ };
+ if is_ok {
Ok(face)
} else {
Err(())
@@ -115,14 +118,8 @@ impl FontHandleMethods for FontHandle {
}
}
}
-
- // an identifier usable by FontContextHandle to recreate this FontHandle.
- fn face_identifier(&self) -> String {
- match self.source {
- FontSourceFile(ref path) => path.clone(),
- _ => unreachable!(), // This will be handled when the rest of the font
- // refactor is complete. For now, it can never be hit.
- }
+ fn get_template(&self) -> Arc<FontTemplateData> {
+ self.font_data.clone()
}
fn family_name(&self) -> String {
unsafe { str::raw::from_c_str((*self.face).family_name) }
@@ -265,39 +262,6 @@ impl<'a> FontHandle {
}
}
- pub fn new_from_file(fctx: &FontContextHandle, file: &str,
- maybe_style: Option<&SpecifiedFontStyle>) -> Result<FontHandle, ()> {
- unsafe {
- let ft_ctx: FT_Library = fctx.ctx.ctx;
- if ft_ctx.is_null() { return Err(()); }
-
- let mut face: FT_Face = ptr::null();
- let face_index = 0 as FT_Long;
- file.to_c_str().with_ref(|file_str| {
- FT_New_Face(ft_ctx, file_str,
- face_index, &mut face);
- });
- if face.is_null() {
- return Err(());
- }
-
- let ok = match maybe_style {
- Some(style) => FontHandle::set_char_size(face, style.pt_size).is_ok(),
- None => true,
- };
-
- if ok {
- Ok(FontHandle {
- source: FontSourceFile(file.to_str()),
- face: face,
- handle: fctx.clone()
- })
- } else {
- Err(())
- }
- }
- }
-
fn get_face_rec(&'a self) -> &'a FT_FaceRec {
unsafe {
&(*self.face)
diff --git a/src/components/gfx/platform/linux/font_context.rs b/src/components/gfx/platform/linux/font_context.rs
index 3196f25120e..97c1fdf698e 100644
--- a/src/components/gfx/platform/linux/font_context.rs
+++ b/src/components/gfx/platform/linux/font_context.rs
@@ -2,10 +2,6 @@
* 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::UsedFontStyle;
-use platform::font::FontHandle;
-use font_context::FontContextHandleMethods;
-
use freetype::freetype::FTErrorMethods;
use freetype::freetype::FT_Add_Default_Modules;
use freetype::freetype::FT_Done_FreeType;
@@ -84,12 +80,3 @@ impl FontContextHandle {
}
}
}
-
-impl FontContextHandleMethods for FontContextHandle {
- fn create_font_from_identifier(&self, name: &str, style: Option<&UsedFontStyle>)
- -> Result<FontHandle, ()> {
- debug!("Creating font handle for {:s}", name);
- FontHandle::new_from_file(self, name.as_slice(), style)
- }
-}
-
diff --git a/src/components/gfx/platform/linux/font_list.rs b/src/components/gfx/platform/linux/font_list.rs
index f76cde75c69..b401bb2b94a 100644
--- a/src/components/gfx/platform/linux/font_list.rs
+++ b/src/components/gfx/platform/linux/font_list.rs
@@ -40,7 +40,7 @@ pub fn get_available_families(callback: |String|) {
}
}
-pub fn load_variations_for_family(family_name: &str, callback: |String|) {
+pub fn get_variations_for_family(family_name: &str, callback: |String|) {
debug!("getting variations for {}", family_name);
unsafe {
let config = FcConfigGetCurrent();
diff --git a/src/components/gfx/platform/linux/font_template.rs b/src/components/gfx/platform/linux/font_template.rs
new file mode 100644
index 00000000000..e00a1018317
--- /dev/null
+++ b/src/components/gfx/platform/linux/font_template.rs
@@ -0,0 +1,28 @@
+/* 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 std::io;
+use std::io::File;
+
+/// Platform specific font representation for Linux.
+/// The identifier is an absolute path, and the bytes
+/// field is the loaded data that can be passed to
+/// freetype and azure directly.
+pub struct FontTemplateData {
+ pub bytes: Vec<u8>,
+ pub identifier: String,
+}
+
+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();
+
+ FontTemplateData {
+ bytes: bytes,
+ identifier: identifier.to_string(),
+ }
+ }
+}
diff --git a/src/components/gfx/platform/macos/font.rs b/src/components/gfx/platform/macos/font.rs
index 2edb233a527..26209abb9d9 100644
--- a/src/components/gfx/platform/macos/font.rs
+++ b/src/components/gfx/platform/macos/font.rs
@@ -10,25 +10,25 @@ extern crate core_text;
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
use font::FontTableTag;
-use font::{FractionalPixel, SpecifiedFontStyle};
+use font::FractionalPixel;
use servo_util::geometry::{Au, px_to_pt};
use servo_util::geometry;
use platform::macos::font_context::FontContextHandle;
use text::glyph::GlyphId;
use style::computed_values::font_weight;
+use platform::font_template::FontTemplateData;
use core_foundation::base::CFIndex;
use core_foundation::data::CFData;
use core_foundation::string::UniChar;
-use core_graphics::data_provider::CGDataProvider;
-use core_graphics::font::{CGFont, CGGlyph};
+use core_graphics::font::CGGlyph;
use core_graphics::geometry::CGRect;
use core_text::font::CTFont;
use core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
use core_text::font_descriptor::{kCTFontDefaultOrientation};
-use core_text;
use std::ptr;
+use sync::Arc;
pub struct FontTable {
data: CFData,
@@ -52,43 +52,30 @@ impl FontTableMethods for FontTable {
}
pub struct FontHandle {
- cgfont: Option<CGFont>,
+ pub font_data: Arc<FontTemplateData>,
pub ctfont: CTFont,
}
-impl FontHandle {
- pub fn new_from_CTFont(_: &FontContextHandle, ctfont: CTFont) -> Result<FontHandle, ()> {
- Ok(FontHandle {
- cgfont: None,
- ctfont: ctfont,
+impl FontHandleMethods for FontHandle {
+ fn new_from_template(_fctx: &FontContextHandle,
+ template: Arc<FontTemplateData>,
+ pt_size: Option<f64>)
+ -> Result<FontHandle, ()> {
+ let size = match pt_size {
+ 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,
+ })
})
}
- pub fn get_CGFont(&mut self) -> CGFont {
- match self.cgfont {
- Some(ref font) => font.clone(),
- None => {
- let cgfont = self.ctfont.copy_to_CGFont();
- self.cgfont = Some(cgfont.clone());
- cgfont
- }
- }
- }
-}
-
-impl FontHandleMethods for FontHandle {
- fn new_from_buffer(_: &FontContextHandle, buf: Vec<u8>, style: &SpecifiedFontStyle)
- -> Result<FontHandle, ()> {
- let fontprov = CGDataProvider::from_buffer(buf.as_slice());
- let cgfont = CGFont::from_data_provider(fontprov);
- let ctfont = core_text::font::new_from_CGFont(&cgfont, style.pt_size);
-
- let result = Ok(FontHandle {
- cgfont: Some(cgfont),
- ctfont: ctfont,
- });
-
- return result;
+ fn get_template(&self) -> Arc<FontTemplateData> {
+ self.font_data.clone()
}
fn family_name(&self) -> String {
@@ -182,9 +169,5 @@ impl FontHandleMethods for FontHandle {
Some(FontTable::wrap(data))
})
}
-
- fn face_identifier(&self) -> String {
- self.ctfont.postscript_name()
- }
}
diff --git a/src/components/gfx/platform/macos/font_context.rs b/src/components/gfx/platform/macos/font_context.rs
index 4b66aa6bbf8..94730641c3d 100644
--- a/src/components/gfx/platform/macos/font_context.rs
+++ b/src/components/gfx/platform/macos/font_context.rs
@@ -2,12 +2,6 @@
* 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::UsedFontStyle;
-use font_context::FontContextHandleMethods;
-use platform::macos::font::FontHandle;
-
-use core_text;
-
#[deriving(Clone)]
pub struct FontContextHandle {
ctx: ()
@@ -20,19 +14,3 @@ impl FontContextHandle {
FontContextHandle { ctx: () }
}
}
-
-impl FontContextHandleMethods for FontContextHandle {
- fn create_font_from_identifier(&self,
- name: &str,
- style: Option<&UsedFontStyle>)
- -> Result<FontHandle, ()> {
- let pt_size = match style {
- Some(style) => style.pt_size,
- None => 0.0,
- };
- let ctfont_result = core_text::font::new_from_name(name.as_slice(), pt_size);
- ctfont_result.and_then(|ctfont| {
- FontHandle::new_from_CTFont(self, ctfont)
- })
- }
-}
diff --git a/src/components/gfx/platform/macos/font_list.rs b/src/components/gfx/platform/macos/font_list.rs
index 65d375c5845..dd0611a0356 100644
--- a/src/components/gfx/platform/macos/font_list.rs
+++ b/src/components/gfx/platform/macos/font_list.rs
@@ -18,7 +18,7 @@ pub fn get_available_families(callback: |String|) {
}
}
-pub fn load_variations_for_family(family_name: &str, callback: |String|) {
+pub fn get_variations_for_family(family_name: &str, callback: |String|) {
debug!("Looking for faces of family: {:s}", family_name);
let family_collection =
diff --git a/src/components/gfx/platform/macos/font_template.rs b/src/components/gfx/platform/macos/font_template.rs
new file mode 100644
index 00000000000..bda41186da3
--- /dev/null
+++ b/src/components/gfx/platform/macos/font_template.rs
@@ -0,0 +1,25 @@
+/* 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 core_text::font::CTFont;
+use core_text;
+
+/// Platform specific font representation for mac.
+/// The identifier is a PostScript font name. The
+/// CTFont object is cached here for use by the
+/// render functions that create CGFont references.
+pub struct FontTemplateData {
+ pub ctfont: 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);
+ FontTemplateData {
+ ctfont: ctfont_result.unwrap(),
+ identifier: identifier.to_string(),
+ }
+ }
+}
diff --git a/src/components/gfx/platform/mod.rs b/src/components/gfx/platform/mod.rs
index 34870cc2f2d..eada62fc637 100644
--- a/src/components/gfx/platform/mod.rs
+++ b/src/components/gfx/platform/mod.rs
@@ -2,15 +2,16 @@
* 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/. */
-#[cfg(target_os="linux")] pub use platform::linux::{font, font_context, font_list};
-#[cfg(target_os="macos")] pub use platform::macos::{font, font_context, font_list};
-#[cfg(target_os="android")] pub use platform::android::{font, font_context, font_list};
+#[cfg(target_os="linux")] pub use platform::linux::{font, font_context, font_list, font_template};
+#[cfg(target_os="macos")] pub use platform::macos::{font, font_context, font_list, font_template};
+#[cfg(target_os="android")] pub use platform::android::{font, font_context, font_list, font_template};
#[cfg(target_os="linux")]
pub mod linux {
pub mod font;
pub mod font_context;
pub mod font_list;
+ pub mod font_template;
}
#[cfg(target_os="macos")]
@@ -18,6 +19,7 @@ pub mod macos {
pub mod font;
pub mod font_context;
pub mod font_list;
+ pub mod font_template;
}
#[cfg(target_os="android")]
@@ -25,4 +27,5 @@ pub mod android {
pub mod font;
pub mod font_context;
pub mod font_list;
+ pub mod font_template;
}
diff --git a/src/components/gfx/render_task.rs b/src/components/gfx/render_task.rs
index 8048db3b70d..d6c31bce048 100644
--- a/src/components/gfx/render_task.rs
+++ b/src/components/gfx/render_task.rs
@@ -7,7 +7,7 @@
use buffer_map::BufferMap;
use display_list::optimizer::DisplayListOptimizer;
use display_list::DisplayList;
-use font_context::{FontContext, FontContextInfo};
+use font_context::FontContext;
use render_context::RenderContext;
use azure::azure_hl::{B8G8R8A8, Color, DrawTarget, StolenGLResources};
@@ -34,6 +34,7 @@ use servo_util::time::{TimeProfilerChan, profile};
use servo_util::time;
use std::comm::{Receiver, Sender, channel};
use sync::Arc;
+use font_cache_task::FontCacheTask;
/// Information about a layer that layout sends to the painting task.
pub struct RenderLayer {
@@ -144,12 +145,15 @@ impl<C:RenderListener + Send> RenderTask<C> {
port: Receiver<Msg>,
compositor: C,
constellation_chan: ConstellationChan,
+ font_cache_task: FontCacheTask,
failure_msg: Failure,
opts: Opts,
time_profiler_chan: TimeProfilerChan,
shutdown_chan: Sender<()>) {
let ConstellationChan(c) = constellation_chan.clone();
+ let fc = font_cache_task.clone();
+
let mut task_opts = TaskOpts::new();
task_opts.name = Some("RenderTask".into_maybe_owned());
task_opts.on_exit = Some(proc(result: task::Result) {
@@ -172,11 +176,7 @@ impl<C:RenderListener + Send> RenderTask<C> {
port: port,
compositor: compositor,
constellation_chan: constellation_chan,
- font_ctx: box FontContext::new(FontContextInfo {
- backend: opts.render_backend.clone(),
- needs_font_list: false,
- time_profiler_chan: time_profiler_chan.clone(),
- }),
+ font_ctx: box FontContext::new(fc.clone()),
opts: opts,
time_profiler_chan: time_profiler_chan,
diff --git a/src/components/gfx/text/shaping/harfbuzz.rs b/src/components/gfx/text/shaping/harfbuzz.rs
index b6646db771a..e028ae8dac2 100644
--- a/src/components/gfx/text/shaping/harfbuzz.rs
+++ b/src/components/gfx/text/shaping/harfbuzz.rs
@@ -163,7 +163,7 @@ impl Shaper {
let hb_font: *hb_font_t = hb_font_create(hb_face);
// Set points-per-em. if zero, performs no hinting in that direction.
- let pt_size = font.style.pt_size;
+ let pt_size = font.pt_size;
hb_font_set_ppem(hb_font, pt_size as c_uint, pt_size as c_uint);
// Set scaling. Note that this takes 16.16 fixed point.
diff --git a/src/components/gfx/text/text_run.rs b/src/components/gfx/text/text_run.rs
index 1f182572ac1..719660c676d 100644
--- a/src/components/gfx/text/text_run.rs
+++ b/src/components/gfx/text/text_run.rs
@@ -2,7 +2,7 @@
* 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, RunMetrics, FontStyle, FontMetrics};
+use font::{Font, RunMetrics, FontMetrics};
use servo_util::geometry::Au;
use servo_util::range::Range;
use servo_util::vec::{Comparator, FullBinarySearchMethods};
@@ -10,14 +10,16 @@ use std::slice::Items;
use style::computed_values::text_decoration;
use sync::Arc;
use text::glyph::{CharIndex, GlyphStore};
+use font::FontHandleMethods;
+use platform::font_template::FontTemplateData;
/// A single "paragraph" of text in one font size and style.
#[deriving(Clone)]
pub struct TextRun {
pub text: Arc<String>,
- pub font_descriptor: FontDescriptor,
+ pub font_template: Arc<FontTemplateData>,
+ pub pt_size: f64,
pub font_metrics: FontMetrics,
- pub font_style: FontStyle,
pub decoration: text_decoration::T,
/// The glyph runs that make up this text run.
pub glyphs: Arc<Vec<GlyphRun>>,
@@ -119,12 +121,11 @@ impl<'a> Iterator<Range<CharIndex>> for LineIterator<'a> {
impl<'a> TextRun {
pub fn new(font: &mut Font, text: String, decoration: text_decoration::T) -> TextRun {
let glyphs = TextRun::break_and_shape(font, text.as_slice());
-
let run = TextRun {
text: Arc::new(text),
- font_style: font.style.clone(),
font_metrics: font.metrics.clone(),
- font_descriptor: font.get_descriptor(),
+ font_template: font.handle.get_template(),
+ pt_size: font.pt_size,
decoration: decoration,
glyphs: Arc::new(glyphs),
};
@@ -133,7 +134,6 @@ impl<'a> TextRun {
pub fn break_and_shape(font: &mut Font, text: &str) -> Vec<GlyphRun> {
// TODO(Issue #230): do a better job. See Gecko's LineBreaker.
-
let mut glyphs = vec!();
let (mut byte_i, mut char_i) = (0u, CharIndex(0));
let mut cur_slice_is_whitespace = false;
diff --git a/src/components/layout/context.rs b/src/components/layout/context.rs
index 4163de71c6c..fdd6dec0254 100644
--- a/src/components/layout/context.rs
+++ b/src/components/layout/context.rs
@@ -9,7 +9,8 @@ use css::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache};
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::display_list::OpaqueNode;
-use gfx::font_context::{FontContext, FontContextInfo};
+use gfx::font_context::FontContext;
+use gfx::font_cache_task::FontCacheTask;
#[cfg(not(target_os="android"))]
use green::task::GreenTask;
use script::layout_interface::LayoutChan;
@@ -67,8 +68,8 @@ pub struct LayoutContext {
/// A channel up to the layout task.
pub layout_chan: LayoutChan,
- /// Information needed to construct a font context.
- pub font_context_info: FontContextInfo,
+ /// Interface to the font cache task.
+ pub font_cache_task: FontCacheTask,
/// The CSS selector stylist.
///
@@ -105,7 +106,7 @@ impl LayoutContext {
unsafe {
if FONT_CONTEXT == ptr::mut_null() {
- let context = box FontContext::new(self.font_context_info.clone());
+ let context = box FontContext::new(self.font_cache_task.clone());
FONT_CONTEXT = mem::transmute(context)
}
mem::transmute(FONT_CONTEXT)
@@ -172,7 +173,7 @@ impl LayoutContext {
match opt {
Some(c) => context = mem::transmute(c),
None => {
- context = mem::transmute(box FontContext::new(self.font_context_info.clone()))
+ context = mem::transmute(box FontContext::new(self.font_cache_task.clone()))
}
}
font_context.replace(Some(context));
diff --git a/src/components/layout/layout_task.rs b/src/components/layout/layout_task.rs
index f7fd408fd6e..e97057c605c 100644
--- a/src/components/layout/layout_task.rs
+++ b/src/components/layout/layout_task.rs
@@ -27,7 +27,7 @@ use geom::rect::Rect;
use geom::size::Size2D;
use gfx::display_list::{ClipDisplayItemClass, ContentStackingLevel, DisplayItem};
use gfx::display_list::{DisplayItemIterator, DisplayList, OpaqueNode};
-use gfx::font_context::{FontContext, FontContextInfo};
+use gfx::font_context::FontContext;
use gfx::render_task::{RenderMsg, RenderChan, RenderLayer};
use gfx::{render_task, color};
use script::dom::bindings::js::JS;
@@ -44,6 +44,7 @@ use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg};
use servo_msg::compositor_msg::Scrollable;
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, Failure, FailureMsg};
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
+use gfx::font_cache_task::{FontCacheTask};
use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
use servo_util::geometry::Au;
use servo_util::geometry;
@@ -84,6 +85,9 @@ pub struct LayoutTask {
/// The channel on which messages can be sent to the image cache.
pub image_cache_task: ImageCacheTask,
+ /// Public interface to the font cache task.
+ pub font_cache_task: FontCacheTask,
+
/// The local image cache.
pub local_image_cache: Arc<Mutex<LocalImageCache>>,
@@ -278,6 +282,7 @@ impl LayoutTask {
script_chan: ScriptChan,
render_chan: RenderChan,
img_cache_task: ImageCacheTask,
+ font_cache_task: FontCacheTask,
opts: Opts,
time_profiler_chan: TimeProfilerChan,
shutdown_chan: Sender<()>) {
@@ -293,6 +298,7 @@ impl LayoutTask {
script_chan,
render_chan,
img_cache_task,
+ font_cache_task,
&opts,
time_profiler_chan);
layout.start();
@@ -309,6 +315,7 @@ impl LayoutTask {
script_chan: ScriptChan,
render_chan: RenderChan,
image_cache_task: ImageCacheTask,
+ font_cache_task: FontCacheTask,
opts: &Opts,
time_profiler_chan: TimeProfilerChan)
-> LayoutTask {
@@ -328,6 +335,7 @@ impl LayoutTask {
script_chan: script_chan,
render_chan: render_chan,
image_cache_task: image_cache_task.clone(),
+ font_cache_task: font_cache_task,
local_image_cache: local_image_cache,
screen_size: screen_size,
@@ -349,18 +357,12 @@ impl LayoutTask {
// Create a layout context for use in building display lists, hit testing, &c.
fn build_layout_context(&self, reflow_root: &LayoutNode, url: &Url) -> LayoutContext {
- let font_context_info = FontContextInfo {
- backend: self.opts.render_backend,
- needs_font_list: true,
- time_profiler_chan: self.time_profiler_chan.clone(),
- };
-
LayoutContext {
image_cache: self.local_image_cache.clone(),
screen_size: self.screen_size.clone(),
constellation_chan: self.constellation_chan.clone(),
layout_chan: self.chan.clone(),
- font_context_info: font_context_info,
+ font_cache_task: self.font_cache_task.clone(),
stylist: &*self.stylist,
url: (*url).clone(),
reflow_root: OpaqueNodeMethods::from_layout_node(reflow_root),
@@ -594,7 +596,7 @@ impl LayoutTask {
// FIXME(pcwalton): This is a pretty bogus thing to do. Essentially this is a workaround
// for libgreen having slow TLS.
let mut font_context_opt = if self.parallel_traversal.is_none() {
- Some(box FontContext::new(layout_ctx.font_context_info.clone()))
+ Some(box FontContext::new(layout_ctx.font_cache_task.clone()))
} else {
None
};
diff --git a/src/components/layout/text.rs b/src/components/layout/text.rs
index 4f354c96703..5991df7db44 100644
--- a/src/components/layout/text.rs
+++ b/src/components/layout/text.rs
@@ -142,8 +142,8 @@ impl TextRunScanner {
// TODO(#177): Text run creation must account for the renderability of text by
// font group fonts. This is probably achieved by creating the font group above
// and then letting `FontGroup` decide which `Font` to stick into the text run.
- let fontgroup = font_context.get_resolved_font_for_style(&font_style);
- let run = box fontgroup.borrow().create_textrun(
+ let fontgroup = font_context.get_layout_font_group_for_style(&font_style);
+ let run = box fontgroup.create_textrun(
transformed_text.clone(), decoration);
debug!("TextRunScanner: pushing single text fragment in range: {} ({})",
@@ -164,7 +164,7 @@ impl TextRunScanner {
// and then letting `FontGroup` decide which `Font` to stick into the text run.
let in_fragment = &in_fragments[self.clump.begin().to_uint()];
let font_style = in_fragment.font_style();
- let fontgroup = font_context.get_resolved_font_for_style(&font_style);
+ let fontgroup = font_context.get_layout_font_group_for_style(&font_style);
let decoration = in_fragment.text_decoration();
// TODO(#115): Use the actual CSS `white-space` property of the relevant style.
@@ -218,7 +218,7 @@ impl TextRunScanner {
let clump = self.clump;
let run = if clump.length() != CharIndex(0) && run_str.len() > 0 {
Some(Arc::new(box TextRun::new(
- &mut *fontgroup.borrow().fonts.get(0).borrow_mut(),
+ &mut *fontgroup.fonts.get(0).borrow_mut(),
run_str.to_string(), decoration)))
} else {
None
@@ -258,8 +258,8 @@ impl TextRunScanner {
#[inline]
pub fn font_metrics_for_style(font_context: &mut FontContext, font_style: &FontStyle)
-> FontMetrics {
- let fontgroup = font_context.get_resolved_font_for_style(font_style);
- fontgroup.borrow().fonts.get(0).borrow().metrics.clone()
+ let fontgroup = font_context.get_layout_font_group_for_style(font_style);
+ fontgroup.fonts.get(0).borrow().metrics.clone()
}
/// Converts a computed style to a font style used for rendering.
diff --git a/src/components/main/servo.rs b/src/components/main/servo.rs
index 49f68a2bf1b..f845846280e 100644
--- a/src/components/main/servo.rs
+++ b/src/components/main/servo.rs
@@ -20,6 +20,7 @@ extern crate servo_msg = "msg";
#[phase(plugin, link)]
extern crate servo_util = "util";
extern crate green;
+extern crate gfx;
extern crate libc;
extern crate native;
extern crate rustrt;
@@ -35,6 +36,8 @@ use servo_net::image_cache_task::{ImageCacheTask, SyncImageCacheTask};
#[cfg(not(test))]
use servo_net::resource_task::ResourceTask;
#[cfg(not(test))]
+use gfx::font_cache_task::FontCacheTask;
+#[cfg(not(test))]
use servo_util::time::TimeProfiler;
#[cfg(not(test))]
use servo_util::memory::MemoryProfiler;
@@ -115,10 +118,12 @@ pub fn run(opts: opts::Opts) {
} else {
ImageCacheTask(resource_task.clone())
};
+ let font_cache_task = FontCacheTask::new();
let constellation_chan = Constellation::start(compositor_chan,
opts,
resource_task,
image_cache_task,
+ font_cache_task,
time_profiler_chan_clone);
// Send the URL command to the constellation.