зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #2775 - Font refactoring work - add font cache task, cleanup various code paths (from glennw:font-cache)
Source-Repo: https://github.com/servo/servo Source-Revision: 0dec28dd4a0f0d10dd721c16d8388c431718e303
This commit is contained in:
Родитель
8e33bd3d23
Коммит
1765070bdb
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,54 +97,76 @@ 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,
|
||||
pub struct Font {
|
||||
pub handle: FontHandle,
|
||||
pub metrics: FontMetrics,
|
||||
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 FontDescriptor {
|
||||
pub fn new(style: UsedFontStyle, selector: FontSelector) -> FontDescriptor {
|
||||
FontDescriptor {
|
||||
style: style,
|
||||
selector: selector,
|
||||
impl Font {
|
||||
pub fn shape_text(&mut self, text: String, is_whitespace: bool) -> Arc<GlyphStore> {
|
||||
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>(&'a mut self) -> &'a Shaper {
|
||||
// fast path: already created a shaper
|
||||
match self.shaper {
|
||||
Some(ref shaper) => {
|
||||
let s: &'a Shaper = shaper;
|
||||
return s;
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
|
||||
let shaper = Shaper::new(self);
|
||||
self.shaper = Some(shaper);
|
||||
self.shaper.get_ref()
|
||||
}
|
||||
|
||||
pub fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
||||
let result = self.handle.get_table_for_tag(tag);
|
||||
let status = if result.is_some() { "Found" } else { "Didn't find" };
|
||||
|
||||
debug!("{:s} font table[{:s}] with family={}, face={}",
|
||||
status, tag.tag_to_str(),
|
||||
self.handle.family_name(), self.handle.face_name());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
|
||||
self.handle.glyph_index(codepoint)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 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>>>
|
||||
pub fonts: Vec<Rc<RefCell<Font>>>,
|
||||
}
|
||||
|
||||
impl FontGroup {
|
||||
pub fn new(families: Vec<String>, style: &UsedFontStyle, fonts: Vec<Rc<RefCell<Font>>>) -> FontGroup {
|
||||
pub fn new(fonts: Vec<Rc<RefCell<Font>>>) -> FontGroup {
|
||||
FontGroup {
|
||||
families: families,
|
||||
style: (*style).clone(),
|
||||
fonts: fonts,
|
||||
fonts: fonts
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,240 +205,3 @@ impl RunMetrics {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
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 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();
|
||||
|
||||
Font {
|
||||
handle: handle,
|
||||
azure_font: None,
|
||||
shaper: None,
|
||||
style: (*style).clone(),
|
||||
metrics: metrics,
|
||||
backend: backend,
|
||||
shape_cache: HashCache::new(),
|
||||
glyph_advance_cache: HashCache::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_shaper(&'a mut self) -> &'a Shaper {
|
||||
// fast path: already created a shaper
|
||||
match self.shaper {
|
||||
Some(ref shaper) => {
|
||||
let s: &'a Shaper = shaper;
|
||||
return s;
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
|
||||
let shaper = Shaper::new(self);
|
||||
self.shaper = Some(shaper);
|
||||
self.shaper.get_ref()
|
||||
}
|
||||
|
||||
pub fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
||||
let result = self.handle.get_table_for_tag(tag);
|
||||
let status = if result.is_some() { "Found" } else { "Didn't find" };
|
||||
|
||||
debug!("{:s} font table[{:s}] with family={}, face={}",
|
||||
status, tag.tag_to_str(),
|
||||
self.handle.family_name(), self.handle.face_name());
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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 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)
|
||||
}
|
||||
|
||||
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 fn get_descriptor(&self) -> FontDescriptor {
|
||||
FontDescriptor::new(self.style.clone(), SelectorPlatformIdentifier(self.handle.face_identifier()))
|
||||
}
|
||||
|
||||
pub fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
|
||||
self.handle.glyph_index(codepoint)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
/// Whether we need a font list.
|
||||
pub needs_font_list: bool,
|
||||
#[cfg(target_os="linux")]
|
||||
#[cfg(target_os="android")]
|
||||
use azure::scaled_font::FontData;
|
||||
|
||||
/// A channel up to the time profiler.
|
||||
pub time_profiler_chan: TimeProfilerChan,
|
||||
#[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)
|
||||
}
|
||||
|
||||
pub trait FontContextHandleMethods {
|
||||
fn create_font_from_identifier(&self, &str, Option<&UsedFontStyle>) -> Result<FontHandle, ()>;
|
||||
#[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)
|
||||
}
|
||||
|
||||
/// 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),
|
||||
platform_handle: handle,
|
||||
font_cache_task: font_cache_task,
|
||||
layout_font_cache: vec!(),
|
||||
render_font_cache: vec!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a font for use in layout calculations.
|
||||
fn create_layout_font(&self, template: Arc<FontTemplateData>,
|
||||
descriptor: FontTemplateDescriptor, pt_size: f64) -> Font {
|
||||
|
||||
let handle: FontHandle = FontHandleMethods::new_from_template(&self.platform_handle, template, Some(pt_size)).unwrap();
|
||||
let metrics = handle.get_metrics();
|
||||
|
||||
Font {
|
||||
handle: handle,
|
||||
backend: info.backend,
|
||||
generic_fonts: generic_fonts,
|
||||
time_profiler_chan: info.time_profiler_chan.clone(),
|
||||
shaper: None,
|
||||
descriptor: descriptor,
|
||||
pt_size: pt_size,
|
||||
metrics: metrics,
|
||||
shape_cache: HashCache::new(),
|
||||
glyph_advance_cache: HashCache::new(),
|
||||
}
|
||||
}
|
||||
|
||||
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 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()
|
||||
});
|
||||
|
||||
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 mut fonts: Vec<Rc<RefCell<Font>>> = vec!();
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
fn create_font_group(&mut self, style: &SpecifiedFontStyle) -> Rc<RefCell<FontGroup>> {
|
||||
let mut fonts = vec!();
|
||||
|
||||
debug!("(create font group) --- starting ---");
|
||||
|
||||
// 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 desc = FontTemplateDescriptor::new(style.weight, style.style == font_style::italic);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
/// FontTemplateData structure 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
@ -36,9 +39,7 @@ fn fixed_to_float_ft(f: i32) -> f64 {
|
|||
fixed_to_float(6, f)
|
||||
}
|
||||
|
||||
pub struct FontTable {
|
||||
bogus: ()
|
||||
}
|
||||
pub struct FontTable;
|
||||
|
||||
impl FontTableMethods for FontTable {
|
||||
fn with_buffer(&self, _blk: |*u8, uint|) {
|
||||
|
@ -46,15 +47,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 +68,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 +85,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,34 +93,32 @@ impl FontHandleMethods for FontHandle {
|
|||
Err(()) => Err(())
|
||||
};
|
||||
|
||||
fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
|
||||
-> Result<FT_Face, ()> {
|
||||
unsafe {
|
||||
let mut face: FT_Face = ptr::null();
|
||||
let face_index = 0 as FT_Long;
|
||||
let result = FT_New_Memory_Face(lib, cbuf, cbuflen as FT_Long,
|
||||
face_index, &mut face);
|
||||
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();
|
||||
let face_index = 0 as FT_Long;
|
||||
let result = FT_New_Memory_Face(lib, cbuf, cbuflen as FT_Long,
|
||||
face_index, &mut face);
|
||||
|
||||
if !result.succeeded() || face.is_null() {
|
||||
return Err(());
|
||||
}
|
||||
if FontHandle::set_char_size(face, pt_size).is_ok() {
|
||||
Ok(face)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
if !result.succeeded() || face.is_null() {
|
||||
return Err(());
|
||||
}
|
||||
match pt_size {
|
||||
Some(s) => {
|
||||
match FontHandle::set_char_size(face, s) {
|
||||
Ok(_) => Ok(face),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
}
|
||||
None => Ok(face),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 +260,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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
@ -36,9 +39,7 @@ fn fixed_to_float_ft(f: i32) -> f64 {
|
|||
fixed_to_float(6, f)
|
||||
}
|
||||
|
||||
pub struct FontTable {
|
||||
_bogus: ()
|
||||
}
|
||||
pub struct FontTable;
|
||||
|
||||
impl FontTableMethods for FontTable {
|
||||
fn with_buffer(&self, _blk: |*u8, uint|) {
|
||||
|
@ -46,15 +47,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 +68,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 +85,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,34 +93,32 @@ impl FontHandleMethods for FontHandle {
|
|||
Err(()) => Err(())
|
||||
};
|
||||
|
||||
fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
|
||||
-> Result<FT_Face, ()> {
|
||||
unsafe {
|
||||
let mut face: FT_Face = ptr::null();
|
||||
let face_index = 0 as FT_Long;
|
||||
let result = FT_New_Memory_Face(lib, cbuf, cbuflen as FT_Long,
|
||||
face_index, &mut face);
|
||||
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();
|
||||
let face_index = 0 as FT_Long;
|
||||
let result = FT_New_Memory_Face(lib, cbuf, cbuflen as FT_Long,
|
||||
face_index, &mut face);
|
||||
|
||||
if !result.succeeded() || face.is_null() {
|
||||
return Err(());
|
||||
}
|
||||
if FontHandle::set_char_size(face, pt_size).is_ok() {
|
||||
Ok(face)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
if !result.succeeded() || face.is_null() {
|
||||
return Err(());
|
||||
}
|
||||
match pt_size {
|
||||
Some(s) => {
|
||||
match FontHandle::set_char_size(face, s) {
|
||||
Ok(_) => Ok(face),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
}
|
||||
None => Ok(face),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 +260,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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
|||
#[cfg(not(test))]
|
||||
use servo_net::resource_task::new_resource_task;
|
||||
#[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::new(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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче