From 0442d8afcadf0a814f816d241832ff0ee114de6e Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Fri, 8 Aug 2014 13:33:08 +1000 Subject: [PATCH] Unify the android + linux font code folders. Fixes #3028. --- .../gfx/platform/android/font_list.rs | 105 ------- .../gfx/platform/android/font_template.rs | 35 --- .../platform/{android => freetype}/font.rs | 0 .../{android => freetype}/font_context.rs | 0 .../platform/{linux => freetype}/font_list.rs | 6 + .../{linux => freetype}/font_template.rs | 0 src/components/gfx/platform/linux/font.rs | 296 ------------------ .../gfx/platform/linux/font_context.rs | 82 ----- src/components/gfx/platform/mod.rs | 20 +- 9 files changed, 14 insertions(+), 530 deletions(-) delete mode 100644 src/components/gfx/platform/android/font_list.rs delete mode 100644 src/components/gfx/platform/android/font_template.rs rename src/components/gfx/platform/{android => freetype}/font.rs (100%) rename src/components/gfx/platform/{android => freetype}/font_context.rs (100%) rename src/components/gfx/platform/{linux => freetype}/font_list.rs (96%) rename src/components/gfx/platform/{linux => freetype}/font_template.rs (100%) delete mode 100644 src/components/gfx/platform/linux/font.rs delete mode 100644 src/components/gfx/platform/linux/font_context.rs diff --git a/src/components/gfx/platform/android/font_list.rs b/src/components/gfx/platform/android/font_list.rs deleted file mode 100644 index 79e1dadcb6b..00000000000 --- a/src/components/gfx/platform/android/font_list.rs +++ /dev/null @@ -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 { - vec!("Roboto".to_string()) -} diff --git a/src/components/gfx/platform/android/font_template.rs b/src/components/gfx/platform/android/font_template.rs deleted file mode 100644 index e8c058ee9ac..00000000000 --- a/src/components/gfx/platform/android/font_template.rs +++ /dev/null @@ -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, - pub identifier: String, -} - -impl FontTemplateData { - pub fn new(identifier: &str, font_data: Option>) -> 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(), - } - } -} diff --git a/src/components/gfx/platform/android/font.rs b/src/components/gfx/platform/freetype/font.rs similarity index 100% rename from src/components/gfx/platform/android/font.rs rename to src/components/gfx/platform/freetype/font.rs diff --git a/src/components/gfx/platform/android/font_context.rs b/src/components/gfx/platform/freetype/font_context.rs similarity index 100% rename from src/components/gfx/platform/android/font_context.rs rename to src/components/gfx/platform/freetype/font_context.rs diff --git a/src/components/gfx/platform/linux/font_list.rs b/src/components/gfx/platform/freetype/font_list.rs similarity index 96% rename from src/components/gfx/platform/linux/font_list.rs rename to src/components/gfx/platform/freetype/font_list.rs index 223bf175bdf..afb9e555a43 100644 --- a/src/components/gfx/platform/linux/font_list.rs +++ b/src/components/gfx/platform/freetype/font_list.rs @@ -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 { vec!( "Fira Sans".to_string(), @@ -107,3 +108,8 @@ pub fn get_last_resort_font_families() -> Vec { "Arial".to_string() ) } + +#[cfg(target_os="android")] +pub fn get_last_resort_font_families() -> Vec { + vec!("Roboto".to_string()) +} diff --git a/src/components/gfx/platform/linux/font_template.rs b/src/components/gfx/platform/freetype/font_template.rs similarity index 100% rename from src/components/gfx/platform/linux/font_template.rs rename to src/components/gfx/platform/freetype/font_template.rs diff --git a/src/components/gfx/platform/linux/font.rs b/src/components/gfx/platform/linux/font.rs deleted file mode 100644 index 704dd9c8aa0..00000000000 --- a/src/components/gfx/platform/linux/font.rs +++ /dev/null @@ -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, - 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, - pt_size: Option) - -> Result { - 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) - -> Result { - 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 { - 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 { - 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 { - 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 { - 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); - } -} - diff --git a/src/components/gfx/platform/linux/font_context.rs b/src/components/gfx/platform/linux/font_context.rs deleted file mode 100644 index b6e8222dc61..00000000000 --- a/src/components/gfx/platform/linux/font_context.rs +++ /dev/null @@ -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, -} - -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::() 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 }), - } - } - } -} diff --git a/src/components/gfx/platform/mod.rs b/src/components/gfx/platform/mod.rs index eada62fc637..ded6f3888e8 100644 --- a/src/components/gfx/platform/mod.rs +++ b/src/components/gfx/platform/mod.rs @@ -2,12 +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, 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")] +#[cfg(target_os="android")] +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")] -pub mod linux { +#[cfg(target_os="android")] +pub mod freetype { pub mod font; pub mod font_context; pub mod font_list; @@ -21,11 +25,3 @@ pub mod macos { pub mod font_list; 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; -}