Implement basic support for WOFF 1.0
This commit is contained in:
parent
9490fa2d3b
commit
5e9b8c9423
|
@ -7,6 +7,7 @@ authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||||
bitflags = "0.7"
|
bitflags = "0.7"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
euclid = "0.10"
|
euclid = "0.10"
|
||||||
|
flate2 = "0.2"
|
||||||
gl = "0.6"
|
gl = "0.6"
|
||||||
memmap = "0.5"
|
memmap = "0.5"
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
|
|
|
@ -66,6 +66,7 @@ fn main() {
|
||||||
let shelf_height = point_size * 2;
|
let shelf_height = point_size * 2;
|
||||||
|
|
||||||
let file = Mmap::open_path(env::args().nth(1).unwrap(), Protection::Read).unwrap();
|
let file = Mmap::open_path(env::args().nth(1).unwrap(), Protection::Read).unwrap();
|
||||||
|
let mut buffer = vec![];
|
||||||
|
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
let start = time::precise_time_ns();
|
let start = time::precise_time_ns();
|
||||||
|
@ -75,7 +76,7 @@ fn main() {
|
||||||
loop {
|
loop {
|
||||||
glyph_count = 0;
|
glyph_count = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
let font = Font::new(file.as_slice()).unwrap();
|
let font = Font::new(file.as_slice(), &mut buffer).unwrap();
|
||||||
let codepoint_ranges = [CodepointRange::new(' ' as u32, '~' as u32)];
|
let codepoint_ranges = [CodepointRange::new(' ' as u32, '~' as u32)];
|
||||||
|
|
||||||
let glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges)
|
let glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges)
|
||||||
|
|
|
@ -13,8 +13,9 @@ use std::env;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let file = Mmap::open_path(env::args().nth(1).unwrap(), Protection::Read).unwrap();
|
let file = Mmap::open_path(env::args().nth(1).unwrap(), Protection::Read).unwrap();
|
||||||
|
let mut buffer = vec![];
|
||||||
unsafe {
|
unsafe {
|
||||||
let font = Font::new(file.as_slice()).unwrap();
|
let font = Font::new(file.as_slice(), &mut buffer).unwrap();
|
||||||
let codepoint_ranges = [CodepointRange::new('!' as u32, '~' as u32)];
|
let codepoint_ranges = [CodepointRange::new('!' as u32, '~' as u32)];
|
||||||
let glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges).unwrap();
|
let glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges).unwrap();
|
||||||
for (glyph_index, (_, glyph_id)) in glyph_mapping.iter().enumerate() {
|
for (glyph_index, (_, glyph_id)) in glyph_mapping.iter().enumerate() {
|
||||||
|
|
|
@ -72,6 +72,7 @@ fn main() {
|
||||||
let rasterizer = Rasterizer::new(&instance, device, queue, rasterizer_options).unwrap();
|
let rasterizer = Rasterizer::new(&instance, device, queue, rasterizer_options).unwrap();
|
||||||
|
|
||||||
let file = Mmap::open_path(matches.value_of("FONT-FILE").unwrap(), Protection::Read).unwrap();
|
let file = Mmap::open_path(matches.value_of("FONT-FILE").unwrap(), Protection::Read).unwrap();
|
||||||
|
let mut buffer = vec![];
|
||||||
|
|
||||||
let point_size = match matches.value_of("POINT-SIZE") {
|
let point_size = match matches.value_of("POINT-SIZE") {
|
||||||
Some(point_size) => point_size.parse().unwrap(),
|
Some(point_size) => point_size.parse().unwrap(),
|
||||||
|
@ -85,7 +86,7 @@ fn main() {
|
||||||
|
|
||||||
let (outlines, atlas);
|
let (outlines, atlas);
|
||||||
unsafe {
|
unsafe {
|
||||||
let font = Font::from_collection_index(file.as_slice(), font_index).unwrap();
|
let font = Font::from_collection_index(file.as_slice(), font_index, &mut buffer).unwrap();
|
||||||
let codepoint_ranges = [CodepointRange::new(' ' as u32, '~' as u32)];
|
let codepoint_ranges = [CodepointRange::new(' ' as u32, '~' as u32)];
|
||||||
let glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges).unwrap();
|
let glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -102,8 +102,9 @@ fn main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let file = Mmap::open_path(matches.value_of("FONT-FILE").unwrap(), Protection::Read).unwrap();
|
let file = Mmap::open_path(matches.value_of("FONT-FILE").unwrap(), Protection::Read).unwrap();
|
||||||
|
let mut buffer = vec![];
|
||||||
let font = unsafe {
|
let font = unsafe {
|
||||||
Font::from_collection_index(file.as_slice(), font_index).unwrap()
|
Font::from_collection_index(file.as_slice(), font_index, &mut buffer).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let units_per_em = font.units_per_em() as f32;
|
let units_per_em = font.units_per_em() as f32;
|
||||||
|
|
|
@ -18,6 +18,8 @@ use font::Font;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use util::Jump;
|
use util::Jump;
|
||||||
|
|
||||||
|
pub const MAGIC_NUMBER: u32 = 0x0100;
|
||||||
|
|
||||||
const SFNT: u32 = ((b's' as u32) << 24) |
|
const SFNT: u32 = ((b's' as u32) << 24) |
|
||||||
((b'f' as u32) << 16) |
|
((b'f' as u32) << 16) |
|
||||||
((b'n' as u32) << 8) |
|
((b'n' as u32) << 8) |
|
||||||
|
|
|
@ -13,4 +13,5 @@
|
||||||
pub mod dfont;
|
pub mod dfont;
|
||||||
pub mod otf;
|
pub mod otf;
|
||||||
pub mod ttc;
|
pub mod ttc;
|
||||||
|
pub mod woff;
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,31 @@ const OTTO: u32 = ((b'O' as u32) << 24) |
|
||||||
((b'T' as u32) << 8) |
|
((b'T' as u32) << 8) |
|
||||||
(b'O' as u32);
|
(b'O' as u32);
|
||||||
|
|
||||||
|
pub const KNOWN_TABLE_COUNT: usize = 9;
|
||||||
|
|
||||||
|
pub static KNOWN_TABLES: [u32; KNOWN_TABLE_COUNT] = [
|
||||||
|
cff::TAG,
|
||||||
|
os_2::TAG,
|
||||||
|
cmap::TAG,
|
||||||
|
glyf::TAG,
|
||||||
|
head::TAG,
|
||||||
|
hhea::TAG,
|
||||||
|
hmtx::TAG,
|
||||||
|
kern::TAG,
|
||||||
|
loca::TAG,
|
||||||
|
];
|
||||||
|
|
||||||
|
// This must agree with the above.
|
||||||
|
const TABLE_INDEX_CFF: usize = 0;
|
||||||
|
const TABLE_INDEX_OS_2: usize = 1;
|
||||||
|
const TABLE_INDEX_CMAP: usize = 2;
|
||||||
|
const TABLE_INDEX_GLYF: usize = 3;
|
||||||
|
const TABLE_INDEX_HEAD: usize = 4;
|
||||||
|
const TABLE_INDEX_HHEA: usize = 5;
|
||||||
|
const TABLE_INDEX_HMTX: usize = 6;
|
||||||
|
const TABLE_INDEX_KERN: usize = 7;
|
||||||
|
const TABLE_INDEX_LOCA: usize = 8;
|
||||||
|
|
||||||
pub static SFNT_VERSIONS: [u32; 3] = [
|
pub static SFNT_VERSIONS: [u32; 3] = [
|
||||||
0x10000,
|
0x10000,
|
||||||
((b't' as u32) << 24) | ((b'r' as u32) << 16) | ((b'u' as u32) << 8) | (b'e' as u32),
|
((b't' as u32) << 24) | ((b'r' as u32) << 16) | ((b'u' as u32) << 8) | (b'e' as u32),
|
||||||
|
@ -65,32 +90,18 @@ impl<'a> Font<'a> {
|
||||||
let num_tables = try!(reader.read_u16::<BigEndian>().map_err(FontError::eof));
|
let num_tables = try!(reader.read_u16::<BigEndian>().map_err(FontError::eof));
|
||||||
try!(reader.jump(mem::size_of::<u16>() * 3).map_err(FontError::eof));
|
try!(reader.jump(mem::size_of::<u16>() * 3).map_err(FontError::eof));
|
||||||
|
|
||||||
let (mut cff_table, mut cmap_table) = (None, None);
|
let mut tables = [None; KNOWN_TABLE_COUNT];
|
||||||
let (mut glyf_table, mut head_table) = (None, None);
|
|
||||||
let (mut hhea_table, mut hmtx_table) = (None, None);
|
|
||||||
let (mut kern_table, mut loca_table) = (None, None);
|
|
||||||
let mut os_2_table = None;
|
|
||||||
|
|
||||||
for _ in 0..num_tables {
|
for _ in 0..num_tables {
|
||||||
let table_id = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
let table_id = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
|
let _checksum = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
// Skip over the checksum.
|
|
||||||
try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
|
||||||
|
|
||||||
let offset = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof)) as usize;
|
let offset = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof)) as usize;
|
||||||
let length = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof)) as usize;
|
let length = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof)) as usize;
|
||||||
|
|
||||||
let mut slot = match table_id {
|
// Find the table ID in our list of known IDs, which must be sorted.
|
||||||
cff::TAG => &mut cff_table,
|
debug_assert!(KNOWN_TABLES.windows(2).all(|w| w[0] < w[1]));
|
||||||
cmap::TAG => &mut cmap_table,
|
let slot = match KNOWN_TABLES.binary_search(&table_id) {
|
||||||
glyf::TAG => &mut glyf_table,
|
Err(_) => continue,
|
||||||
head::TAG => &mut head_table,
|
Ok(table_index) => &mut tables[table_index],
|
||||||
hhea::TAG => &mut hhea_table,
|
|
||||||
hmtx::TAG => &mut hmtx_table,
|
|
||||||
kern::TAG => &mut kern_table,
|
|
||||||
loca::TAG => &mut loca_table,
|
|
||||||
os_2::TAG => &mut os_2_table,
|
|
||||||
_ => continue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make sure there isn't more than one copy of the table.
|
// Make sure there isn't more than one copy of the table.
|
||||||
|
@ -103,27 +114,37 @@ impl<'a> Font<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let cff_table = match cff_table {
|
Font::from_table_list(bytes, &tables)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn from_table_list<'b>(bytes: &'b [u8],
|
||||||
|
tables: &[Option<FontTable<'b>>; KNOWN_TABLE_COUNT])
|
||||||
|
-> Result<Font<'b>, FontError> {
|
||||||
|
let cff_table = match tables[TABLE_INDEX_CFF] {
|
||||||
None => None,
|
None => None,
|
||||||
Some(cff_table) => Some(try!(CffTable::new(cff_table))),
|
Some(cff_table) => Some(try!(CffTable::new(cff_table))),
|
||||||
};
|
};
|
||||||
|
|
||||||
let loca_table = match loca_table {
|
let loca_table = match tables[TABLE_INDEX_LOCA] {
|
||||||
None => None,
|
None => None,
|
||||||
Some(loca_table) => Some(try!(LocaTable::new(loca_table))),
|
Some(loca_table) => Some(try!(LocaTable::new(loca_table))),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For brevity below…
|
||||||
|
let missing = FontError::RequiredTableMissing;
|
||||||
|
|
||||||
let tables = FontTables {
|
let tables = FontTables {
|
||||||
cmap: CmapTable::new(try!(cmap_table.ok_or(FontError::RequiredTableMissing))),
|
cmap: CmapTable::new(try!(tables[TABLE_INDEX_CMAP].ok_or(missing))),
|
||||||
head: try!(HeadTable::new(try!(head_table.ok_or(FontError::RequiredTableMissing)))),
|
head: try!(HeadTable::new(try!(tables[TABLE_INDEX_HEAD].ok_or(missing)))),
|
||||||
hhea: try!(HheaTable::new(try!(hhea_table.ok_or(FontError::RequiredTableMissing)))),
|
hhea: try!(HheaTable::new(try!(tables[TABLE_INDEX_HHEA].ok_or(missing)))),
|
||||||
hmtx: HmtxTable::new(try!(hmtx_table.ok_or(FontError::RequiredTableMissing))),
|
hmtx: HmtxTable::new(try!(tables[TABLE_INDEX_HMTX].ok_or(missing))),
|
||||||
os_2: try!(Os2Table::new(try!(os_2_table.ok_or(FontError::RequiredTableMissing)))),
|
os_2: try!(Os2Table::new(try!(tables[TABLE_INDEX_OS_2].ok_or(missing)))),
|
||||||
|
|
||||||
cff: cff_table,
|
cff: cff_table,
|
||||||
glyf: glyf_table.map(GlyfTable::new),
|
glyf: tables[TABLE_INDEX_GLYF].map(GlyfTable::new),
|
||||||
loca: loca_table,
|
loca: loca_table,
|
||||||
kern: kern_table.and_then(|table| KernTable::new(table).ok()),
|
kern: tables[TABLE_INDEX_KERN].and_then(|table| KernTable::new(table).ok()),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Font::from_tables(bytes, tables))
|
Ok(Font::from_tables(bytes, tables))
|
||||||
|
|
|
@ -18,10 +18,10 @@ use font::Font;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use util::Jump;
|
use util::Jump;
|
||||||
|
|
||||||
pub const TTCF: u32 = ((b't' as u32) << 24) |
|
pub const MAGIC_NUMBER: u32 = ((b't' as u32) << 24) |
|
||||||
((b't' as u32) << 16) |
|
((b't' as u32) << 16) |
|
||||||
((b'c' as u32) << 8) |
|
((b'c' as u32) << 8) |
|
||||||
(b'f' as u32);
|
(b'f' as u32);
|
||||||
|
|
||||||
impl<'a> Font<'a> {
|
impl<'a> Font<'a> {
|
||||||
/// Creates a new font from a single font within a byte buffer containing the contents of a
|
/// Creates a new font from a single font within a byte buffer containing the contents of a
|
||||||
|
@ -29,7 +29,7 @@ impl<'a> Font<'a> {
|
||||||
pub fn from_ttc_index<'b>(bytes: &'b [u8], index: u32) -> Result<Font<'b>, FontError> {
|
pub fn from_ttc_index<'b>(bytes: &'b [u8], index: u32) -> Result<Font<'b>, FontError> {
|
||||||
let mut reader = bytes;
|
let mut reader = bytes;
|
||||||
let magic_number = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
let magic_number = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
if magic_number != TTCF {
|
if magic_number != MAGIC_NUMBER {
|
||||||
return Err(FontError::UnknownFormat)
|
return Err(FontError::UnknownFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
// Copyright 2017 The Servo Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! Web Open Font Format 1.0 (`.woff`) files.
|
||||||
|
//!
|
||||||
|
//! See the specification: https://www.w3.org/TR/WOFF/
|
||||||
|
//!
|
||||||
|
//! TODO(pcwalton): WOFF 2.0.
|
||||||
|
|
||||||
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
|
use containers::otf::{KNOWN_TABLES, KNOWN_TABLE_COUNT, SFNT_VERSIONS};
|
||||||
|
use error::FontError;
|
||||||
|
use flate2::FlateReadExt;
|
||||||
|
use font::{Font, FontTable};
|
||||||
|
use std::io::Read;
|
||||||
|
use std::iter;
|
||||||
|
use std::mem;
|
||||||
|
use util::Jump;
|
||||||
|
|
||||||
|
pub const MAGIC_NUMBER: u32 = ((b'w' as u32) << 24) |
|
||||||
|
((b'O' as u32) << 16) |
|
||||||
|
((b'F' as u32) << 8) |
|
||||||
|
(b'F' as u32);
|
||||||
|
|
||||||
|
impl<'a> Font<'a> {
|
||||||
|
/// Creates a new font from a buffer containing data in the WOFF format.
|
||||||
|
///
|
||||||
|
/// The given buffer will be used to decompress data.
|
||||||
|
///
|
||||||
|
/// Decompresses eagerly.
|
||||||
|
pub fn from_woff<'b>(bytes: &'b [u8], buffer: &'b mut Vec<u8>) -> Result<Font<'b>, FontError> {
|
||||||
|
let mut reader = bytes;
|
||||||
|
|
||||||
|
// Check magic number.
|
||||||
|
let magic_number = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
|
if magic_number != MAGIC_NUMBER {
|
||||||
|
return Err(FontError::UnknownFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the flavor.
|
||||||
|
let flavor = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
|
if !SFNT_VERSIONS.contains(&flavor) {
|
||||||
|
return Err(FontError::UnknownFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the number of tables.
|
||||||
|
let _length = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
|
let num_tables = try!(reader.read_u16::<BigEndian>().map_err(FontError::eof));
|
||||||
|
let _reserved = try!(reader.read_u16::<BigEndian>().map_err(FontError::eof));
|
||||||
|
|
||||||
|
// Allocate size for uncompressed tables.
|
||||||
|
let total_sfnt_size = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
|
try!(reader.jump(mem::size_of::<u32>() * 6).map_err(FontError::eof));
|
||||||
|
let buffer_start = buffer.len();
|
||||||
|
buffer.extend(iter::repeat(0).take(total_sfnt_size as usize));
|
||||||
|
let mut buffer = &mut buffer[buffer_start..];
|
||||||
|
|
||||||
|
// Decompress and load tables as necessary.
|
||||||
|
let mut tables = [None; KNOWN_TABLE_COUNT];
|
||||||
|
for _ in 0..num_tables {
|
||||||
|
let tag = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
|
let offset = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
|
let comp_length = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
|
let orig_length = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
|
let _orig_checksum = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
|
|
||||||
|
// Find the table ID in our list of known IDs, which must be sorted.
|
||||||
|
debug_assert!(KNOWN_TABLES.windows(2).all(|w| w[0] < w[1]));
|
||||||
|
let slot = match KNOWN_TABLES.binary_search(&tag) {
|
||||||
|
Err(_) => continue,
|
||||||
|
Ok(table_index) => &mut tables[table_index],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make sure there isn't more than one copy of the table.
|
||||||
|
if slot.is_some() {
|
||||||
|
return Err(FontError::Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate space in the buffer.
|
||||||
|
let comp_end = offset as usize + comp_length as usize;
|
||||||
|
let mut temp = buffer; // borrow check black magic
|
||||||
|
let (mut dest, mut rest) = temp.split_at_mut(orig_length as usize);
|
||||||
|
buffer = rest;
|
||||||
|
|
||||||
|
// Decompress or copy as applicable.
|
||||||
|
//
|
||||||
|
// FIXME(pcwalton): Errors here may be zlib errors, not EOFs.
|
||||||
|
if comp_length != orig_length {
|
||||||
|
let mut table_reader = bytes;
|
||||||
|
try!(table_reader.jump(offset as usize).map_err(FontError::eof));
|
||||||
|
let mut table_reader = table_reader.zlib_decode();
|
||||||
|
try!(table_reader.read_exact(dest).map_err(FontError::eof));
|
||||||
|
} else if comp_end <= bytes.len() {
|
||||||
|
dest.clone_from_slice(&bytes[offset as usize..comp_end])
|
||||||
|
} else {
|
||||||
|
return Err(FontError::UnexpectedEof)
|
||||||
|
}
|
||||||
|
|
||||||
|
*slot = Some(FontTable {
|
||||||
|
bytes: dest,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Font::from_table_list(bytes, &tables)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
22
src/font.rs
22
src/font.rs
|
@ -12,8 +12,10 @@
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use charmap::{CodepointRange, GlyphMapping};
|
use charmap::{CodepointRange, GlyphMapping};
|
||||||
|
use containers::dfont;
|
||||||
use containers::otf::{FontTables, SFNT_VERSIONS};
|
use containers::otf::{FontTables, SFNT_VERSIONS};
|
||||||
use containers::ttc::TTCF;
|
use containers::ttc;
|
||||||
|
use containers::woff;
|
||||||
use error::FontError;
|
use error::FontError;
|
||||||
use euclid::Point2D;
|
use euclid::Point2D;
|
||||||
use outline::GlyphBounds;
|
use outline::GlyphBounds;
|
||||||
|
@ -49,9 +51,12 @@ impl<'a> Font<'a> {
|
||||||
/// If this is a `.ttc` or `.dfont` collection, this returns the first font within it. If you
|
/// If this is a `.ttc` or `.dfont` collection, this returns the first font within it. If you
|
||||||
/// want to read another one, use the `Font::from_collection_index` API.
|
/// want to read another one, use the `Font::from_collection_index` API.
|
||||||
///
|
///
|
||||||
|
/// The supplied `buffer` is an arbitrary vector that may or may not be used as a temporary
|
||||||
|
/// storage space. Typically you will want to just pass an empty vector here.
|
||||||
|
///
|
||||||
/// Returns the font on success or an error on failure.
|
/// Returns the font on success or an error on failure.
|
||||||
pub fn new<'b>(bytes: &'b [u8]) -> Result<Font<'b>, FontError> {
|
pub fn new<'b>(bytes: &'b [u8], buffer: &'b mut Vec<u8>) -> Result<Font<'b>, FontError> {
|
||||||
Font::from_collection_index(bytes, 0)
|
Font::from_collection_index(bytes, 0, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new font from a single font within a byte buffer containing the contents of a
|
/// Creates a new font from a single font within a byte buffer containing the contents of a
|
||||||
|
@ -59,15 +64,20 @@ impl<'a> Font<'a> {
|
||||||
///
|
///
|
||||||
/// If this is a `.ttc` or `.dfont` collection, this returns the appropriate font within it.
|
/// If this is a `.ttc` or `.dfont` collection, this returns the appropriate font within it.
|
||||||
///
|
///
|
||||||
|
/// The supplied `buffer` is an arbitrary vector that may or may not be used as a temporary
|
||||||
|
/// storage space. Typically you will want to just pass an empty vector here.
|
||||||
|
///
|
||||||
/// Returns the font on success or an error on failure.
|
/// Returns the font on success or an error on failure.
|
||||||
pub fn from_collection_index<'b>(bytes: &'b [u8], index: u32) -> Result<Font<'b>, FontError> {
|
pub fn from_collection_index<'b>(bytes: &'b [u8], index: u32, buffer: &'b mut Vec<u8>)
|
||||||
|
-> Result<Font<'b>, FontError> {
|
||||||
// Check the magic number.
|
// Check the magic number.
|
||||||
let mut reader = bytes;
|
let mut reader = bytes;
|
||||||
let magic_number = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
let magic_number = try!(reader.read_u32::<BigEndian>().map_err(FontError::eof));
|
||||||
match magic_number {
|
match magic_number {
|
||||||
TTCF => Font::from_ttc_index(bytes, index),
|
ttc::MAGIC_NUMBER => Font::from_ttc_index(bytes, index),
|
||||||
|
woff::MAGIC_NUMBER => Font::from_woff(bytes, buffer),
|
||||||
|
dfont::MAGIC_NUMBER => Font::from_dfont_index(bytes, index),
|
||||||
magic_number if SFNT_VERSIONS.contains(&magic_number) => Font::from_otf(bytes, 0),
|
magic_number if SFNT_VERSIONS.contains(&magic_number) => Font::from_otf(bytes, 0),
|
||||||
0x0100 => Font::from_dfont_index(bytes, index),
|
|
||||||
_ => Err(FontError::UnknownFormat),
|
_ => Err(FontError::UnknownFormat),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,7 @@ extern crate bitflags;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate compute_shader;
|
extern crate compute_shader;
|
||||||
extern crate euclid;
|
extern crate euclid;
|
||||||
|
extern crate flate2;
|
||||||
extern crate gl;
|
extern crate gl;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate memmap;
|
extern crate memmap;
|
||||||
|
|
|
@ -12,8 +12,9 @@ static TEST_FONT_PATH: &'static str = "resources/tests/nimbus-sans/NimbusSanL-Re
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_add_glyphs(bencher: &mut Bencher) {
|
fn bench_add_glyphs(bencher: &mut Bencher) {
|
||||||
let file = Mmap::open_path(TEST_FONT_PATH, Protection::Read).expect("Couldn't open test font");
|
let file = Mmap::open_path(TEST_FONT_PATH, Protection::Read).expect("Couldn't open test font");
|
||||||
|
let mut buffer = vec![];
|
||||||
unsafe {
|
unsafe {
|
||||||
let font = Font::new(file.as_slice()).unwrap();
|
let font = Font::new(file.as_slice(), &mut buffer).unwrap();
|
||||||
let codepoint_ranges = [CodepointRange::new('!' as u32, '~' as u32)];
|
let codepoint_ranges = [CodepointRange::new('!' as u32, '~' as u32)];
|
||||||
let glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges)
|
let glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges)
|
||||||
.expect("Couldn't find glyph ranges");
|
.expect("Couldn't find glyph ranges");
|
||||||
|
|
Loading…
Reference in New Issue