mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Auto merge of #11273 - mbrubeck:fast-shape, r=pcwalton
Add a fast path for shaping ASCII text On both my Linux laptop and iMac, this is about twice as fast as Harfbuzz text shaping on https://en.wikipedia.org/wiki/Barack_Obama. I haven't tested this on any high-DPI (retina) displays, and I'm not 100% certain that the font unit scaling is correct there. Depends on servo/core-text-rs#50. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/11273) <!-- Reviewable:end -->
This commit is contained in:
commit
c0c70ef094
9 changed files with 258 additions and 80 deletions
|
@ -47,6 +47,7 @@ webrender_traits = {git = "https://github.com/servo/webrender_traits"}
|
||||||
xi-unicode = "0.0.1"
|
xi-unicode = "0.0.1"
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
|
byteorder = "0.5"
|
||||||
core-foundation = "0.2"
|
core-foundation = "0.2"
|
||||||
core-graphics = "0.3"
|
core-graphics = "0.3"
|
||||||
core-text = "1.1"
|
core-text = "1.1"
|
||||||
|
|
|
@ -24,6 +24,16 @@ use unicode_script::Script;
|
||||||
use util::cache::HashCache;
|
use util::cache::HashCache;
|
||||||
use webrender_traits;
|
use webrender_traits;
|
||||||
|
|
||||||
|
macro_rules! ot_tag {
|
||||||
|
($t1:expr, $t2:expr, $t3:expr, $t4:expr) => (
|
||||||
|
(($t1 as u32) << 24) | (($t2 as u32) << 16) | (($t3 as u32) << 8) | ($t4 as u32)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const GPOS: u32 = ot_tag!('G', 'P', 'O', 'S');
|
||||||
|
pub const GSUB: u32 = ot_tag!('G', 'S', 'U', 'B');
|
||||||
|
pub const KERN: u32 = ot_tag!('k', 'e', 'r', 'n');
|
||||||
|
|
||||||
static TEXT_SHAPING_PERFORMANCE_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
|
static TEXT_SHAPING_PERFORMANCE_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||||
|
|
||||||
// FontHandle encapsulates access to the platform's font API,
|
// FontHandle encapsulates access to the platform's font API,
|
||||||
|
@ -43,9 +53,11 @@ pub trait FontHandleMethods: Sized {
|
||||||
|
|
||||||
fn glyph_index(&self, codepoint: char) -> Option<GlyphId>;
|
fn glyph_index(&self, codepoint: char) -> Option<GlyphId>;
|
||||||
fn glyph_h_advance(&self, GlyphId) -> Option<FractionalPixel>;
|
fn glyph_h_advance(&self, GlyphId) -> Option<FractionalPixel>;
|
||||||
fn glyph_h_kerning(&self, GlyphId, GlyphId) -> FractionalPixel;
|
fn glyph_h_kerning(&self, glyph0: GlyphId, glyph1: GlyphId) -> FractionalPixel;
|
||||||
|
/// Can this font do basic horizontal LTR shaping without Harfbuzz?
|
||||||
|
fn can_do_fast_shaping(&self) -> bool;
|
||||||
fn metrics(&self) -> FontMetrics;
|
fn metrics(&self) -> FontMetrics;
|
||||||
fn table_for_tag(&self, FontTableTag) -> Option<Box<FontTable>>;
|
fn table_for_tag(&self, FontTableTag) -> Option<FontTable>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to abstract over the shaper's choice of fixed int representation.
|
// Used to abstract over the shaper's choice of fixed int representation.
|
||||||
|
@ -68,7 +80,7 @@ impl FontTableTagConversions for FontTableTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FontTableMethods {
|
pub trait FontTableMethods {
|
||||||
fn with_buffer<F>(&self, F) where F: FnOnce(*const u8, usize);
|
fn buffer(&self) -> &[u8];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
@ -198,7 +210,7 @@ impl Font {
|
||||||
self.shaper.as_ref().unwrap()
|
self.shaper.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn table_for_tag(&self, tag: FontTableTag) -> Option<Box<FontTable>> {
|
pub fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
||||||
let result = self.handle.table_for_tag(tag);
|
let result = self.handle.table_for_tag(tag);
|
||||||
let status = if result.is_some() { "Found" } else { "Didn't find" };
|
let status = if result.is_some() { "Found" } else { "Didn't find" };
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ extern crate azure;
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
|
|
||||||
// Mac OS-specific library dependencies
|
// Mac OS-specific library dependencies
|
||||||
|
#[cfg(target_os = "macos")] extern crate byteorder;
|
||||||
#[cfg(target_os = "macos")] extern crate core_foundation;
|
#[cfg(target_os = "macos")] extern crate core_foundation;
|
||||||
#[cfg(target_os = "macos")] extern crate core_graphics;
|
#[cfg(target_os = "macos")] extern crate core_graphics;
|
||||||
#[cfg(target_os = "macos")] extern crate core_text;
|
#[cfg(target_os = "macos")] extern crate core_text;
|
||||||
|
@ -95,7 +96,7 @@ mod paint_context;
|
||||||
pub mod display_list;
|
pub mod display_list;
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
pub mod font;
|
#[macro_use] pub mod font;
|
||||||
pub mod font_cache_thread;
|
pub mod font_cache_thread;
|
||||||
pub mod font_context;
|
pub mod font_context;
|
||||||
pub mod font_template;
|
pub mod font_template;
|
||||||
|
|
|
@ -6,7 +6,7 @@ extern crate freetype;
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
|
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
|
||||||
use font::{FontTableTag, FractionalPixel};
|
use font::{FontTableTag, FractionalPixel, GPOS, GSUB, KERN};
|
||||||
use freetype::freetype::{FTErrorMethods, FT_F26Dot6, FT_Face, FT_FaceRec};
|
use freetype::freetype::{FTErrorMethods, FT_F26Dot6, FT_Face, FT_FaceRec};
|
||||||
use freetype::freetype::{FT_Done_Face, FT_New_Memory_Face};
|
use freetype::freetype::{FT_Done_Face, FT_New_Memory_Face};
|
||||||
use freetype::freetype::{FT_Get_Char_Index, FT_Get_Postscript_Name};
|
use freetype::freetype::{FT_Get_Char_Index, FT_Get_Postscript_Name};
|
||||||
|
@ -35,13 +35,14 @@ fn fixed_to_float_ft(f: i32) -> f64 {
|
||||||
fixed_to_float(6, f)
|
fixed_to_float(6, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct FontTable {
|
pub struct FontTable {
|
||||||
buffer: Vec<u8>,
|
buffer: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontTableMethods for FontTable {
|
impl FontTableMethods for FontTable {
|
||||||
fn with_buffer<F>(&self, blk: F) where F: FnOnce(*const u8, usize) {
|
fn buffer(&self) -> &[u8] {
|
||||||
blk(self.buffer.as_ptr(), self.buffer.len())
|
&self.buffer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,9 +50,10 @@ impl FontTableMethods for FontTable {
|
||||||
pub struct FontHandle {
|
pub struct FontHandle {
|
||||||
// The font binary. This must stay valid for the lifetime of the font,
|
// The font binary. This must stay valid for the lifetime of the font,
|
||||||
// if the font is created using FT_Memory_Face.
|
// if the font is created using FT_Memory_Face.
|
||||||
pub font_data: Arc<FontTemplateData>,
|
font_data: Arc<FontTemplateData>,
|
||||||
pub face: FT_Face,
|
face: FT_Face,
|
||||||
pub handle: FontContextHandle
|
handle: FontContextHandle,
|
||||||
|
can_do_fast_shaping: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for FontHandle {
|
impl Drop for FontHandle {
|
||||||
|
@ -73,22 +75,19 @@ impl FontHandleMethods for FontHandle {
|
||||||
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
||||||
if ft_ctx.is_null() { return Err(()); }
|
if ft_ctx.is_null() { return Err(()); }
|
||||||
|
|
||||||
let face_result = create_face_from_buffer(ft_ctx, &template.bytes, pt_size);
|
return create_face_from_buffer(ft_ctx, &template.bytes, pt_size).map(|face| {
|
||||||
|
let mut handle = FontHandle {
|
||||||
// TODO: this could be more simply written as result::chain
|
|
||||||
// and moving buf into the struct ctor, but cant' move out of
|
|
||||||
// captured binding.
|
|
||||||
return match face_result {
|
|
||||||
Ok(face) => {
|
|
||||||
let handle = FontHandle {
|
|
||||||
face: face,
|
face: face,
|
||||||
font_data: template.clone(),
|
font_data: template.clone(),
|
||||||
handle: fctx.clone()
|
handle: fctx.clone(),
|
||||||
};
|
can_do_fast_shaping: false,
|
||||||
Ok(handle)
|
};
|
||||||
}
|
// TODO (#11310): Implement basic support for GPOS and GSUB.
|
||||||
Err(()) => Err(())
|
handle.can_do_fast_shaping = handle.has_table(KERN) &&
|
||||||
};
|
!handle.has_table(GPOS) &&
|
||||||
|
!handle.has_table(GSUB);
|
||||||
|
handle
|
||||||
|
});
|
||||||
|
|
||||||
fn create_face_from_buffer(lib: FT_Library, buffer: &[u8], pt_size: Option<Au>)
|
fn create_face_from_buffer(lib: FT_Library, buffer: &[u8], pt_size: Option<Au>)
|
||||||
-> Result<FT_Face, ()> {
|
-> Result<FT_Face, ()> {
|
||||||
|
@ -101,15 +100,10 @@ impl FontHandleMethods for FontHandle {
|
||||||
if !result.succeeded() || face.is_null() {
|
if !result.succeeded() || face.is_null() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
match pt_size {
|
if let Some(s) = pt_size {
|
||||||
Some(s) => {
|
try!(FontHandle::set_char_size(face, s).or(Err(())))
|
||||||
match FontHandle::set_char_size(face, s) {
|
|
||||||
Ok(_) => Ok(face),
|
|
||||||
Err(_) => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => Ok(face),
|
|
||||||
}
|
}
|
||||||
|
Ok(face)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,6 +179,10 @@ impl FontHandleMethods for FontHandle {
|
||||||
fixed_to_float_ft(delta.x as i32)
|
fixed_to_float_ft(delta.x as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn can_do_fast_shaping(&self) -> bool {
|
||||||
|
self.can_do_fast_shaping
|
||||||
|
}
|
||||||
|
|
||||||
fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
|
fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
|
||||||
assert!(!self.face.is_null());
|
assert!(!self.face.is_null());
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -260,7 +258,7 @@ impl FontHandleMethods for FontHandle {
|
||||||
metrics
|
metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table_for_tag(&self, tag: FontTableTag) -> Option<Box<FontTable>> {
|
fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
||||||
let tag = tag as FT_ULong;
|
let tag = tag as FT_ULong;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -274,7 +272,7 @@ impl FontHandleMethods for FontHandle {
|
||||||
if !FT_Load_Sfnt_Table(self.face, tag, 0, buf.as_mut_ptr(), &mut len).succeeded() {
|
if !FT_Load_Sfnt_Table(self.face, tag, 0, buf.as_mut_ptr(), &mut len).succeeded() {
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
Some(box FontTable { buffer: buf })
|
Some(FontTable { buffer: buf })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,6 +287,12 @@ impl<'a> FontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn has_table(&self, tag: FontTableTag) -> bool {
|
||||||
|
unsafe {
|
||||||
|
FT_Load_Sfnt_Table(self.face, tag as FT_ULong, 0, ptr::null_mut(), &mut 0).succeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn face_rec_mut(&'a self) -> &'a mut FT_FaceRec {
|
fn face_rec_mut(&'a self) -> &'a mut FT_FaceRec {
|
||||||
unsafe {
|
unsafe {
|
||||||
&mut (*self.face)
|
&mut (*self.face)
|
||||||
|
|
|
@ -9,6 +9,7 @@ extern crate core_graphics;
|
||||||
extern crate core_text;
|
extern crate core_text;
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
use core_foundation::base::CFIndex;
|
use core_foundation::base::CFIndex;
|
||||||
use core_foundation::data::CFData;
|
use core_foundation::data::CFData;
|
||||||
use core_foundation::string::UniChar;
|
use core_foundation::string::UniChar;
|
||||||
|
@ -17,16 +18,18 @@ use core_graphics::geometry::CGRect;
|
||||||
use core_text::font::CTFont;
|
use core_text::font::CTFont;
|
||||||
use core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
|
use core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
|
||||||
use core_text::font_descriptor::{kCTFontDefaultOrientation};
|
use core_text::font_descriptor::{kCTFontDefaultOrientation};
|
||||||
use font::FontTableTag;
|
use font::{FontHandleMethods, FontMetrics, FontTableTag, FontTableMethods, FractionalPixel};
|
||||||
use font::FractionalPixel;
|
use font::{GPOS, GSUB, KERN};
|
||||||
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
|
|
||||||
use platform::font_template::FontTemplateData;
|
use platform::font_template::FontTemplateData;
|
||||||
use platform::macos::font_context::FontContextHandle;
|
use platform::macos::font_context::FontContextHandle;
|
||||||
use std::ptr;
|
use std::ops::Range;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::{fmt, ptr};
|
||||||
use style::computed_values::{font_stretch, font_weight};
|
use style::computed_values::{font_stretch, font_weight};
|
||||||
use text::glyph::GlyphId;
|
use text::glyph::GlyphId;
|
||||||
|
|
||||||
|
const KERN_PAIR_LEN: usize = 6;
|
||||||
|
|
||||||
pub struct FontTable {
|
pub struct FontTable {
|
||||||
data: CFData,
|
data: CFData,
|
||||||
}
|
}
|
||||||
|
@ -52,17 +55,116 @@ impl FontTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontTableMethods for FontTable {
|
impl FontTableMethods for FontTable {
|
||||||
fn with_buffer<F>(&self, blk: F) where F: FnOnce(*const u8, usize) {
|
fn buffer(&self) -> &[u8] {
|
||||||
blk(self.data.bytes().as_ptr(), self.data.len() as usize);
|
self.data.bytes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FontHandle {
|
pub struct FontHandle {
|
||||||
pub font_data: Arc<FontTemplateData>,
|
font_data: Arc<FontTemplateData>,
|
||||||
pub ctfont: CTFont,
|
ctfont: CTFont,
|
||||||
|
h_kern_subtable: Option<CachedKernTable>,
|
||||||
|
can_do_fast_shaping: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FontHandle {
|
||||||
|
/// Cache all the data needed for basic horizontal kerning. This is used only as a fallback or
|
||||||
|
/// fast path (when the GPOS table is missing or unnecessary) so it needn't handle every case.
|
||||||
|
fn find_h_kern_subtable(&self) -> Option<CachedKernTable> {
|
||||||
|
let font_table = match self.table_for_tag(KERN) {
|
||||||
|
Some(table) => table,
|
||||||
|
None => return None
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut result = CachedKernTable {
|
||||||
|
font_table: font_table,
|
||||||
|
pair_data_range: 0..0,
|
||||||
|
px_per_font_unit: 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Look for a subtable with horizontal kerning in format 0.
|
||||||
|
// https://www.microsoft.com/typography/otspec/kern.htm
|
||||||
|
const KERN_COVERAGE_HORIZONTAL_FORMAT_0: u16 = 1;
|
||||||
|
const SUBTABLE_HEADER_LEN: usize = 6;
|
||||||
|
const FORMAT_0_HEADER_LEN: usize = 8;
|
||||||
|
{
|
||||||
|
let table = result.font_table.buffer();
|
||||||
|
let version = BigEndian::read_u16(table);
|
||||||
|
if version != 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let num_subtables = BigEndian::read_u16(&table[2..]);
|
||||||
|
let mut start = 4;
|
||||||
|
for _ in 0..num_subtables {
|
||||||
|
// TODO: Check the subtable version number?
|
||||||
|
let len = BigEndian::read_u16(&table[start + 2..]) as usize;
|
||||||
|
let cov = BigEndian::read_u16(&table[start + 4..]);
|
||||||
|
let end = start + len;
|
||||||
|
if cov == KERN_COVERAGE_HORIZONTAL_FORMAT_0 {
|
||||||
|
// Found a matching subtable.
|
||||||
|
if result.pair_data_range.len() > 0 {
|
||||||
|
debug!("Found multiple horizontal kern tables. Disable fast path.");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// Read the subtable header.
|
||||||
|
let subtable_start = start + SUBTABLE_HEADER_LEN;
|
||||||
|
let n_pairs = BigEndian::read_u16(&table[subtable_start..]) as usize;
|
||||||
|
let pair_data_start = subtable_start + FORMAT_0_HEADER_LEN;
|
||||||
|
|
||||||
|
result.pair_data_range = pair_data_start..end;
|
||||||
|
let pt_per_font_unit = self.ctfont.pt_size() as f64 /
|
||||||
|
self.ctfont.units_per_em() as f64;
|
||||||
|
result.px_per_font_unit = pt_to_px(pt_per_font_unit);
|
||||||
|
|
||||||
|
debug_assert_eq!(n_pairs * KERN_PAIR_LEN, result.pair_data_range.len());
|
||||||
|
}
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if result.pair_data_range.len() > 0 {
|
||||||
|
Some(result)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CachedKernTable {
|
||||||
|
font_table: FontTable,
|
||||||
|
pair_data_range: Range<usize>,
|
||||||
|
px_per_font_unit: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CachedKernTable {
|
||||||
|
/// Search for a glyph pair in the kern table and return the corresponding value.
|
||||||
|
fn binary_search(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> Option<i16> {
|
||||||
|
let pairs = &self.font_table.buffer()[self.pair_data_range.clone()];
|
||||||
|
|
||||||
|
let query = first_glyph << 16 | second_glyph;
|
||||||
|
let (mut start, mut end) = (0, pairs.len() / KERN_PAIR_LEN);
|
||||||
|
while start < end {
|
||||||
|
let i = (start + end) / 2;
|
||||||
|
let key = BigEndian::read_u32(&pairs[i * KERN_PAIR_LEN..]);
|
||||||
|
if key > query {
|
||||||
|
end = i;
|
||||||
|
} else if key < query {
|
||||||
|
start = i + 1;
|
||||||
|
} else {
|
||||||
|
return Some(BigEndian::read_i16(&pairs[i * KERN_PAIR_LEN + 4..]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for CachedKernTable {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
write!(f, "CachedKernTable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl FontHandleMethods for FontHandle {
|
impl FontHandleMethods for FontHandle {
|
||||||
fn new_from_template(_fctx: &FontContextHandle,
|
fn new_from_template(_fctx: &FontContextHandle,
|
||||||
template: Arc<FontTemplateData>,
|
template: Arc<FontTemplateData>,
|
||||||
|
@ -74,10 +176,18 @@ impl FontHandleMethods for FontHandle {
|
||||||
};
|
};
|
||||||
match template.ctfont(size) {
|
match template.ctfont(size) {
|
||||||
Some(ref ctfont) => {
|
Some(ref ctfont) => {
|
||||||
Ok(FontHandle {
|
let mut handle = FontHandle {
|
||||||
font_data: template.clone(),
|
font_data: template.clone(),
|
||||||
ctfont: ctfont.clone_with_font_size(size),
|
ctfont: ctfont.clone_with_font_size(size),
|
||||||
})
|
h_kern_subtable: None,
|
||||||
|
can_do_fast_shaping: false,
|
||||||
|
};
|
||||||
|
handle.h_kern_subtable = handle.find_h_kern_subtable();
|
||||||
|
// TODO (#11310): Implement basic support for GPOS and GSUB.
|
||||||
|
handle.can_do_fast_shaping = handle.h_kern_subtable.is_some() &&
|
||||||
|
handle.table_for_tag(GPOS).is_none() &&
|
||||||
|
handle.table_for_tag(GSUB).is_none();
|
||||||
|
Ok(handle)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
Err(())
|
Err(())
|
||||||
|
@ -155,12 +265,19 @@ impl FontHandleMethods for FontHandle {
|
||||||
return Some(glyphs[0] as GlyphId);
|
return Some(glyphs[0] as GlyphId);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn glyph_h_kerning(&self, _first_glyph: GlyphId, _second_glyph: GlyphId)
|
fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> FractionalPixel {
|
||||||
-> FractionalPixel {
|
if let Some(ref table) = self.h_kern_subtable {
|
||||||
// TODO: Implement on mac
|
if let Some(font_units) = table.binary_search(first_glyph, second_glyph) {
|
||||||
|
return font_units as f64 * table.px_per_font_unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
0.0
|
0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn can_do_fast_shaping(&self) -> bool {
|
||||||
|
self.can_do_fast_shaping
|
||||||
|
}
|
||||||
|
|
||||||
fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
|
fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
|
||||||
let glyphs = [glyph as CGGlyph];
|
let glyphs = [glyph as CGGlyph];
|
||||||
let advance = self.ctfont.get_advances_for_glyphs(kCTFontDefaultOrientation,
|
let advance = self.ctfont.get_advances_for_glyphs(kCTFontDefaultOrientation,
|
||||||
|
@ -209,10 +326,10 @@ impl FontHandleMethods for FontHandle {
|
||||||
metrics
|
metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table_for_tag(&self, tag: FontTableTag) -> Option<Box<FontTable>> {
|
fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
||||||
let result: Option<CFData> = self.ctfont.get_font_table(tag);
|
let result: Option<CFData> = self.ctfont.get_font_table(tag);
|
||||||
result.and_then(|data| {
|
result.and_then(|data| {
|
||||||
Some(box FontTable::wrap(data))
|
Some(FontTable::wrap(data))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use euclid::Point2D;
|
use euclid::Point2D;
|
||||||
use font::{DISABLE_KERNING_SHAPING_FLAG, Font, FontTableMethods, FontTableTag};
|
use font::{DISABLE_KERNING_SHAPING_FLAG, Font, FontHandleMethods, FontTableMethods, FontTableTag};
|
||||||
use font::{IGNORE_LIGATURES_SHAPING_FLAG, RTL_FLAG, ShapingOptions};
|
use font::{IGNORE_LIGATURES_SHAPING_FLAG, KERN, RTL_FLAG, ShapingOptions};
|
||||||
use harfbuzz::{HB_DIRECTION_LTR, HB_DIRECTION_RTL, HB_MEMORY_MODE_READONLY};
|
use harfbuzz::{HB_DIRECTION_LTR, HB_DIRECTION_RTL, HB_MEMORY_MODE_READONLY};
|
||||||
use harfbuzz::{hb_blob_create, hb_face_create_for_tables};
|
use harfbuzz::{hb_blob_create, hb_face_create_for_tables};
|
||||||
use harfbuzz::{hb_blob_t};
|
use harfbuzz::{hb_blob_t};
|
||||||
|
@ -34,21 +34,15 @@ use harfbuzz::{hb_glyph_position_t};
|
||||||
use harfbuzz::{hb_position_t, hb_tag_t};
|
use harfbuzz::{hb_position_t, hb_tag_t};
|
||||||
use libc::{c_char, c_int, c_uint, c_void};
|
use libc::{c_char, c_int, c_uint, c_void};
|
||||||
use platform::font::FontTable;
|
use platform::font::FontTable;
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
use std::{char, cmp, ptr};
|
use std::{char, cmp, ptr};
|
||||||
use text::glyph::{ByteIndex, GlyphData, GlyphId, GlyphStore};
|
use text::glyph::{ByteIndex, GlyphData, GlyphId, GlyphStore};
|
||||||
use text::shaping::ShaperMethods;
|
use text::shaping::ShaperMethods;
|
||||||
use text::util::{fixed_to_float, float_to_fixed, is_bidi_control};
|
use text::util::{fixed_to_float, float_to_fixed, is_bidi_control};
|
||||||
|
use unicode_script::Script;
|
||||||
macro_rules! hb_tag {
|
|
||||||
($t1:expr, $t2:expr, $t3:expr, $t4:expr) => (
|
|
||||||
(($t1 as u32) << 24) | (($t2 as u32) << 16) | (($t3 as u32) << 8) | ($t4 as u32)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const NO_GLYPH: i32 = -1;
|
const NO_GLYPH: i32 = -1;
|
||||||
|
const LIGA: u32 = ot_tag!('l', 'i', 'g', 'a');
|
||||||
static KERN: u32 = hb_tag!('k', 'e', 'r', 'n');
|
|
||||||
static LIGA: u32 = hb_tag!('l', 'i', 'g', 'a');
|
|
||||||
|
|
||||||
pub struct ShapedGlyphData {
|
pub struct ShapedGlyphData {
|
||||||
count: usize,
|
count: usize,
|
||||||
|
@ -207,7 +201,14 @@ impl ShaperMethods for Shaper {
|
||||||
/// Calculate the layout metrics associated with the given text when painted in a specific
|
/// Calculate the layout metrics associated with the given text when painted in a specific
|
||||||
/// font.
|
/// font.
|
||||||
fn shape_text(&self, text: &str, options: &ShapingOptions, glyphs: &mut GlyphStore) {
|
fn shape_text(&self, text: &str, options: &ShapingOptions, glyphs: &mut GlyphStore) {
|
||||||
|
if self.can_use_fast_path(text, options) {
|
||||||
|
debug!("shape_text: Using ASCII fast path.");
|
||||||
|
self.shape_text_fast(text, options, glyphs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
|
debug!("shape_text: Using Harfbuzz.");
|
||||||
|
|
||||||
let hb_buffer: *mut hb_buffer_t = hb_buffer_create();
|
let hb_buffer: *mut hb_buffer_t = hb_buffer_create();
|
||||||
hb_buffer_set_direction(hb_buffer, if options.flags.contains(RTL_FLAG) {
|
hb_buffer_set_direction(hb_buffer, if options.flags.contains(RTL_FLAG) {
|
||||||
HB_DIRECTION_RTL
|
HB_DIRECTION_RTL
|
||||||
|
@ -249,6 +250,47 @@ impl ShaperMethods for Shaper {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shaper {
|
impl Shaper {
|
||||||
|
fn can_use_fast_path(&self, text: &str, options: &ShapingOptions) -> bool {
|
||||||
|
let font = self.font_and_shaping_options.font;
|
||||||
|
|
||||||
|
options.script == Script::Latin &&
|
||||||
|
!options.flags.contains(RTL_FLAG) &&
|
||||||
|
unsafe { (*font).handle.can_do_fast_shaping() } &&
|
||||||
|
text.is_ascii()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fast path for ASCII text that only needs simple horizontal LTR kerning.
|
||||||
|
fn shape_text_fast(&self, text: &str, options: &ShapingOptions, glyphs: &mut GlyphStore) {
|
||||||
|
let font = unsafe { &mut *self.font_and_shaping_options.font };
|
||||||
|
|
||||||
|
let mut prev_glyph_id = None;
|
||||||
|
for (i, byte) in text.bytes().enumerate() {
|
||||||
|
let character = byte as char;
|
||||||
|
let glyph_id = match font.glyph_index(character) {
|
||||||
|
Some(id) => id,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut advance = Au::from_f64_px(font.glyph_h_advance(glyph_id));
|
||||||
|
if character == ' ' {
|
||||||
|
advance += options.word_spacing;
|
||||||
|
}
|
||||||
|
if let Some(letter_spacing) = options.letter_spacing {
|
||||||
|
advance += letter_spacing;
|
||||||
|
}
|
||||||
|
let offset = prev_glyph_id.map(|prev| {
|
||||||
|
let h_kerning = Au::from_f64_px(font.glyph_h_kerning(prev, glyph_id));
|
||||||
|
advance += h_kerning;
|
||||||
|
Point2D::new(h_kerning, Au(0))
|
||||||
|
});
|
||||||
|
|
||||||
|
let glyph = GlyphData::new(glyph_id, advance, offset, true, true);
|
||||||
|
glyphs.add_glyph_for_byte_index(ByteIndex(i as isize), character, &glyph);
|
||||||
|
prev_glyph_id = Some(glyph_id);
|
||||||
|
}
|
||||||
|
glyphs.finalize_changes();
|
||||||
|
}
|
||||||
|
|
||||||
fn save_glyph_results(&self,
|
fn save_glyph_results(&self,
|
||||||
text: &str,
|
text: &str,
|
||||||
options: &ShapingOptions,
|
options: &ShapingOptions,
|
||||||
|
@ -527,17 +569,15 @@ extern fn font_table_func(_: *mut hb_face_t,
|
||||||
// `Box::into_raw` intentionally leaks the FontTable so we don't destroy the buffer
|
// `Box::into_raw` intentionally leaks the FontTable so we don't destroy the buffer
|
||||||
// while HarfBuzz is using it. When HarfBuzz is done with the buffer, it will pass
|
// while HarfBuzz is using it. When HarfBuzz is done with the buffer, it will pass
|
||||||
// this raw pointer back to `destroy_blob_func` which will deallocate the Box.
|
// this raw pointer back to `destroy_blob_func` which will deallocate the Box.
|
||||||
let font_table_ptr = Box::into_raw(font_table);
|
let font_table_ptr = Box::into_raw(box font_table);
|
||||||
|
|
||||||
let mut blob: *mut hb_blob_t = ptr::null_mut();
|
let buf = (*font_table_ptr).buffer();
|
||||||
(*font_table_ptr).with_buffer(|buf: *const u8, len: usize| {
|
// HarfBuzz calls `destroy_blob_func` when the buffer is no longer needed.
|
||||||
// HarfBuzz calls `destroy_blob_func` when the buffer is no longer needed.
|
let blob = hb_blob_create(buf.as_ptr() as *const c_char,
|
||||||
blob = hb_blob_create(buf as *const c_char,
|
buf.len() as c_uint,
|
||||||
len as c_uint,
|
|
||||||
HB_MEMORY_MODE_READONLY,
|
HB_MEMORY_MODE_READONLY,
|
||||||
font_table_ptr as *mut c_void,
|
font_table_ptr as *mut c_void,
|
||||||
Some(destroy_blob_func));
|
Some(destroy_blob_func));
|
||||||
});
|
|
||||||
|
|
||||||
assert!(!blob.is_null());
|
assert!(!blob.is_null());
|
||||||
blob
|
blob
|
||||||
|
|
9
components/servo/Cargo.lock
generated
9
components/servo/Cargo.lock
generated
|
@ -101,7 +101,7 @@ source = "git+https://github.com/servo/rust-azure#a7177c8df81554352bc51de2f5b77c
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-text 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
||||||
"heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -404,7 +404,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-text"
|
name = "core-text"
|
||||||
version = "1.1.0"
|
version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -744,9 +744,10 @@ dependencies = [
|
||||||
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"azure 0.4.5 (git+https://github.com/servo/rust-azure)",
|
"azure 0.4.5 (git+https://github.com/servo/rust-azure)",
|
||||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-text 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
||||||
|
@ -2501,7 +2502,7 @@ dependencies = [
|
||||||
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-text 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
||||||
|
|
9
ports/cef/Cargo.lock
generated
9
ports/cef/Cargo.lock
generated
|
@ -78,7 +78,7 @@ source = "git+https://github.com/servo/rust-azure#a7177c8df81554352bc51de2f5b77c
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-text 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
||||||
"heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -366,7 +366,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-text"
|
name = "core-text"
|
||||||
version = "1.1.0"
|
version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -665,9 +665,10 @@ dependencies = [
|
||||||
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"azure 0.4.5 (git+https://github.com/servo/rust-azure)",
|
"azure 0.4.5 (git+https://github.com/servo/rust-azure)",
|
||||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-text 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
||||||
|
@ -2362,7 +2363,7 @@ dependencies = [
|
||||||
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-text 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
||||||
|
|
9
ports/gonk/Cargo.lock
generated
9
ports/gonk/Cargo.lock
generated
|
@ -80,7 +80,7 @@ source = "git+https://github.com/servo/rust-azure#a7177c8df81554352bc51de2f5b77c
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-text 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
||||||
"heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -368,7 +368,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-text"
|
name = "core-text"
|
||||||
version = "1.1.0"
|
version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -677,9 +677,10 @@ dependencies = [
|
||||||
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"azure 0.4.5 (git+https://github.com/servo/rust-azure)",
|
"azure 0.4.5 (git+https://github.com/servo/rust-azure)",
|
||||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-text 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
||||||
|
@ -2321,7 +2322,7 @@ dependencies = [
|
||||||
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-text 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue