mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Merge pull request #1342 from ksh8281/remove_@_from_font_context
Remove @ from font context, remove SendableTextRun
This commit is contained in:
commit
403958aed7
17 changed files with 255 additions and 218 deletions
|
@ -18,7 +18,7 @@ use color::Color;
|
|||
use servo_util::geometry::Au;
|
||||
use style::computed_values::border_style;
|
||||
use render_context::RenderContext;
|
||||
use text::SendableTextRun;
|
||||
use text::TextRun;
|
||||
|
||||
use std::cast::transmute_region;
|
||||
use geom::{Point2D, Rect, Size2D, SideOffsets2D};
|
||||
|
@ -47,7 +47,7 @@ impl<E> DisplayList<E> {
|
|||
}
|
||||
|
||||
/// Draws the display list into the given render context.
|
||||
pub fn draw_into_context(&self, render_context: &RenderContext) {
|
||||
pub fn draw_into_context(&self, render_context: &mut RenderContext) {
|
||||
debug!("Beginning display list.");
|
||||
for item in self.list.iter() {
|
||||
// FIXME(Issue #150): crashes
|
||||
|
@ -87,7 +87,7 @@ pub struct SolidColorDisplayItem<E> {
|
|||
/// Renders text.
|
||||
pub struct TextDisplayItem<E> {
|
||||
base: BaseDisplayItem<E>,
|
||||
text_run: ~SendableTextRun,
|
||||
text_run: ~TextRun,
|
||||
range: Range,
|
||||
color: Color,
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ pub struct ClipDisplayItem<E> {
|
|||
|
||||
impl<E> DisplayItem<E> {
|
||||
/// Renders this display item into the given render context.
|
||||
fn draw_into_context(&self, render_context: &RenderContext) {
|
||||
fn draw_into_context(&self, render_context: &mut RenderContext) {
|
||||
match *self {
|
||||
SolidColorDisplayItemClass(ref solid_color) => {
|
||||
render_context.draw_solid_color(&solid_color.base.bounds, solid_color.color)
|
||||
|
@ -142,36 +142,38 @@ impl<E> DisplayItem<E> {
|
|||
debug!("Drawing text at {:?}.", text.base.bounds);
|
||||
|
||||
// FIXME(pcwalton): Allocating? Why?
|
||||
let new_run = @text.text_run.deserialize(render_context.font_ctx);
|
||||
let font = render_context.font_ctx.get_font_by_descriptor(&text.text_run.font_descriptor).unwrap();
|
||||
|
||||
let font = new_run.font;
|
||||
let font_metrics = font.with_borrow( |font| {
|
||||
font.metrics.clone()
|
||||
});
|
||||
let origin = text.base.bounds.origin;
|
||||
let baseline_origin = Point2D(origin.x, origin.y + font.metrics.ascent);
|
||||
|
||||
font.draw_text_into_context(render_context,
|
||||
new_run,
|
||||
&text.range,
|
||||
baseline_origin,
|
||||
text.color);
|
||||
|
||||
let baseline_origin = Point2D(origin.x, origin.y + font_metrics.ascent);
|
||||
font.with_mut_borrow( |font| {
|
||||
font.draw_text_into_context(render_context,
|
||||
&text.text_run,
|
||||
&text.range,
|
||||
baseline_origin,
|
||||
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 = 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;
|
||||
|
||||
if new_run.decoration.underline {
|
||||
if text.text_run.decoration.underline {
|
||||
let underline_y = baseline_origin.y - underline_offset;
|
||||
let underline_bounds = Rect(Point2D(baseline_origin.x, underline_y),
|
||||
Size2D(width, underline_size));
|
||||
render_context.draw_solid_color(&underline_bounds, text.color);
|
||||
}
|
||||
if new_run.decoration.overline {
|
||||
if text.text_run.decoration.overline {
|
||||
let overline_bounds = Rect(Point2D(baseline_origin.x, origin.y),
|
||||
Size2D(width, underline_size));
|
||||
render_context.draw_solid_color(&overline_bounds, text.color);
|
||||
}
|
||||
if new_run.decoration.line_through {
|
||||
if text.text_run.decoration.line_through {
|
||||
let strikeout_y = baseline_origin.y - strikeout_offset;
|
||||
let strikeout_bounds = Rect(Point2D(baseline_origin.x, strikeout_y),
|
||||
Size2D(width, strikeout_size));
|
||||
|
|
|
@ -11,6 +11,7 @@ use std::cast;
|
|||
use std::ptr;
|
||||
use std::str;
|
||||
use std::vec;
|
||||
use std::rc::RcMut;
|
||||
use servo_util::cache::{Cache, HashCache};
|
||||
use servo_util::range::Range;
|
||||
use servo_util::time::ProfilerChan;
|
||||
|
@ -75,6 +76,7 @@ pub trait FontTableMethods {
|
|||
fn with_buffer(&self, &fn(*u8, uint));
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct FontMetrics {
|
||||
underline_size: Au,
|
||||
underline_offset: Au,
|
||||
|
@ -171,15 +173,15 @@ pub enum FontSelector {
|
|||
// 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,
|
||||
families: ~str,
|
||||
// style of the first western font in group, which is
|
||||
// used for purposes of calculating text run metrics.
|
||||
style: UsedFontStyle,
|
||||
fonts: ~[@mut Font],
|
||||
fonts: ~[RcMut<Font>]
|
||||
}
|
||||
|
||||
impl FontGroup {
|
||||
pub fn new(families: @str, style: &UsedFontStyle, fonts: ~[@mut Font]) -> FontGroup {
|
||||
pub fn new(families: ~str, style: &UsedFontStyle, fonts: ~[RcMut<Font>]) -> FontGroup {
|
||||
FontGroup {
|
||||
families: families,
|
||||
style: (*style).clone(),
|
||||
|
@ -195,7 +197,9 @@ impl FontGroup {
|
|||
assert!(self.fonts.len() > 0);
|
||||
|
||||
// TODO(Issue #177): Actually fall back through the FontGroup when a font is unsuitable.
|
||||
return TextRun::new(self.fonts[0], text, decoration);
|
||||
self.fonts[0].with_mut_borrow(|font| {
|
||||
TextRun::new(font, text.clone(), decoration)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,7 +238,7 @@ and the renderer can use it to render text.
|
|||
pub struct Font {
|
||||
priv handle: FontHandle,
|
||||
priv azure_font: Option<ScaledFont>,
|
||||
priv shaper: Option<@Shaper>,
|
||||
priv shaper: Option<Shaper>,
|
||||
style: UsedFontStyle,
|
||||
metrics: FontMetrics,
|
||||
backend: BackendType,
|
||||
|
@ -243,13 +247,13 @@ pub struct Font {
|
|||
glyph_advance_cache: HashCache<u32, FractionalPixel>,
|
||||
}
|
||||
|
||||
impl Font {
|
||||
impl<'self> Font {
|
||||
pub fn new_from_buffer(ctx: &FontContext,
|
||||
buffer: ~[u8],
|
||||
style: &SpecifiedFontStyle,
|
||||
backend: BackendType,
|
||||
profiler_chan: ProfilerChan)
|
||||
-> Result<@mut Font, ()> {
|
||||
-> Result<RcMut<Font>, ()> {
|
||||
let handle = FontHandleMethods::new_from_buffer(&ctx.handle, buffer, style);
|
||||
let handle: FontHandle = if handle.is_ok() {
|
||||
handle.unwrap()
|
||||
|
@ -260,7 +264,7 @@ impl Font {
|
|||
let metrics = handle.get_metrics();
|
||||
// TODO(Issue #179): convert between specified and used font style here?
|
||||
|
||||
return Ok(@mut Font {
|
||||
return Ok(RcMut::new(Font {
|
||||
handle: handle,
|
||||
azure_font: None,
|
||||
shaper: None,
|
||||
|
@ -270,15 +274,15 @@ impl Font {
|
|||
profiler_chan: profiler_chan,
|
||||
shape_cache: HashCache::new(),
|
||||
glyph_advance_cache: HashCache::new(),
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn new_from_adopted_handle(_fctx: &FontContext, handle: FontHandle,
|
||||
style: &SpecifiedFontStyle, backend: BackendType,
|
||||
profiler_chan: ProfilerChan) -> @mut Font {
|
||||
profiler_chan: ProfilerChan) -> Font {
|
||||
let metrics = handle.get_metrics();
|
||||
|
||||
@mut Font {
|
||||
Font {
|
||||
handle: handle,
|
||||
azure_font: None,
|
||||
shaper: None,
|
||||
|
@ -293,7 +297,7 @@ impl Font {
|
|||
|
||||
pub fn new_from_existing_handle(fctx: &FontContext, handle: &FontHandle,
|
||||
style: &SpecifiedFontStyle, backend: BackendType,
|
||||
profiler_chan: ProfilerChan) -> Result<@mut Font,()> {
|
||||
profiler_chan: ProfilerChan) -> Result<RcMut<Font>,()> {
|
||||
|
||||
// TODO(Issue #179): convert between specified and used font style here?
|
||||
let styled_handle = match handle.clone_with_style(&fctx.handle, style) {
|
||||
|
@ -301,19 +305,22 @@ impl Font {
|
|||
Err(()) => return Err(())
|
||||
};
|
||||
|
||||
return Ok(Font::new_from_adopted_handle(fctx, styled_handle, style, backend, profiler_chan));
|
||||
return Ok(RcMut::new(Font::new_from_adopted_handle(fctx, styled_handle, style, backend, profiler_chan)));
|
||||
}
|
||||
|
||||
fn get_shaper(@mut self) -> @Shaper {
|
||||
fn make_shaper(&'self mut self) -> &'self Shaper {
|
||||
// fast path: already created a shaper
|
||||
match self.shaper {
|
||||
Some(shaper) => { return shaper; },
|
||||
Some(ref shaper) => {
|
||||
let s: &'self Shaper = shaper;
|
||||
return s;
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
|
||||
let shaper = @Shaper::new(self);
|
||||
let shaper = Shaper::new(self);
|
||||
self.shaper = Some(shaper);
|
||||
shaper
|
||||
self.shaper.get_ref()
|
||||
}
|
||||
|
||||
pub fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
||||
|
@ -369,7 +376,7 @@ impl Font {
|
|||
#[fixed_stack_segment]
|
||||
pub fn draw_text_into_context(&mut self,
|
||||
rctx: &RenderContext,
|
||||
run: &TextRun,
|
||||
run: &~TextRun,
|
||||
range: &Range,
|
||||
baseline_origin: Point2D<Au>,
|
||||
color: Color) {
|
||||
|
@ -454,11 +461,13 @@ impl Font {
|
|||
RunMetrics::new(advance, self.metrics.ascent, self.metrics.descent)
|
||||
}
|
||||
|
||||
pub fn shape_text(@mut self, text: ~str, is_whitespace: bool) -> Arc<GlyphStore> {
|
||||
let shaper = self.get_shaper();
|
||||
pub fn shape_text(&mut self, text: ~str, is_whitespace: bool) -> Arc<GlyphStore> {
|
||||
|
||||
//FIXME (ksh8281)
|
||||
self.make_shaper();
|
||||
do self.shape_cache.find_or_create(&text) |txt| {
|
||||
let mut glyphs = GlyphStore::new(text.char_len(), is_whitespace);
|
||||
shaper.shape_text(*txt, &mut glyphs);
|
||||
self.shaper.get_ref().shape_text(*txt, &mut glyphs);
|
||||
Arc::new(glyphs)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ use platform::font_context::FontContextHandle;
|
|||
use azure::azure_hl::BackendType;
|
||||
use std::hashmap::HashMap;
|
||||
|
||||
use std::rc::RcMut;
|
||||
|
||||
// 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 {
|
||||
|
@ -34,9 +36,9 @@ pub trait FontContextHandleMethods {
|
|||
}
|
||||
|
||||
pub struct FontContext {
|
||||
instance_cache: LRUCache<FontDescriptor, @mut Font>,
|
||||
instance_cache: LRUCache<FontDescriptor, RcMut<Font>>,
|
||||
font_list: Option<FontList>, // only needed by layout
|
||||
group_cache: LRUCache<SpecifiedFontStyle, @FontGroup>,
|
||||
group_cache: LRUCache<SpecifiedFontStyle, RcMut<FontGroup>>,
|
||||
handle: FontContextHandle,
|
||||
backend: BackendType,
|
||||
generic_fonts: HashMap<~str,~str>,
|
||||
|
@ -76,7 +78,7 @@ impl<'self> FontContext {
|
|||
self.font_list.get_ref()
|
||||
}
|
||||
|
||||
pub fn get_resolved_font_for_style(&mut self, style: &SpecifiedFontStyle) -> @FontGroup {
|
||||
pub fn get_resolved_font_for_style(&mut self, style: &SpecifiedFontStyle) -> RcMut<FontGroup> {
|
||||
match self.group_cache.find(style) {
|
||||
Some(fg) => {
|
||||
debug!("font group cache hit");
|
||||
|
@ -85,13 +87,13 @@ impl<'self> FontContext {
|
|||
None => {
|
||||
debug!("font group cache miss");
|
||||
let fg = self.create_font_group(style);
|
||||
self.group_cache.insert(style.clone(), fg);
|
||||
self.group_cache.insert(style.clone(), fg.clone());
|
||||
fg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_font_by_descriptor(&mut self, desc: &FontDescriptor) -> Result<@mut Font, ()> {
|
||||
pub fn get_font_by_descriptor(&mut self, desc: &FontDescriptor) -> Result<RcMut<Font>, ()> {
|
||||
match self.instance_cache.find(desc) {
|
||||
Some(f) => {
|
||||
debug!("font cache hit");
|
||||
|
@ -100,9 +102,9 @@ impl<'self> FontContext {
|
|||
None => {
|
||||
debug!("font cache miss");
|
||||
let result = self.create_font_instance(desc);
|
||||
match result {
|
||||
Ok(font) => {
|
||||
self.instance_cache.insert(desc.clone(), font);
|
||||
match result.clone() {
|
||||
Ok(ref font) => {
|
||||
self.instance_cache.insert(desc.clone(), font.clone());
|
||||
}, _ => {}
|
||||
};
|
||||
result
|
||||
|
@ -120,7 +122,7 @@ impl<'self> FontContext {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_font_group(&mut self, style: &SpecifiedFontStyle) -> @FontGroup {
|
||||
fn create_font_group(&mut self, style: &SpecifiedFontStyle) -> RcMut<FontGroup> {
|
||||
let mut fonts = ~[];
|
||||
|
||||
debug!("(create font group) --- starting ---");
|
||||
|
@ -130,24 +132,35 @@ impl<'self> FontContext {
|
|||
let family_name = family.trim();
|
||||
let transformed_family_name = self.transform_family(family_name);
|
||||
debug!("(create font group) transformed family is `{:s}`", transformed_family_name);
|
||||
let mut found = false;
|
||||
|
||||
let result = match self.font_list {
|
||||
Some(ref fl) => fl.find_font_in_family(transformed_family_name, style),
|
||||
Some(ref mut fl) => {
|
||||
let font_in_family = fl.find_font_in_family(&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
|
||||
}
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let mut found = false;
|
||||
for font_entry in result.iter() {
|
||||
found = true;
|
||||
match result {
|
||||
Some(ref result) => {
|
||||
found = true;
|
||||
let instance = self.get_font_by_descriptor(result);
|
||||
|
||||
let font_id =
|
||||
SelectorPlatformIdentifier(font_entry.handle.face_identifier());
|
||||
let font_desc = FontDescriptor::new((*style).clone(), font_id);
|
||||
|
||||
let instance = self.get_font_by_descriptor(&font_desc);
|
||||
|
||||
for font in instance.iter() { fonts.push(*font); }
|
||||
};
|
||||
for font in instance.iter() { fonts.push(font.clone()); }
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if !found {
|
||||
debug!("(create font group) didn't find `{:s}`", transformed_family_name);
|
||||
|
@ -156,48 +169,62 @@ impl<'self> FontContext {
|
|||
|
||||
if fonts.len() == 0 {
|
||||
let last_resort = FontList::get_last_resort_font_families();
|
||||
|
||||
for family in last_resort.iter() {
|
||||
let result = match self.font_list {
|
||||
Some(ref fl) => fl.find_font_in_family(*family, style),
|
||||
None => None,
|
||||
let font_desc = match self.font_list {
|
||||
Some(ref mut font_list) => {
|
||||
let font_desc = {
|
||||
let font_entry = font_list.find_font_in_family(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
|
||||
}
|
||||
};
|
||||
|
||||
for font_entry in result.iter() {
|
||||
let font_id =
|
||||
SelectorPlatformIdentifier(font_entry.handle.face_identifier());
|
||||
let font_desc = FontDescriptor::new((*style).clone(), font_id);
|
||||
match font_desc {
|
||||
Some(ref fd) => {
|
||||
let instance = self.get_font_by_descriptor(fd);
|
||||
|
||||
let instance = self.get_font_by_descriptor(&font_desc);
|
||||
|
||||
for font in instance.iter() {
|
||||
fonts.push(*font);
|
||||
}
|
||||
}
|
||||
for font in instance.iter() {
|
||||
fonts.push(font.clone());
|
||||
}
|
||||
},
|
||||
None => { }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
assert!(fonts.len() > 0);
|
||||
// TODO(Issue #179): Split FontStyle into specified and used styles
|
||||
let used_style = (*style).clone();
|
||||
|
||||
debug!("(create font group) --- finished ---");
|
||||
|
||||
@FontGroup::new(style.families.to_managed(), &used_style, fonts)
|
||||
unsafe { RcMut::new_unchecked(FontGroup::new(style.families.to_owned(), &used_style, fonts)) }
|
||||
}
|
||||
|
||||
fn create_font_instance(&self, desc: &FontDescriptor) -> Result<@mut Font, ()> {
|
||||
fn create_font_instance(&self, desc: &FontDescriptor) -> Result<RcMut<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).clone(),
|
||||
desc.style.clone());
|
||||
do result_handle.and_then |handle| {
|
||||
Ok(Font::new_from_adopted_handle(self,
|
||||
Ok(RcMut::new(Font::new_from_adopted_handle(self,
|
||||
handle,
|
||||
&desc.style,
|
||||
self.backend,
|
||||
self.profiler_chan.clone()))
|
||||
self.profiler_chan.clone())))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,11 +13,11 @@ use servo_util::time::ProfilerChan;
|
|||
|
||||
use std::hashmap::HashMap;
|
||||
|
||||
pub type FontFamilyMap = HashMap<~str, @mut FontFamily>;
|
||||
pub type FontFamilyMap = HashMap<~str, FontFamily>;
|
||||
|
||||
trait FontListHandleMethods {
|
||||
fn get_available_families(&self, fctx: &FontContextHandle) -> FontFamilyMap;
|
||||
fn load_variations_for_family(&self, family: @mut FontFamily);
|
||||
fn load_variations_for_family(&self, family: &mut FontFamily);
|
||||
fn get_last_resort_font_families() -> ~[~str];
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ pub struct FontList {
|
|||
prof_chan: ProfilerChan,
|
||||
}
|
||||
|
||||
impl FontList {
|
||||
impl<'self> FontList {
|
||||
pub fn new(fctx: &FontContextHandle,
|
||||
prof_chan: ProfilerChan)
|
||||
-> FontList {
|
||||
|
@ -52,39 +52,27 @@ impl FontList {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn find_font_in_family(&self,
|
||||
family_name: &str,
|
||||
style: &SpecifiedFontStyle) -> Option<@FontEntry> {
|
||||
let family = self.find_family(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 mut result: Option<@FontEntry> = None;
|
||||
for fam in family.iter() {
|
||||
result = fam.find_font_for_style(&self.handle, style);
|
||||
}
|
||||
|
||||
let decision = if result.is_some() {
|
||||
"Found"
|
||||
} else {
|
||||
"Couldn't find"
|
||||
};
|
||||
|
||||
debug!("FontList: {:s} font face in family[{:s}] matching style", decision, family_name);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn find_family(&self, family_name: &str) -> Option<@mut FontFamily> {
|
||||
// look up canonical name
|
||||
let family = self.family_map.find_equiv(&family_name);
|
||||
|
||||
let decision = if family.is_some() { "Found" } else { "Couldn't find" };
|
||||
debug!("FontList: {:s} font family with name={:s}", decision, family_name);
|
||||
|
||||
pub fn find_font_in_family(&'self mut self,
|
||||
family_name: &~str,
|
||||
style: &SpecifiedFontStyle) -> Option<&'self FontEntry> {
|
||||
// TODO(Issue #188): look up localized font family names if canonical name not found
|
||||
family.map(|f| *f)
|
||||
// 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: &'self 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(&mut self.handle, 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() -> ~[~str] {
|
||||
|
@ -94,12 +82,12 @@ impl FontList {
|
|||
}
|
||||
|
||||
// Holds a specific font family, and the various
|
||||
pub struct FontFamily {
|
||||
pub struct FontFamily<'self> {
|
||||
family_name: ~str,
|
||||
entries: ~[@FontEntry],
|
||||
entries: ~[FontEntry],
|
||||
}
|
||||
|
||||
impl FontFamily {
|
||||
impl<'self> FontFamily {
|
||||
pub fn new(family_name: &str) -> FontFamily {
|
||||
FontFamily {
|
||||
family_name: family_name.to_str(),
|
||||
|
@ -107,7 +95,7 @@ impl FontFamily {
|
|||
}
|
||||
}
|
||||
|
||||
fn load_family_variations(@mut self, list: &FontListHandle) {
|
||||
fn load_family_variations(&mut self, list: &FontListHandle) {
|
||||
if self.entries.len() > 0 {
|
||||
return
|
||||
}
|
||||
|
@ -115,8 +103,8 @@ impl FontFamily {
|
|||
assert!(self.entries.len() > 0)
|
||||
}
|
||||
|
||||
pub fn find_font_for_style(@mut self, list: &FontListHandle, style: &SpecifiedFontStyle)
|
||||
-> Option<@FontEntry> {
|
||||
pub fn find_font_for_style(&'self mut self, list: &FontListHandle, style: &SpecifiedFontStyle)
|
||||
-> Option<&'self FontEntry> {
|
||||
self.load_family_variations(list);
|
||||
|
||||
// TODO(Issue #189): optimize lookup for
|
||||
|
@ -129,7 +117,7 @@ impl FontFamily {
|
|||
if (style.weight.is_bold() == entry.is_bold()) &&
|
||||
(style.italic == entry.is_italic()) {
|
||||
|
||||
return Some(*entry);
|
||||
return Some(entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use font::{CSSFontWeight, FontHandleMethods, FontMetrics, FontTableMethods};
|
|||
use font::{FontTableTag, FractionalPixel, SpecifiedFontStyle, UsedFontStyle, FontWeight100};
|
||||
use font::{FontWeight200, FontWeight300, FontWeight400, FontWeight500, FontWeight600};
|
||||
use font::{FontWeight700, FontWeight800, FontWeight900};
|
||||
use font_context::FontContextHandleMethods;
|
||||
use servo_util::geometry::Au;
|
||||
use servo_util::geometry;
|
||||
use platform::font_context::FontContextHandle;
|
||||
|
@ -93,7 +94,7 @@ impl FontHandleMethods for FontHandle {
|
|||
let handle = FontHandle {
|
||||
face: face,
|
||||
source: FontSourceMem(buf),
|
||||
handle: *fctx
|
||||
handle: fctx.clone()
|
||||
};
|
||||
Ok(handle)
|
||||
}
|
||||
|
@ -295,7 +296,7 @@ impl<'self> FontHandle {
|
|||
Ok(FontHandle {
|
||||
source: FontSourceFile(file.to_str()),
|
||||
face: face,
|
||||
handle: *fctx
|
||||
handle: fctx.clone()
|
||||
})
|
||||
} else {
|
||||
Err(())
|
||||
|
@ -323,7 +324,7 @@ impl<'self> FontHandle {
|
|||
Ok(FontHandle {
|
||||
source: FontSourceFile(file),
|
||||
face: face,
|
||||
handle: *fctx
|
||||
handle: fctx.clone()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,34 +12,53 @@ use freetype::freetype::{FT_Done_FreeType, FT_Init_FreeType};
|
|||
|
||||
use std::ptr;
|
||||
|
||||
#[deriving(Clone)]
|
||||
struct FreeTypeLibraryHandle {
|
||||
ctx: FT_Library,
|
||||
}
|
||||
|
||||
impl Drop for FreeTypeLibraryHandle {
|
||||
#[fixed_stack_segment]
|
||||
fn drop(&mut self) {
|
||||
assert!(self.ctx.is_not_null());
|
||||
unsafe {
|
||||
FT_Done_FreeType(self.ctx);
|
||||
}
|
||||
}
|
||||
// FIXME(ksh8281) this value have to use atomic operation for counting ref
|
||||
static mut font_context_ref_count: uint = 0;
|
||||
static mut ft_pointer: Option<FT_Library> = None;
|
||||
pub struct FontContextHandle {
|
||||
ctx: FreeTypeLibraryHandle,
|
||||
}
|
||||
|
||||
pub struct FontContextHandle {
|
||||
ctx: @FreeTypeLibraryHandle,
|
||||
impl Drop for FontContextHandle {
|
||||
#[fixed_stack_segment]
|
||||
fn drop(&mut self) {
|
||||
assert!(self.ctx.ctx.is_not_null());
|
||||
unsafe {
|
||||
assert!(font_context_ref_count >= 1);
|
||||
font_context_ref_count = font_context_ref_count - 1;
|
||||
if font_context_ref_count == 0 {
|
||||
FT_Done_FreeType(self.ctx.ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FontContextHandle {
|
||||
#[fixed_stack_segment]
|
||||
pub fn new() -> FontContextHandle {
|
||||
unsafe {
|
||||
let ctx: FT_Library = ptr::null();
|
||||
let result = FT_Init_FreeType(ptr::to_unsafe_ptr(&ctx));
|
||||
if !result.succeeded() { fail!(); }
|
||||
|
||||
FontContextHandle {
|
||||
ctx: @FreeTypeLibraryHandle { ctx: ctx },
|
||||
match ft_pointer {
|
||||
Some(ref ctx) => {
|
||||
font_context_ref_count = font_context_ref_count + 1;
|
||||
FontContextHandle {
|
||||
ctx: FreeTypeLibraryHandle { ctx: ctx.clone() },
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let ctx: FT_Library = ptr::null();
|
||||
let result = FT_Init_FreeType(ptr::to_unsafe_ptr(&ctx));
|
||||
if !result.succeeded() { fail!("Unable to initialize FreeType library"); }
|
||||
ft_pointer = Some(ctx);
|
||||
font_context_ref_count = font_context_ref_count + 1;
|
||||
FontContextHandle {
|
||||
ctx: FreeTypeLibraryHandle { ctx: ctx },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +66,12 @@ impl FontContextHandle {
|
|||
|
||||
impl FontContextHandleMethods for FontContextHandle {
|
||||
fn clone(&self) -> FontContextHandle {
|
||||
FontContextHandle { ctx: self.ctx }
|
||||
unsafe {
|
||||
font_context_ref_count = font_context_ref_count + 1;
|
||||
FontContextHandle {
|
||||
ctx: self.ctx.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle)
|
||||
|
|
|
@ -53,7 +53,7 @@ impl FontListHandle {
|
|||
while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
|
||||
let family_name = str::raw::from_c_str(family as *c_char);
|
||||
debug!("Creating new FontFamily for family: {:s}", family_name);
|
||||
let new_family = @mut FontFamily::new(family_name);
|
||||
let new_family = FontFamily::new(family_name);
|
||||
family_map.insert(family_name, new_family);
|
||||
v += 1;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ impl FontListHandle {
|
|||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
pub fn load_variations_for_family(&self, family: @mut FontFamily) {
|
||||
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
|
||||
debug!("getting variations for {:?}", family);
|
||||
unsafe {
|
||||
let config = FcConfigGetCurrent();
|
||||
|
@ -120,7 +120,7 @@ impl FontListHandle {
|
|||
let font_handle = font_handle.unwrap();
|
||||
|
||||
debug!("Creating new FontEntry for face: {:s}", font_handle.face_name());
|
||||
let entry = @FontEntry::new(font_handle);
|
||||
let entry = FontEntry::new(font_handle);
|
||||
family.entries.push(entry);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,13 +36,13 @@ impl FontListHandle {
|
|||
let family_name = family_name_cf.to_str();
|
||||
debug!("Creating new FontFamily for family: {:s}", family_name);
|
||||
|
||||
let new_family = @mut FontFamily::new(family_name);
|
||||
let new_family = FontFamily::new(family_name);
|
||||
family_map.insert(family_name, new_family);
|
||||
}
|
||||
family_map
|
||||
}
|
||||
|
||||
pub fn load_variations_for_family(&self, family: @mut FontFamily) {
|
||||
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
|
||||
debug!("Looking for faces of family: {:s}", family.family_name);
|
||||
|
||||
let family_collection = core_text::font_collection::create_for_family(family.family_name);
|
||||
|
@ -54,7 +54,7 @@ impl FontListHandle {
|
|||
let handle = FontHandle::new_from_CTFont(&self.fctx, font).unwrap();
|
||||
|
||||
debug!("Creating new FontEntry for face: {:s}", handle.face_name());
|
||||
let entry = @FontEntry::new(handle);
|
||||
let entry = FontEntry::new(handle);
|
||||
family.entries.push(entry)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ use std::libc::size_t;
|
|||
|
||||
pub struct RenderContext<'self> {
|
||||
draw_target: &'self DrawTarget,
|
||||
font_ctx: @mut FontContext,
|
||||
font_ctx: &'self mut ~FontContext,
|
||||
opts: &'self Opts,
|
||||
/// The rectangle that this context encompasses in page coordinates.
|
||||
page_rect: Rect<f32>,
|
||||
|
|
|
@ -97,7 +97,7 @@ pub struct RenderTask<C,T> {
|
|||
port: Port<Msg<T>>,
|
||||
compositor: C,
|
||||
constellation_chan: ConstellationChan,
|
||||
font_ctx: @mut FontContext,
|
||||
font_ctx: ~FontContext,
|
||||
opts: Opts,
|
||||
|
||||
/// A channel to the profiler.
|
||||
|
@ -150,7 +150,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
port: port,
|
||||
compositor: compositor,
|
||||
constellation_chan: constellation_chan,
|
||||
font_ctx: @mut FontContext::new(opts.render_backend.clone(),
|
||||
font_ctx: ~FontContext::new(opts.render_backend.clone(),
|
||||
false,
|
||||
profiler_chan.clone()),
|
||||
opts: opts,
|
||||
|
@ -266,9 +266,9 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
|
||||
{
|
||||
// Build the render context.
|
||||
let ctx = RenderContext {
|
||||
let mut ctx = RenderContext {
|
||||
draw_target: &draw_target,
|
||||
font_ctx: self.font_ctx,
|
||||
font_ctx: &mut self.font_ctx,
|
||||
opts: &self.opts,
|
||||
page_rect: tile.page_rect,
|
||||
screen_rect: tile.screen_rect,
|
||||
|
@ -287,7 +287,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
|
||||
// Draw the display list.
|
||||
do profile(time::RenderingDrawingCategory, self.profiler_chan.clone()) {
|
||||
render_layer.display_list.get().draw_into_context(&ctx);
|
||||
render_layer.display_list.get().draw_into_context(&mut ctx);
|
||||
ctx.draw_target.flush();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ 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. */
|
||||
|
||||
pub use text::shaping::Shaper;
|
||||
pub use text::text_run::SendableTextRun;
|
||||
pub use text::text_run::TextRun;
|
||||
|
||||
pub mod glyph;
|
||||
|
|
|
@ -21,7 +21,7 @@ pub trait ShaperMethods {
|
|||
// TODO(Issue #163): this is a workaround for static methods and
|
||||
// typedefs not working well together. It should be removed.
|
||||
pub impl Shaper {
|
||||
pub fn new(font: @mut Font) -> Shaper {
|
||||
pub fn new(font: &mut Font) -> Shaper {
|
||||
harfbuzz::shaper::HarfbuzzShaper::new(font)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,7 +136,6 @@ impl ShapedGlyphData {
|
|||
}
|
||||
|
||||
pub struct Shaper {
|
||||
font: @mut Font,
|
||||
priv hb_face: *hb_face_t,
|
||||
priv hb_font: *hb_font_t,
|
||||
priv hb_funcs: *hb_font_funcs_t,
|
||||
|
@ -161,13 +160,10 @@ impl Drop for Shaper {
|
|||
|
||||
impl Shaper {
|
||||
#[fixed_stack_segment]
|
||||
pub fn new(font: @mut Font) -> Shaper {
|
||||
pub fn new(font: &mut Font) -> Shaper {
|
||||
unsafe {
|
||||
// Indirection for Rust Issue #6248, dynamic freeze scope artifically extended
|
||||
let font_ptr = {
|
||||
let borrowed_font= &mut *font;
|
||||
borrowed_font as *mut Font
|
||||
};
|
||||
let font_ptr = font as *mut Font;
|
||||
let hb_face: *hb_face_t = hb_face_create_for_tables(get_font_table_func,
|
||||
font_ptr as *c_void,
|
||||
None);
|
||||
|
@ -190,7 +186,6 @@ impl Shaper {
|
|||
hb_font_set_funcs(hb_font, hb_funcs, font_ptr as *c_void, None);
|
||||
|
||||
Shaper {
|
||||
font: font,
|
||||
hb_face: hb_face,
|
||||
hb_font: hb_font,
|
||||
hb_funcs: hb_funcs,
|
||||
|
|
|
@ -4,47 +4,24 @@
|
|||
|
||||
use std::vec::VecIterator;
|
||||
|
||||
use font_context::FontContext;
|
||||
use servo_util::geometry::Au;
|
||||
use text::glyph::GlyphStore;
|
||||
use font::{Font, FontDescriptor, RunMetrics};
|
||||
use font::{Font, FontDescriptor, RunMetrics, FontStyle, FontMetrics};
|
||||
use servo_util::range::Range;
|
||||
use extra::arc::Arc;
|
||||
use style::computed_values::text_decoration;
|
||||
|
||||
/// A text run.
|
||||
#[deriving(Clone)]
|
||||
pub struct TextRun {
|
||||
text: Arc<~str>,
|
||||
font: @mut Font,
|
||||
font_descriptor: FontDescriptor,
|
||||
font_metrics: FontMetrics,
|
||||
font_style: FontStyle,
|
||||
decoration: text_decoration::T,
|
||||
glyphs: Arc<~[Arc<GlyphStore>]>,
|
||||
}
|
||||
|
||||
/// The same as a text run, but with a font descriptor instead of a font. This makes them thread
|
||||
/// safe.
|
||||
pub struct SendableTextRun {
|
||||
text: Arc<~str>,
|
||||
font: FontDescriptor,
|
||||
decoration: text_decoration::T,
|
||||
priv glyphs: Arc<~[Arc<GlyphStore>]>,
|
||||
}
|
||||
|
||||
impl SendableTextRun {
|
||||
pub fn deserialize(&self, fctx: @mut FontContext) -> TextRun {
|
||||
let font = match fctx.get_font_by_descriptor(&self.font) {
|
||||
Ok(f) => f,
|
||||
Err(_) => fail!("Font descriptor deserialization failed! desc={:?}", self.font)
|
||||
};
|
||||
|
||||
TextRun {
|
||||
text: self.text.clone(),
|
||||
font: font,
|
||||
decoration: self.decoration,
|
||||
glyphs: self.glyphs.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SliceIterator<'self> {
|
||||
priv glyph_iter: VecIterator<'self, Arc<GlyphStore>>,
|
||||
priv range: Range,
|
||||
|
@ -120,12 +97,14 @@ impl<'self> Iterator<Range> for LineIterator<'self> {
|
|||
}
|
||||
|
||||
impl<'self> TextRun {
|
||||
pub fn new(font: @mut Font, text: ~str, decoration: text_decoration::T) -> TextRun {
|
||||
pub fn new(font: &mut Font, text: ~str, decoration: text_decoration::T) -> TextRun {
|
||||
let glyphs = TextRun::break_and_shape(font, text);
|
||||
|
||||
let run = TextRun {
|
||||
text: Arc::new(text),
|
||||
font: font,
|
||||
font_style: font.style.clone(),
|
||||
font_metrics: font.metrics.clone(),
|
||||
font_descriptor: font.get_descriptor(),
|
||||
decoration: decoration,
|
||||
glyphs: Arc::new(glyphs),
|
||||
};
|
||||
|
@ -133,10 +112,9 @@ impl<'self> TextRun {
|
|||
}
|
||||
|
||||
pub fn teardown(&self) {
|
||||
self.font.teardown();
|
||||
}
|
||||
|
||||
pub fn break_and_shape(font: @mut Font, text: &str) -> ~[Arc<GlyphStore>] {
|
||||
pub fn break_and_shape(font: &mut Font, text: &str) -> ~[Arc<GlyphStore>] {
|
||||
// TODO(Issue #230): do a better job. See Gecko's LineBreaker.
|
||||
|
||||
let mut glyphs = ~[];
|
||||
|
@ -191,15 +169,6 @@ impl<'self> TextRun {
|
|||
glyphs
|
||||
}
|
||||
|
||||
pub fn serialize(&self) -> SendableTextRun {
|
||||
SendableTextRun {
|
||||
text: self.text.clone(),
|
||||
font: self.font.get_descriptor(),
|
||||
decoration: self.decoration,
|
||||
glyphs: self.glyphs.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn char_len(&self) -> uint {
|
||||
do self.glyphs.get().iter().fold(0u) |len, slice_glyphs| {
|
||||
len + slice_glyphs.get().char_len()
|
||||
|
@ -218,19 +187,30 @@ impl<'self> TextRun {
|
|||
}
|
||||
|
||||
pub fn metrics_for_range(&self, range: &Range) -> RunMetrics {
|
||||
self.font.measure_text(self, range)
|
||||
// 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 self.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.font_metrics.ascent, self.font_metrics.descent)
|
||||
}
|
||||
|
||||
pub fn metrics_for_slice(&self, glyphs: &GlyphStore, slice_range: &Range) -> RunMetrics {
|
||||
self.font.measure_text_for_slice(glyphs, slice_range)
|
||||
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.font_metrics.ascent, self.font_metrics.descent)
|
||||
}
|
||||
|
||||
pub fn min_width_for_range(&self, range: &Range) -> Au {
|
||||
let mut max_piece_width = Au(0);
|
||||
debug!("iterating outer range {:?}", range);
|
||||
for (glyphs, offset, slice_range) in self.iter_slices_for_range(range) {
|
||||
for (_, offset, slice_range) in self.iter_slices_for_range(range) {
|
||||
debug!("iterated on {:?}[{:?}]", offset, slice_range);
|
||||
let metrics = self.font.measure_text_for_slice(glyphs, &slice_range);
|
||||
let metrics = self.metrics_for_range(&slice_range);
|
||||
max_piece_width = Au::max(max_piece_width, metrics.advance_width);
|
||||
}
|
||||
max_piece_width
|
||||
|
|
|
@ -630,13 +630,21 @@ impl Box {
|
|||
|
||||
// Create the text box.
|
||||
do list.with_mut_ref |list| {
|
||||
// FIXME(pcwalton): Allocation? Why?!
|
||||
let run = ~TextRun {
|
||||
text: text_box.run.text.clone(),
|
||||
font_descriptor: text_box.run.font_descriptor.clone(),
|
||||
font_metrics: text_box.run.font_metrics.clone(),
|
||||
font_style: text_box.run.font_style.clone(),
|
||||
decoration: text_box.run.decoration.clone(),
|
||||
glyphs: text_box.run.glyphs.clone()
|
||||
};
|
||||
let text_display_item = ~TextDisplayItem {
|
||||
base: BaseDisplayItem {
|
||||
bounds: absolute_box_bounds,
|
||||
extra: ExtraDisplayListData::new(&self),
|
||||
},
|
||||
// FIXME(pcwalton): Allocation? Why?!
|
||||
text_run: ~text_box.run.serialize(),
|
||||
text_run: run,
|
||||
range: text_box.range,
|
||||
color: color,
|
||||
};
|
||||
|
|
|
@ -711,7 +711,7 @@ impl Flow for InlineFlow {
|
|||
|
||||
// Find the top and bottom of the content area.
|
||||
// Those are used in text-top and text-bottom value of 'vertical-align'
|
||||
let text_ascent = text_box.run.font.metrics.ascent;
|
||||
let text_ascent = text_box.run.font_metrics.ascent;
|
||||
|
||||
// Offset from the top of the box is 1/2 of the leading + ascent
|
||||
let text_offset = text_ascent + (line_height - em_size).scale_by(0.5);
|
||||
|
|
|
@ -125,7 +125,7 @@ impl TextRunScanner {
|
|||
// 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 = ctx.font_ctx.get_resolved_font_for_style(&font_style);
|
||||
let run = @fontgroup.create_textrun(transformed_text, decoration);
|
||||
let run = @fontgroup.with_borrow(|fg| fg.create_textrun(transformed_text.clone(), decoration));
|
||||
|
||||
debug!("TextRunScanner: pushing single text box in range: {} ({})",
|
||||
self.clump,
|
||||
|
@ -188,7 +188,11 @@ impl TextRunScanner {
|
|||
// sequence. If no clump takes ownership, however, it will leak.
|
||||
let clump = self.clump;
|
||||
let run = if clump.length() != 0 && run_str.len() > 0 {
|
||||
Some(@TextRun::new(fontgroup.fonts[0], run_str, decoration))
|
||||
fontgroup.with_borrow( |fg| {
|
||||
fg.fonts[0].with_mut_borrow( |font| {
|
||||
Some(@TextRun::new(font, run_str.clone(), decoration))
|
||||
})
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue