Extract mono-cache implementation; lay groundwork for private font matching.

This commit is contained in:
Brian J. Burg 2012-11-07 12:04:17 -08:00
parent a3f4b52c90
commit b8d7824067
18 changed files with 372 additions and 88 deletions

View file

@ -10,7 +10,11 @@ pub use dl = display_list;
pub use display_list::DisplayList; pub use display_list::DisplayList;
pub use font::Font; pub use font::Font;
pub use font_cache::FontCache; pub use font::FontDescriptor;
pub use font::FontGroup;
pub use font::FontSelector;
pub use font::FontStyle;
pub use font::RunMetrics;
pub use font_context::FontContext; pub use font_context::FontContext;
pub use font_matcher::FontMatcher; pub use font_matcher::FontMatcher;
pub use geometry::Au; pub use geometry::Au;

View file

@ -49,7 +49,7 @@ impl DisplayItem {
match *self { match *self {
SolidColor(_, color) => ctx.draw_solid_color(&self.d().bounds, color), SolidColor(_, color) => ctx.draw_solid_color(&self.d().bounds, color),
Text(_, run, range) => { Text(_, run, range) => {
let new_run = @run.deserialize(ctx.font_cache); let new_run = @run.deserialize(ctx.font_ctx);
let font = new_run.font; let font = new_run.font;
let origin = self.d().bounds.origin; let origin = self.d().bounds.origin;
let baseline_origin = Point2D(origin.x, origin.y + font.metrics.ascent); let baseline_origin = Point2D(origin.x, origin.y + font.metrics.ascent);

View file

@ -38,23 +38,147 @@ enum CSSFontWeight {
FontWeight800, FontWeight800,
FontWeight900, FontWeight900,
} }
pub impl CSSFontWeight : cmp::Eq;
struct FontStyle { // TODO: eventually this will be split into the specified and used
// font styles. specified contains uninterpreted CSS font property
// values, while 'used' is attached to gfx::Font to descript the
// instance's properties.
//
// For now, the cases are differentiated with a typedef
pub struct FontStyle {
pt_size: float, pt_size: float,
weight: CSSFontWeight, weight: CSSFontWeight,
italic: bool, italic: bool,
oblique: bool, oblique: bool,
families: ~str,
// TODO: font-stretch, text-decoration, font-variant, size-adjust
} }
struct FontFaceProperties { // TODO(Issue #181): use deriving for trivial cmp::Eq implementations
pub impl FontStyle : cmp::Eq {
pure fn eq(other: &FontStyle) -> bool {
use std::cmp::FuzzyEq;
self.pt_size.fuzzy_eq(&other.pt_size) &&
self.weight == other.weight &&
self.italic == other.italic &&
self.oblique == other.oblique &&
self.families == other.families
}
pure fn ne(other: &FontStyle) -> bool { !self.eq(other) }
}
pub type SpecifiedFontStyle = FontStyle;
pub type UsedFontStyle = FontStyle;
// TODO: move me to layout
struct ResolvedFont {
group: @FontGroup,
style: SpecifiedFontStyle,
}
// 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.
pub struct FontDescriptor {
style: UsedFontStyle,
selector: FontSelector,
}
// TODO(Issue #181): use deriving for trivial cmp::Eq implementations
pub impl FontDescriptor : cmp::Eq {
pure fn eq(other: &FontDescriptor) -> bool {
self.style == other.style &&
self.selector == other.selector
}
pure fn ne(other: &FontDescriptor) -> bool { !self.eq(other) }
}
pub impl FontDescriptor {
static pure fn new(style: &UsedFontStyle, selector: &FontSelector) -> FontDescriptor {
FontDescriptor {
style: copy *style,
selector: copy *selector,
}
}
}
// A FontSelector is a platform-specific strategy for serializing face names.
pub enum FontSelector {
SelectorPlatformName(~str),
SelectorStubDummy, // aka, use Josephin Sans
}
// TODO(Issue #181): use deriving for trivial cmp::Eq implementations
pub impl FontSelector : cmp::Eq {
pure fn eq(other: &FontSelector) -> bool {
match (self, *other) {
(SelectorStubDummy, SelectorStubDummy) => true,
(SelectorPlatformName(a), SelectorPlatformName(b)) => a == b,
_ => false
}
}
pure fn ne(other: &FontSelector) -> bool { !self.eq(other) }
}
// Holds a specific font family, and the various
pub struct FontFamily {
family_name: @str, family_name: @str,
face_name: ~str, entries: ~[@FontEntry],
priv weight: u16,
priv italic: bool,
} }
impl FontFaceProperties { // This struct is the result of mapping a specified FontStyle into the
pure fn is_bold() -> bool { self.weight >= (500 as u16) } // 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 {
families: @str,
// style of the first western font in group, which is
// used for purposes of calculating text run metrics.
style: UsedFontStyle,
fonts: ~[@Font],
}
pub impl FontGroup {
static fn new(families: @str, style: &UsedFontStyle, fonts: ~[@Font]) -> FontGroup {
FontGroup {
families: families,
style: copy *style,
fonts: move fonts,
}
}
}
// 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.
struct FontEntry {
family: @FontFamily,
face_name: ~str,
priv weight: CSSFontWeight,
priv italic: bool,
// TODO: array of OpenType features, etc.
}
impl FontEntry {
pure fn is_bold() -> bool {
match self.weight {
FontWeight900 | FontWeight800 | FontWeight700 | FontWeight600 => true,
_ => false
}
}
pure fn is_italic() -> bool { self.italic } pure fn is_italic() -> bool { self.italic }
} }
@ -69,7 +193,7 @@ struct RunMetrics {
} }
/** /**
A font handle. Layout can use this to calculate glyph metrics A font instance. Layout can use this to calculate glyph metrics
and the renderer can use it to render text. and the renderer can use it to render text.
*/ */
struct Font { struct Font {
@ -77,7 +201,7 @@ struct Font {
priv handle: FontHandle, priv handle: FontHandle,
priv mut azure_font: Option<AzScaledFontRef>, priv mut azure_font: Option<AzScaledFontRef>,
priv mut shaper: Option<@Shaper>, priv mut shaper: Option<@Shaper>,
style: FontStyle, style: UsedFontStyle,
metrics: FontMetrics, metrics: FontMetrics,
drop { drop {
@ -88,7 +212,7 @@ struct Font {
impl Font { impl Font {
// TODO: who should own fontbuf? // TODO: who should own fontbuf?
static fn new(fontbuf: @~[u8], handle: FontHandle, style: FontStyle) -> Font { static fn new(fontbuf: @~[u8], handle: FontHandle, style: UsedFontStyle) -> Font {
let metrics = handle.get_metrics(); let metrics = handle.get_metrics();
Font { Font {
@ -214,6 +338,7 @@ pub trait FontMethods {
fn draw_text_into_context(rctx: &RenderContext, run: &TextRun, range: Range, baseline_origin: Point2D<Au>); fn draw_text_into_context(rctx: &RenderContext, run: &TextRun, range: Range, baseline_origin: Point2D<Au>);
fn measure_text(&TextRun, Range) -> RunMetrics; fn measure_text(&TextRun, Range) -> RunMetrics;
fn shape_text(@self, &str) -> GlyphStore; fn shape_text(@self, &str) -> GlyphStore;
fn get_descriptor() -> FontDescriptor;
fn buf(&self) -> @~[u8]; fn buf(&self) -> @~[u8];
// these are used to get glyphs and advances in the case that the // these are used to get glyphs and advances in the case that the
@ -315,6 +440,12 @@ pub impl Font : FontMethods {
return move store; return move store;
} }
fn get_descriptor() -> FontDescriptor {
// TODO(Issue #174): implement by-platform-name FontSelectors,
// probably by adding such an API to FontHandle.
FontDescriptor::new(&font_context::dummy_style(), &SelectorStubDummy)
}
fn buf(&self) -> @~[u8] { fn buf(&self) -> @~[u8] {
self.fontbuf self.fontbuf
} }

View file

@ -1,14 +1,8 @@
/*
use font::{Font, FontStyle, FontWeight300}; use font::{Font, FontStyle, FontWeight300};
use native::{FontHandle, FontContext}; use native::{FontHandle, FontContext};
// TODO(Issue #164): delete, and get default font from font list // Font cache that reuses gfx::Font instances.
const TEST_FONT: [u8 * 33004] = #include_bin("JosefinSans-SemiBold.ttf");
fn test_font_bin() -> ~[u8] {
return vec::from_fn(33004, |i| TEST_FONT[i]);
}
// Dummy font cache.
struct FontCache { struct FontCache {
fctx: @FontContext, fctx: @FontContext,
@ -24,36 +18,19 @@ impl FontCache {
} }
pub fn get_test_font(@self) -> @Font { pub fn get_test_font(@self) -> @Font {
let dummy_style = FontStyle {
pt_size: 40f,
weight: FontWeight300,
italic: false,
oblique: false
};
return match self.cached_font { return match self.cached_font {
Some(font) => font, Some(font) => font,
None => match self.get_font(&dummy_style) { None => match self.get_font(&dummy_style) {
Ok(font) => { self.cached_font = Some(font); font } Ok(font) => { self.cached_font = Some(font); font }
Err(*) => /* FIXME */ fail Err(*) => fail
} }
} }
} }
// TODO: maybe FontStyle should be canonicalized when used in FontCache?
priv fn create_font(style: &FontStyle) -> Result<@Font, ()> {
let font_bin = @test_font_bin();
let native_font = FontHandle::new(self.fctx, font_bin, style.pt_size);
let native_font = if native_font.is_ok() {
result::unwrap(move native_font)
} else {
return Err(native_font.get_err());
};
return Ok(@Font::new(font_bin, move native_font, copy *style));
}
pub fn get_font(@self, style: &FontStyle) -> Result<@Font, ()> { pub fn get_font(@self, style: &FontStyle) -> Result<@Font, ()> {
self.create_font(style) self.create_font(style)
} }
} }
*/

View file

@ -1,3 +1,34 @@
use dvec::DVec;
use util::cache;
use gfx::{
FontDescriptor,
FontSelector,
FontStyle,
};
use gfx::font::{SelectorPlatformName, SelectorStubDummy, SpecifiedFontStyle};
use gfx::native::FontHandle;
// TODO(Issue #164): delete, and get default font from font list
const TEST_FONT: [u8 * 33004] = #include_bin("JosefinSans-SemiBold.ttf");
fn test_font_bin() -> ~[u8] {
return vec::from_fn(33004, |i| TEST_FONT[i]);
}
// TODO(Rust #3934): creating lots of new dummy styles is a workaround
// for not being able to store symbolic enums in top-level constants.
pub fn dummy_style() -> FontStyle {
use gfx::font::FontWeight300;
return FontStyle {
pt_size: 20f,
weight: FontWeight300,
italic: false,
oblique: false,
families: ~"Helvetica, serif",
}
}
// TODO(Issue #163): this is a workaround for static methods and // TODO(Issue #163): this is a workaround for static methods and
// typedefs not working well together. It should be removed. // typedefs not working well together. It should be removed.
@ -5,21 +36,91 @@
// to conditionally define the entire impl. // to conditionally define the entire impl.
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
type FontContext/& = quartz::font_context::QuartzFontContext; type FontContextHandle/& = quartz::font_context::QuartzFontContext;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
type FontContext/& = freetype::font_context::FreeTypeFontContext; type FontContextHandle/& = freetype::font_context::FreeTypeFontContext;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub impl FontContext { pub impl FontContextHandle {
static pub fn new() -> FontContext { static pub fn new() -> FontContextHandle {
quartz::font_context::QuartzFontContext::new() quartz::font_context::QuartzFontContext::new()
} }
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub impl FontContext { pub impl FontContextHandle {
static pub fn new() -> FontContext { static pub fn new() -> FontContextHandle {
freetype::font_context::FreeTypeFontContext::new() freetype::font_context::FreeTypeFontContext::new()
} }
} }
pub struct FontContext {
instance_cache: cache::MonoCache<FontDescriptor, @Font>,
handle: FontContextHandle,
}
pub impl FontContext {
static fn new() -> FontContext {
FontContext {
// TODO(Rust #3902): remove extraneous type parameters once they are inferred correctly.
instance_cache: cache::new::<FontDescriptor, @Font, cache::MonoCache<FontDescriptor, @Font>>(10),
handle: FontContextHandle::new()
}
}
fn get_resolved_font_for_style(style: &SpecifiedFontStyle) -> @FontGroup {
// TODO(Issue #178, E): implement a cache of FontGroup instances.
self.create_font_group(style)
}
fn get_font_by_descriptor(desc: &FontDescriptor) -> Result<@Font, ()> {
match self.instance_cache.find(desc) {
Some(f) => Ok(f),
None => {
let result = self.create_font_instance(desc);
match result {
Ok(font) => {
self.instance_cache.insert(desc, font);
}, _ => {}
};
result
}
}
}
priv fn create_font_group(style: &SpecifiedFontStyle) -> @FontGroup {
// TODO(Issue #178, D): implement private font matching
// TODO(Issue #174): implement by-platform-name FontSelectors
let desc = FontDescriptor::new(&font_context::dummy_style(), &SelectorStubDummy);
let fonts = DVec();
match self.get_font_by_descriptor(&desc) {
Ok(instance) => fonts.push(instance),
Err(()) => {}
}
assert fonts.len() > 0;
// TODO(Issue #179): Split FontStyle into specified and used styles
let used_style = copy *style;
@FontGroup::new(style.families.to_managed(), &used_style, dvec::unwrap(move fonts))
}
priv fn create_font_instance(desc: &FontDescriptor) -> Result<@Font, ()> {
match desc.selector {
SelectorStubDummy => {
let font_bin = @test_font_bin();
let handle = FontHandle::new(&self.handle, font_bin, desc.style.pt_size);
let handle = if handle.is_ok() {
result::unwrap(move handle)
} else {
return Err(handle.get_err());
};
return Ok(@Font::new(font_bin, move handle, copy desc.style));
},
// TODO(Issue #174): implement by-platform-name font selectors.
SelectorPlatformName(_) => { fail ~"FontContext::create_font_instance() can't yet handle SelectorPlatformName." }
}
}
}

View file

@ -20,14 +20,14 @@ pub type FontHandle/& = freetype::font_handle::FreeTypeFontHandle;
// to conditionally define the entire impl. // to conditionally define the entire impl.
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
impl FontHandle { impl FontHandle {
static pub fn new(fctx: &native::FontContext, buf: @~[u8], pt_size: float) -> Result<FontHandle, ()> { static pub fn new(fctx: &native::FontContextHandle, buf: @~[u8], pt_size: float) -> Result<FontHandle, ()> {
quartz::font_handle::QuartzFontHandle::new(fctx, buf, pt_size) quartz::font_handle::QuartzFontHandle::new(fctx, buf, pt_size)
} }
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
impl FontHandle { impl FontHandle {
static pub fn new(fctx: &native::FontContext, buf: @~[u8], pt_size: float) -> Result<FontHandle, ()> { static pub fn new(fctx: &native::FontContextHandle, buf: @~[u8], pt_size: float) -> Result<FontHandle, ()> {
freetype::font_handle::FreeTypeFontHandle::new(fctx, buf, pt_size) freetype::font_handle::FreeTypeFontHandle::new(fctx, buf, pt_size)
} }
} }

View file

@ -1,11 +1,9 @@
extern mod harfbuzz; extern mod harfbuzz;
use gfx::au;
use gfx::{ use gfx::{
au,
Au, Au,
Font, Font,
FontCache,
}; };
use geom::point::Point2D; use geom::point::Point2D;

View file

@ -5,4 +5,4 @@ Note that you still must define each of the files as a module in
servo.rc. This is not ideal and may be changed in the future. */ servo.rc. This is not ideal and may be changed in the future. */
pub use font_handle::FontHandle; pub use font_handle::FontHandle;
pub use font_context::FontContext; pub use font_context::FontContextHandle;

View file

@ -1,12 +1,12 @@
use au = geometry;
use compositor::LayerBuffer; use compositor::LayerBuffer;
use gfx::au;
use gfx::{ use gfx::{
Au,
Font, Font,
FontCache, FontContext,
TextRun, TextRun,
}; };
use image::base::Image; use image::base::Image;
use au::Au;
use util::range::Range; use util::range::Range;
use cairo::cairo_hl::ImageSurface; use cairo::cairo_hl::ImageSurface;
@ -23,7 +23,7 @@ use azure::azure_hl::{DrawTarget, Linear};
struct RenderContext { struct RenderContext {
canvas: &LayerBuffer, canvas: &LayerBuffer,
font_cache: @FontCache, font_ctx: @FontContext,
} }
impl RenderContext { impl RenderContext {

View file

@ -9,7 +9,6 @@ use geom::matrix2d::Matrix2D;
use dl = display_list; use dl = display_list;
use gfx::{ use gfx::{
FontCache,
FontContext, FontContext,
RenderContext, RenderContext,
RenderLayer, RenderLayer,
@ -42,7 +41,7 @@ pub fn RenderTask<C: Compositor Send>(compositor: C) -> RenderTask {
port: po, port: po,
compositor: move compositor, compositor: move compositor,
mut layer_buffer_set_port: Cell(move layer_buffer_set_port), mut layer_buffer_set_port: Cell(move layer_buffer_set_port),
font_cache: @FontCache::new(@FontContext::new()), font_ctx: @FontContext::new(),
}.start(); }.start();
} }
} }
@ -51,7 +50,7 @@ priv struct Renderer<C: Compositor Send> {
port: comm::Port<Msg>, port: comm::Port<Msg>,
compositor: C, compositor: C,
layer_buffer_set_port: Cell<pipes::Port<LayerBufferSet>>, layer_buffer_set_port: Cell<pipes::Port<LayerBufferSet>>,
font_cache: @FontCache font_ctx: @FontContext
} }
impl<C: Compositor Send> Renderer<C> { impl<C: Compositor Send> Renderer<C> {
@ -97,7 +96,7 @@ impl<C: Compositor Send> Renderer<C> {
|render_layer, layer_buffer| { |render_layer, layer_buffer| {
let ctx = RenderContext { let ctx = RenderContext {
canvas: layer_buffer, canvas: layer_buffer,
font_cache: self.font_cache font_ctx: self.font_ctx
}; };
// Apply the translation to render the tile we want. // Apply the translation to render the tile we want.

View file

@ -1,11 +1,15 @@
use arc = std::arc; use arc = std::arc;
use arc::ARC; use arc::ARC;
use au = gfx::geometry;
use font::{RunMetrics, Font};
use font_cache::FontCache;
use geom::point::Point2D; use geom::point::Point2D;
use geom::size::Size2D; use geom::size::Size2D;
use gfx::geometry::Au; use gfx::au;
use gfx::{
Au,
Font,
FontContext,
FontDescriptor,
RunMetrics,
};
use glyph::GlyphStore; use glyph::GlyphStore;
use layout::context::LayoutContext; use layout::context::LayoutContext;
use libc::{c_void}; use libc::{c_void};
@ -23,16 +27,20 @@ pub struct TextRun {
// we instead use ARC<TextRun> everywhere. // we instead use ARC<TextRun> everywhere.
pub struct SendableTextRun { pub struct SendableTextRun {
text: ~str, text: ~str,
font_descriptor: (), font: FontDescriptor,
priv glyphs: GlyphStore, priv glyphs: GlyphStore,
} }
impl SendableTextRun { impl SendableTextRun {
pub fn deserialize(&self, cache: @FontCache) -> TextRun { pub fn deserialize(&self, fctx: @FontContext) -> TextRun {
let font = match fctx.get_font_by_descriptor(&self.font) {
Ok(f) => f,
Err(_) => fail fmt!("Font descriptor deserialization failed! desc=%?", self.font)
};
TextRun { TextRun {
text: copy self.text, text: copy self.text,
// TODO: actually deserialize a font descriptor thingy font: font,
font: cache.get_test_font(),
glyphs: copy self.glyphs glyphs: copy self.glyphs
} }
} }
@ -49,11 +57,10 @@ impl TextRun {
return move run; return move run;
} }
pub pure fn serialize(&self, _cache: @FontCache) -> SendableTextRun { pub fn serialize(&self) -> SendableTextRun {
SendableTextRun { SendableTextRun {
text: copy self.text, text: copy self.text,
// TODO: actually serialize a font descriptor thingy font: self.font.get_descriptor(),
font_descriptor: (),
glyphs: copy self.glyphs, glyphs: copy self.glyphs,
} }
} }

View file

@ -409,9 +409,7 @@ impl RenderBox : RenderBoxMethods {
match *self { match *self {
UnscannedTextBox(*) => fail ~"Shouldn't see unscanned boxes here.", UnscannedTextBox(*) => fail ~"Shouldn't see unscanned boxes here.",
TextBox(_,d) => { TextBox(_,d) => {
list.append_item(~DisplayItem::new_Text(&abs_box_bounds, list.append_item(~DisplayItem::new_Text(&abs_box_bounds, ~d.run.serialize(), d.range));
~d.run.serialize(builder.ctx.font_cache),
d.range));
// debug frames for text box bounds // debug frames for text box bounds
debug!("%?", { debug!("%?", {
list.append_item(~DisplayItem::new_Border(&abs_box_bounds, au::from_px(1), list.append_item(~DisplayItem::new_Border(&abs_box_bounds, au::from_px(1),

View file

@ -1,7 +1,7 @@
use geom::rect::Rect; use geom::rect::Rect;
use gfx::{ use gfx::{
Au, Au,
FontCache, FontContext,
}; };
use resource::local_image_cache::LocalImageCache; use resource::local_image_cache::LocalImageCache;
use std::net::url::Url; use std::net::url::Url;
@ -9,7 +9,7 @@ use std::net::url::Url;
/* Represents layout task context. */ /* Represents layout task context. */
struct LayoutContext { struct LayoutContext {
font_cache: @FontCache, font_ctx: @FontContext,
image_cache: @LocalImageCache, image_cache: @LocalImageCache,
doc_url: Url, doc_url: Url,
screen_size: Rect<Au> screen_size: Rect<Au>

View file

@ -7,6 +7,7 @@ use geom::point::Point2D;
use geom::rect::Rect; use geom::rect::Rect;
use geom::size::Size2D; use geom::size::Size2D;
use gfx::display_list::{DisplayList, DisplayListBuilder}; use gfx::display_list::{DisplayList, DisplayListBuilder};
use gfx::font::FontStyle;
use gfx::geometry::Au; use gfx::geometry::Au;
use layout::box::*; use layout::box::*;
use layout::context::LayoutContext; use layout::context::LayoutContext;
@ -235,8 +236,13 @@ impl TextRunScanner {
// TODO(Issue #115): use actual CSS 'white-space' property of relevant style. // TODO(Issue #115): use actual CSS 'white-space' property of relevant style.
let compression = CompressWhitespaceNewline; let compression = CompressWhitespaceNewline;
let transformed_text = transform_text(text, compression); let transformed_text = transform_text(text, compression);
// TODO(Issue #116): use actual font for corresponding DOM node to create text run. // TODO(Issue #116): use actual font and style for corresponding
let run = @TextRun::new(ctx.font_cache.get_test_font(), move transformed_text); // DOM node to create text run.
// TODO(Issue #177): text run creation must account for text-renderability by fontgroup fonts.
// this is probably achieved by creating fontgroup above, and then letting FontGroup decide
// which Font to stick into the TextRun.
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&gfx::font_context::dummy_style());
let run = @TextRun::new(fontgroup.fonts[0], move transformed_text);
debug!("TextRunScanner: pushing single text box in range: %?", self.clump); debug!("TextRunScanner: pushing single text box in range: %?", self.clump);
let new_box = layout::text::adapt_textbox_with_range(in_boxes[self.clump.begin()].d(), run, let new_box = layout::text::adapt_textbox_with_range(in_boxes[self.clump.begin()].d(), run,
Range(0, run.text.len())); Range(0, run.text.len()));
@ -269,7 +275,11 @@ impl TextRunScanner {
// create the run, then make new boxes with the run and adjusted text indices // create the run, then make new boxes with the run and adjusted text indices
// TODO(Issue #116): use actual font for corresponding DOM node to create text run. // TODO(Issue #116): use actual font for corresponding DOM node to create text run.
let run = @gfx::TextRun::new(ctx.font_cache.get_test_font(), move run_str); // TODO(Issue #177): text run creation must account for text-renderability by fontgroup fonts.
// this is probably achieved by creating fontgroup above, and then letting FontGroup decide
// which Font to stick into the TextRun.
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&gfx::font_context::dummy_style());
let run = @TextRun::new(fontgroup.fonts[0], move run_str);
debug!("TextRunScanner: pushing box(es) in range: %?", self.clump); debug!("TextRunScanner: pushing box(es) in range: %?", self.clump);
for self.clump.eachi |i| { for self.clump.eachi |i| {
let range = new_ranges[i - self.clump.begin()]; let range = new_ranges[i - self.clump.begin()];

View file

@ -11,11 +11,10 @@ use dom::node::{Node, LayoutData};
use geom::point::Point2D; use geom::point::Point2D;
use geom::rect::Rect; use geom::rect::Rect;
use geom::size::Size2D; use geom::size::Size2D;
use gfx::{au, dl};
use gfx::{ use gfx::{
au, dl,
Au, Au,
DisplayList, DisplayList,
FontCache,
FontContext, FontContext,
FontMatcher, FontMatcher,
RenderLayer, RenderLayer,
@ -81,7 +80,7 @@ struct Layout {
local_image_cache: @LocalImageCache, local_image_cache: @LocalImageCache,
from_content: comm::Port<Msg>, from_content: comm::Port<Msg>,
font_cache: @FontCache, font_ctx: @FontContext,
font_matcher: @FontMatcher, font_matcher: @FontMatcher,
// This is used to root auxilliary RCU reader data // This is used to root auxilliary RCU reader data
layout_refs: DVec<@LayoutData>, layout_refs: DVec<@LayoutData>,
@ -100,7 +99,7 @@ fn Layout(render_task: RenderTask,
local_image_cache: @LocalImageCache(move image_cache_task), local_image_cache: @LocalImageCache(move image_cache_task),
from_content: from_content, from_content: from_content,
font_matcher: @FontMatcher::new(fctx), font_matcher: @FontMatcher::new(fctx),
font_cache: @FontCache::new(fctx), font_ctx: fctx,
layout_refs: DVec(), layout_refs: DVec(),
css_select_ctx: Mut(new_css_select_ctx()) css_select_ctx: Mut(new_css_select_ctx())
} }
@ -169,7 +168,7 @@ impl Layout {
let layout_ctx = LayoutContext { let layout_ctx = LayoutContext {
image_cache: self.local_image_cache, image_cache: self.local_image_cache,
font_cache: self.font_cache, font_ctx: self.font_ctx,
doc_url: move doc_url, doc_url: move doc_url,
screen_size: Rect(Point2D(Au(0), Au(0)), screen_size) screen_size: Rect(Point2D(Au(0), Au(0)), screen_size)
}; };

View file

@ -142,6 +142,7 @@ pub mod resource {
pub mod util { pub mod util {
pub mod actor; pub mod actor;
pub mod cache;
pub mod range; pub mod range;
pub mod text; pub mod text;
pub mod time; pub mod time;

59
src/servo/util/cache.rs Normal file
View file

@ -0,0 +1,59 @@
use core::cmp::*;
trait Cache<K: Copy Eq, V: Copy> {
static fn new(size: uint) -> self;
fn insert(key: &K, value: V);
fn find(key: &K) -> Option<V>;
fn find_or_create(key: &K, blk: pure fn&(&K) -> V) -> V;
fn evict_all();
}
pub struct MonoCache<K: Copy Eq, V: Copy> {
mut entry: Option<(K,V)>,
}
pub impl<K: Copy Eq, V: Copy> MonoCache<K,V> : Cache<K,V> {
static fn new(_size: uint) -> MonoCache<K,V> {
MonoCache { entry: None }
}
fn insert(key: &K, value: V) {
self.entry = Some((copy *key, value));
}
fn find(key: &K) -> Option<V> {
match self.entry {
None => None,
Some((ref k,v)) => if *k == *key { Some(v) } else { None }
}
}
fn find_or_create(key: &K, blk: pure fn&(&K) -> V) -> V {
return match self.find(key) {
None => {
let value = blk(key);
self.entry = Some((copy *key, copy value));
move value
},
Some(v) => v
};
}
fn evict_all() {
self.entry = None;
}
}
#[test]
fn test_monocache() {
// TODO: this is hideous because of Rust Issue #3902
let cache = cache::new::<uint, @str, MonoCache<uint, @str>>(10);
let one = @"one";
let two = @"two";
cache.insert(1, one);
assert cache.find(1).is_some();
assert cache.find(2).is_none();
cache.find_or_create(2, |_v| { two });
assert cache.find(2).is_some();
assert cache.find(1).is_none();
}

View file

@ -162,7 +162,7 @@ fn test_transform_discard_newline() {
~"foo bar baz", ~"foo bar baz",
~"foobarbaz"]; ~"foobarbaz"];
assert core::vec::same_length(test_strs, oracle_strs); assert test_strs.len() == oracle_strs.len();
let mode = DiscardNewline; let mode = DiscardNewline;
for uint::range(0, test_strs.len()) |i| { for uint::range(0, test_strs.len()) |i| {
@ -188,7 +188,7 @@ fn test_transform_compress_whitespace() {
~"foo bar baz", ~"foo bar baz",
~"foobarbaz\n\n"]; ~"foobarbaz\n\n"];
assert core::vec::same_length(test_strs, oracle_strs); assert test_strs.len() == oracle_strs.len();
let mode = CompressWhitespace; let mode = CompressWhitespace;
for uint::range(0, test_strs.len()) |i| { for uint::range(0, test_strs.len()) |i| {
@ -214,7 +214,7 @@ fn test_transform_compress_whitespace_newline() {
~"foo bar baz", ~"foo bar baz",
~"foobarbaz "]; ~"foobarbaz "];
assert core::vec::same_length(test_strs, oracle_strs); assert test_strs.len() == oracle_strs.len();
let mode = CompressWhitespaceNewline; let mode = CompressWhitespaceNewline;
for uint::range(0, test_strs.len()) |i| { for uint::range(0, test_strs.len()) |i| {