Unify the android + linux font code folders. Fixes #3028.

This commit is contained in:
Glenn Watson 2014-08-08 13:33:08 +10:00
parent 1c0e51015f
commit 0442d8afca
9 changed files with 14 additions and 530 deletions

View file

@ -1,105 +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/. */
#![allow(uppercase_variables)]
extern crate freetype;
extern crate fontconfig;
use fontconfig::fontconfig::{FcChar8, FcResultMatch, FcSetSystem};
use fontconfig::fontconfig::{
FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
FcPatternDestroy, FcFontSetDestroy,
FcPatternCreate, FcPatternAddString,
FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
FcObjectSetAdd, FcPatternGetInteger
};
use libc;
use libc::{c_int, c_char};
use std::ptr;
use std::str;
pub fn get_available_families(callback: |String|) {
unsafe {
let config = FcConfigGetCurrent();
let fontSet = FcConfigGetFonts(config, FcSetSystem);
for i in range(0, (*fontSet).nfont as int) {
let font = (*fontSet).fonts.offset(i);
let mut family: *mut FcChar8 = ptr::mut_null();
let mut v: c_int = 0;
let mut FC_FAMILY_C = "family".to_c_str();
let FC_FAMILY = FC_FAMILY_C.as_mut_ptr();
while FcPatternGetString(*font, FC_FAMILY, v, &mut family) == FcResultMatch {
let family_name = str::raw::from_c_str(family as *const c_char);
callback(family_name);
v += 1;
}
}
}
}
pub fn get_variations_for_family(family_name: &str, callback: |String|) {
debug!("getting variations for {}", family_name);
unsafe {
let config = FcConfigGetCurrent();
let mut font_set = FcConfigGetFonts(config, FcSetSystem);
let font_set_array_ptr = &mut font_set;
let pattern = FcPatternCreate();
assert!(pattern.is_not_null());
let mut FC_FAMILY_C = "family".to_c_str();
let FC_FAMILY = FC_FAMILY_C.as_mut_ptr();
let mut family_name_c = family_name.to_c_str();
let family_name = family_name_c.as_mut_ptr();
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *mut FcChar8);
assert!(ok != 0);
let object_set = FcObjectSetCreate();
assert!(object_set.is_not_null());
let mut FC_FILE_C = "file".to_c_str();
let FC_FILE = FC_FILE_C.as_mut_ptr();
FcObjectSetAdd(object_set, FC_FILE);
let mut FC_INDEX_C = "index".to_c_str();
let FC_INDEX = FC_INDEX_C.as_mut_ptr();
FcObjectSetAdd(object_set, FC_INDEX);
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
debug!("found {} variations", (*matches).nfont);
for i in range(0, (*matches).nfont as int) {
let font = (*matches).fonts.offset(i);
let mut FC_FILE_C = "file".to_c_str();
let FC_FILE = FC_FILE_C.as_mut_ptr();
let mut file: *mut FcChar8 = ptr::mut_null();
let file = if FcPatternGetString(*font, FC_FILE, 0, &mut file) == FcResultMatch {
str::raw::from_c_str(file as *const libc::c_char)
} else {
fail!();
};
let mut FC_INDEX_C = "index".to_c_str();
let FC_INDEX = FC_INDEX_C.as_mut_ptr();
let mut index: libc::c_int = 0;
let index = if FcPatternGetInteger(*font, FC_INDEX, 0, &mut index) == FcResultMatch {
index
} else {
fail!();
};
debug!("variation file: {}", file);
debug!("variation index: {}", index);
callback(file);
}
FcFontSetDestroy(matches);
FcPatternDestroy(pattern);
FcObjectSetDestroy(object_set);
}
}
pub fn get_last_resort_font_families() -> Vec<String> {
vec!("Roboto".to_string())
}

View file

@ -1,35 +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::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, font_data: Option<Vec<u8>>) -> FontTemplateData {
let bytes = match font_data {
Some(bytes) => {
bytes
},
None => {
// TODO: Handle file load failure!
let mut file = File::open_mode(&Path::new(identifier), io::Open, io::Read).unwrap();
file.read_to_end().unwrap()
},
};
FontTemplateData {
bytes: bytes,
identifier: identifier.to_string(),
}
}
}

View file

@ -100,6 +100,7 @@ pub fn get_variations_for_family(family_name: &str, callback: |String|) {
} }
} }
#[cfg(target_os="linux")]
pub fn get_last_resort_font_families() -> Vec<String> { pub fn get_last_resort_font_families() -> Vec<String> {
vec!( vec!(
"Fira Sans".to_string(), "Fira Sans".to_string(),
@ -107,3 +108,8 @@ pub fn get_last_resort_font_families() -> Vec<String> {
"Arial".to_string() "Arial".to_string()
) )
} }
#[cfg(target_os="android")]
pub fn get_last_resort_font_families() -> Vec<String> {
vec!("Roboto".to_string())
}

View file

@ -1,296 +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/. */
extern crate freetype;
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
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_Get_Kerning, 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};
use freetype::freetype::{FT_KERNING_DEFAULT, FT_STYLE_FLAG_ITALIC, FT_STYLE_FLAG_BOLD};
use freetype::freetype::{FT_SizeRec, FT_UInt, FT_Size_Metrics, struct_FT_Vector_};
use freetype::freetype::{ft_sfnt_os2};
use freetype::tt_os2::TT_OS2;
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)
}
fn fixed_to_float_ft(f: i32) -> f64 {
fixed_to_float(6, f)
}
pub struct FontTable;
impl FontTableMethods for FontTable {
fn with_buffer(&self, _blk: |*const u8, uint|) {
fail!()
}
}
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 font_data: Arc<FontTemplateData>,
pub face: FT_Face,
pub handle: FontContextHandle
}
#[unsafe_destructor]
impl Drop for FontHandle {
fn drop(&mut self) {
assert!(self.face.is_not_null());
unsafe {
if !FT_Done_Face(self.face).succeeded() {
fail!("FT_Done_Face failed");
}
}
}
}
impl FontHandleMethods for FontHandle {
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 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
// captured binding.
return match face_result {
Ok(face) => {
let handle = FontHandle {
face: face,
font_data: template.clone(),
handle: fctx.clone()
};
Ok(handle)
}
Err(()) => Err(())
};
fn create_face_from_buffer(lib: FT_Library, cbuf: *const u8, cbuflen: uint, pt_size: Option<f64>)
-> Result<FT_Face, ()> {
unsafe {
let mut face: FT_Face = ptr::mut_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(());
}
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) }
}
fn face_name(&self) -> String {
unsafe { str::raw::from_c_str(&*FT_Get_Postscript_Name(self.face)) }
}
fn is_italic(&self) -> bool {
unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
}
fn boldness(&self) -> font_weight::T {
let default_weight = font_weight::Weight400;
if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
default_weight
} else {
unsafe {
let os2 = FT_Get_Sfnt_Table(self.face, ft_sfnt_os2) as *mut TT_OS2;
let valid = os2.is_not_null() && (*os2).version != 0xffff;
if valid {
let weight =(*os2).usWeightClass;
match weight {
1 | 100..199 => font_weight::Weight100,
2 | 200..299 => font_weight::Weight200,
3 | 300..399 => font_weight::Weight300,
4 | 400..499 => font_weight::Weight400,
5 | 500..599 => font_weight::Weight500,
6 | 600..699 => font_weight::Weight600,
7 | 700..799 => font_weight::Weight700,
8 | 800..899 => font_weight::Weight800,
9 | 900..999 => font_weight::Weight900,
_ => default_weight
}
} else {
default_weight
}
}
}
}
fn glyph_index(&self,
codepoint: char) -> Option<GlyphId> {
assert!(self.face.is_not_null());
unsafe {
let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
return if idx != 0 as FT_UInt {
Some(idx as GlyphId)
} else {
debug!("Invalid codepoint: {}", codepoint);
None
};
}
}
fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId)
-> FractionalPixel {
assert!(self.face.is_not_null());
let mut delta = struct_FT_Vector_ { x: 0, y: 0 };
unsafe {
FT_Get_Kerning(self.face, first_glyph, second_glyph, FT_KERNING_DEFAULT, &mut delta);
}
fixed_to_float_ft(delta.x as i32)
}
fn glyph_h_advance(&self,
glyph: GlyphId) -> Option<FractionalPixel> {
assert!(self.face.is_not_null());
unsafe {
let res = FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
if res.succeeded() {
let void_glyph = (*self.face).glyph;
let slot: FT_GlyphSlot = mem::transmute(void_glyph);
assert!(slot.is_not_null());
debug!("metrics: {:?}", (*slot).metrics);
let advance = (*slot).metrics.horiAdvance;
debug!("h_advance for {} is {}", glyph, advance);
let advance = advance as i32;
return Some(fixed_to_float_ft(advance) as FractionalPixel);
} else {
debug!("Unable to load glyph {}. reason: {}", glyph, res);
return None;
}
}
}
fn get_metrics(&self) -> FontMetrics {
/* TODO(Issue #76): complete me */
let face = self.get_face_rec();
let underline_size = self.font_units_to_au(face.underline_thickness as f64);
let underline_offset = self.font_units_to_au(face.underline_position as f64);
let em_size = self.font_units_to_au(face.units_per_EM as f64);
let ascent = self.font_units_to_au(face.ascender as f64);
let descent = self.font_units_to_au(face.descender as f64);
let max_advance = self.font_units_to_au(face.max_advance_width as f64);
// 'leading' is supposed to be the vertical distance between two baselines,
// reflected by the height attibute in freetype. On OS X (w/ CTFont),
// leading represents the distance between the bottom of a line descent to
// the top of the next line's ascent or: (line_height - ascent - descent),
// see http://stackoverflow.com/a/5635981 for CTFont implementation.
// Convert using a formular similar to what CTFont returns for consistency.
let height = self.font_units_to_au(face.height as f64);
let leading = height - (ascent + descent);
let mut strikeout_size = geometry::from_pt(0.0);
let mut strikeout_offset = geometry::from_pt(0.0);
let mut x_height = geometry::from_pt(0.0);
unsafe {
let os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2) as *mut TT_OS2;
let valid = os2.is_not_null() && (*os2).version != 0xffff;
if valid {
strikeout_size = self.font_units_to_au((*os2).yStrikeoutSize as f64);
strikeout_offset = self.font_units_to_au((*os2).yStrikeoutPosition as f64);
x_height = self.font_units_to_au((*os2).sxHeight as f64);
}
}
let metrics = FontMetrics {
underline_size: underline_size,
underline_offset: underline_offset,
strikeout_size: strikeout_size,
strikeout_offset: strikeout_offset,
leading: leading,
x_height: x_height,
em_size: em_size,
ascent: ascent,
descent: -descent, // linux font's seem to use the opposite sign from mac
max_advance: max_advance
};
debug!("Font metrics (@{:f} pt): {:?}", geometry::to_pt(em_size), metrics);
return metrics;
}
fn get_table_for_tag(&self, _: FontTableTag) -> Option<FontTable> {
None
}
}
impl<'a> FontHandle {
fn set_char_size(face: FT_Face, pt_size: f64) -> Result<(), ()>{
let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
let h_dpi = 72;
let v_dpi = 72;
unsafe {
let result = FT_Set_Char_Size(face, char_width, char_height, h_dpi, v_dpi);
if result.succeeded() { Ok(()) } else { Err(()) }
}
}
fn get_face_rec(&'a self) -> &'a mut FT_FaceRec {
unsafe {
&mut (*self.face)
}
}
fn font_units_to_au(&self, value: f64) -> Au {
let face = self.get_face_rec();
// face.size is a *c_void in the bindings, presumably to avoid
// recursive structural types
let size: &FT_SizeRec = unsafe { mem::transmute(&(*face.size)) };
let metrics: &FT_Size_Metrics = &(*size).metrics;
let em_size = face.units_per_EM as f64;
let x_scale = (metrics.x_ppem as f64) / em_size as f64;
// If this isn't true then we're scaling one of the axes wrong
assert!(metrics.x_ppem == metrics.y_ppem);
return geometry::from_frac_px(value * x_scale);
}
}

View file

@ -1,82 +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 freetype::freetype::FTErrorMethods;
use freetype::freetype::FT_Add_Default_Modules;
use freetype::freetype::FT_Done_FreeType;
use freetype::freetype::FT_Library;
use freetype::freetype::FT_Memory;
use freetype::freetype::FT_New_Library;
use freetype::freetype::struct_FT_MemoryRec_;
use std::ptr;
use std::rc::Rc;
use libc;
use libc::{c_void, c_long, size_t, malloc};
use std::mem;
extern fn ft_alloc(_mem: FT_Memory, size: c_long) -> *mut c_void {
unsafe {
let ptr = libc::malloc(size as size_t);
ptr as *mut c_void
}
}
extern fn ft_free(_mem: FT_Memory, block: *mut c_void) {
unsafe {
libc::free(block);
}
}
extern fn ft_realloc(_mem: FT_Memory, _cur_size: c_long, new_size: c_long, block: *mut c_void) -> *mut c_void {
unsafe {
let ptr = libc::realloc(block, new_size as size_t);
ptr as *mut c_void
}
}
#[deriving(Clone)]
pub struct FreeTypeLibraryHandle {
pub ctx: FT_Library,
}
#[deriving(Clone)]
pub struct FontContextHandle {
pub ctx: Rc<FreeTypeLibraryHandle>,
}
impl Drop for FreeTypeLibraryHandle {
fn drop(&mut self) {
assert!(self.ctx.is_not_null());
unsafe { FT_Done_FreeType(self.ctx) };
}
}
impl FontContextHandle {
pub fn new() -> FontContextHandle {
unsafe {
let ptr = libc::malloc(mem::size_of::<struct_FT_MemoryRec_>() as size_t);
let allocator: &mut struct_FT_MemoryRec_ = mem::transmute(ptr);
ptr::write(allocator, struct_FT_MemoryRec_ {
user: ptr::mut_null(),
alloc: ft_alloc,
free: ft_free,
realloc: ft_realloc,
});
let mut ctx: FT_Library = ptr::mut_null();
let result = FT_New_Library(ptr as FT_Memory, &mut ctx);
if !result.succeeded() { fail!("Unable to initialize FreeType library"); }
FT_Add_Default_Modules(ctx);
FontContextHandle {
ctx: Rc::new(FreeTypeLibraryHandle { ctx: ctx }),
}
}
}
}

View file

@ -2,12 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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, font_template}; #[cfg(target_os="linux")]
#[cfg(target_os="macos")] pub use platform::macos::{font, font_context, font_list, font_template}; #[cfg(target_os="android")]
#[cfg(target_os="android")] pub use platform::android::{font, font_context, font_list, font_template}; pub use platform::freetype::{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="linux")] #[cfg(target_os="linux")]
pub mod linux { #[cfg(target_os="android")]
pub mod freetype {
pub mod font; pub mod font;
pub mod font_context; pub mod font_context;
pub mod font_list; pub mod font_list;
@ -21,11 +25,3 @@ pub mod macos {
pub mod font_list; pub mod font_list;
pub mod font_template; pub mod font_template;
} }
#[cfg(target_os="android")]
pub mod android {
pub mod font;
pub mod font_context;
pub mod font_list;
pub mod font_template;
}