mirror of
https://github.com/servo/servo.git
synced 2025-08-02 04:00:32 +01:00
Cargoify servo
This commit is contained in:
parent
db2f642c32
commit
c6ab60dbfc
1761 changed files with 8423 additions and 2294 deletions
297
components/gfx/platform/freetype/font.rs
Normal file
297
components/gfx/platform/freetype/font.rs
Normal file
|
@ -0,0 +1,297 @@
|
|||
/* 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::string;
|
||||
|
||||
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 { string::raw::from_buf(&*(*self.face).family_name as *const i8 as *const u8) }
|
||||
}
|
||||
fn face_name(&self) -> String {
|
||||
unsafe { string::raw::from_buf(&*FT_Get_Postscript_Name(self.face) as *const i8 as *const u8) }
|
||||
}
|
||||
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,
|
||||
line_gap: height,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
82
components/gfx/platform/freetype/font_context.rs
Normal file
82
components/gfx/platform/freetype/font_context.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
/* 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 }),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
115
components/gfx/platform/freetype/font_list.rs
Normal file
115
components/gfx/platform/freetype/font_list.rs
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![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;
|
||||
use std::ptr;
|
||||
use std::string;
|
||||
|
||||
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 = string::raw::from_buf(family as *const i8 as *const u8);
|
||||
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 {
|
||||
string::raw::from_buf(file as *const i8 as *const u8)
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os="linux")]
|
||||
pub fn get_last_resort_font_families() -> Vec<String> {
|
||||
vec!(
|
||||
"Fira Sans".to_string(),
|
||||
"DejaVu Sans".to_string(),
|
||||
"Arial".to_string()
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os="android")]
|
||||
pub fn get_last_resort_font_families() -> Vec<String> {
|
||||
vec!("Roboto".to_string())
|
||||
}
|
35
components/gfx/platform/freetype/font_template.rs
Normal file
35
components/gfx/platform/freetype/font_template.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::io;
|
||||
use std::io::File;
|
||||
|
||||
/// Platform specific font representation for Linux.
|
||||
/// The identifier is an absolute path, and the bytes
|
||||
/// field is the loaded data that can be passed to
|
||||
/// freetype and azure directly.
|
||||
pub struct FontTemplateData {
|
||||
pub bytes: Vec<u8>,
|
||||
pub identifier: String,
|
||||
}
|
||||
|
||||
impl FontTemplateData {
|
||||
pub fn new(identifier: &str, 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(),
|
||||
}
|
||||
}
|
||||
}
|
185
components/gfx/platform/macos/font.rs
Normal file
185
components/gfx/platform/macos/font.rs
Normal file
|
@ -0,0 +1,185 @@
|
|||
/* 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/. */
|
||||
|
||||
/// Implementation of Quartz (CoreGraphics) fonts.
|
||||
|
||||
extern crate core_foundation;
|
||||
extern crate core_graphics;
|
||||
extern crate core_text;
|
||||
|
||||
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
|
||||
use font::FontTableTag;
|
||||
use font::FractionalPixel;
|
||||
use servo_util::geometry::{Au, px_to_pt};
|
||||
use servo_util::geometry;
|
||||
use platform::macos::font_context::FontContextHandle;
|
||||
use text::glyph::GlyphId;
|
||||
use style::computed_values::font_weight;
|
||||
use platform::font_template::FontTemplateData;
|
||||
|
||||
use core_foundation::base::CFIndex;
|
||||
use core_foundation::data::CFData;
|
||||
use core_foundation::string::UniChar;
|
||||
use core_graphics::font::CGGlyph;
|
||||
use core_graphics::geometry::CGRect;
|
||||
use core_text::font::CTFont;
|
||||
use core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
|
||||
use core_text::font_descriptor::{kCTFontDefaultOrientation};
|
||||
|
||||
use std::ptr;
|
||||
use sync::Arc;
|
||||
|
||||
pub struct FontTable {
|
||||
data: CFData,
|
||||
}
|
||||
|
||||
// Noncopyable.
|
||||
impl Drop for FontTable {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl FontTable {
|
||||
pub fn wrap(data: CFData) -> FontTable {
|
||||
FontTable { data: data }
|
||||
}
|
||||
}
|
||||
|
||||
impl FontTableMethods for FontTable {
|
||||
fn with_buffer(&self, blk: |*const u8, uint|) {
|
||||
blk(self.data.bytes().as_ptr(), self.data.len() as uint);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FontHandle {
|
||||
pub font_data: Arc<FontTemplateData>,
|
||||
pub ctfont: CTFont,
|
||||
}
|
||||
|
||||
impl FontHandleMethods for FontHandle {
|
||||
fn new_from_template(_fctx: &FontContextHandle,
|
||||
template: Arc<FontTemplateData>,
|
||||
pt_size: Option<f64>)
|
||||
-> Result<FontHandle, ()> {
|
||||
let size = match pt_size {
|
||||
Some(s) => s,
|
||||
None => 0.0
|
||||
};
|
||||
match template.ctfont {
|
||||
Some(ref ctfont) => {
|
||||
Ok(FontHandle {
|
||||
font_data: template.clone(),
|
||||
ctfont: ctfont.clone_with_font_size(size),
|
||||
})
|
||||
}
|
||||
None => {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_template(&self) -> Arc<FontTemplateData> {
|
||||
self.font_data.clone()
|
||||
}
|
||||
|
||||
fn family_name(&self) -> String {
|
||||
self.ctfont.family_name()
|
||||
}
|
||||
|
||||
fn face_name(&self) -> String {
|
||||
self.ctfont.face_name()
|
||||
}
|
||||
|
||||
fn is_italic(&self) -> bool {
|
||||
self.ctfont.symbolic_traits().is_italic()
|
||||
}
|
||||
|
||||
fn boldness(&self) -> font_weight::T {
|
||||
// -1.0 to 1.0
|
||||
let normalized = self.ctfont.all_traits().normalized_weight();
|
||||
// 0.0 to 9.0
|
||||
let normalized = (normalized + 1.0) / 2.0 * 9.0;
|
||||
if normalized < 1.0 { return font_weight::Weight100; }
|
||||
if normalized < 2.0 { return font_weight::Weight200; }
|
||||
if normalized < 3.0 { return font_weight::Weight300; }
|
||||
if normalized < 4.0 { return font_weight::Weight400; }
|
||||
if normalized < 5.0 { return font_weight::Weight500; }
|
||||
if normalized < 6.0 { return font_weight::Weight600; }
|
||||
if normalized < 7.0 { return font_weight::Weight700; }
|
||||
if normalized < 8.0 { return font_weight::Weight800; }
|
||||
return font_weight::Weight900;
|
||||
}
|
||||
|
||||
fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
|
||||
let characters: [UniChar, ..1] = [codepoint as UniChar];
|
||||
let mut glyphs: [CGGlyph, ..1] = [0 as CGGlyph];
|
||||
let count: CFIndex = 1;
|
||||
|
||||
let result = self.ctfont.get_glyphs_for_characters(&characters[0],
|
||||
&mut glyphs[0],
|
||||
count);
|
||||
|
||||
if !result {
|
||||
// No glyph for this character
|
||||
return None;
|
||||
}
|
||||
|
||||
assert!(glyphs[0] != 0); // FIXME: error handling
|
||||
return Some(glyphs[0] as GlyphId);
|
||||
}
|
||||
|
||||
fn glyph_h_kerning(&self, _first_glyph: GlyphId, _second_glyph: GlyphId)
|
||||
-> FractionalPixel {
|
||||
// TODO: Implement on mac
|
||||
0.0
|
||||
}
|
||||
|
||||
fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
|
||||
let glyphs = [glyph as CGGlyph];
|
||||
let advance = self.ctfont.get_advances_for_glyphs(kCTFontDefaultOrientation,
|
||||
&glyphs[0],
|
||||
ptr::mut_null(),
|
||||
1);
|
||||
Some(advance as FractionalPixel)
|
||||
}
|
||||
|
||||
fn get_metrics(&self) -> FontMetrics {
|
||||
let bounding_rect: CGRect = self.ctfont.bounding_box();
|
||||
let ascent = self.ctfont.ascent() as f64;
|
||||
let descent = self.ctfont.descent() as f64;
|
||||
let em_size = Au::from_frac_px(self.ctfont.pt_size() as f64);
|
||||
let leading = self.ctfont.leading() as f64;
|
||||
|
||||
let scale = px_to_pt(self.ctfont.pt_size() as f64) / (ascent + descent);
|
||||
let line_gap = (ascent + descent + leading + 0.5).floor();
|
||||
|
||||
let metrics = FontMetrics {
|
||||
underline_size: Au::from_pt(self.ctfont.underline_thickness() as f64),
|
||||
// TODO(Issue #201): underline metrics are not reliable. Have to pull out of font table
|
||||
// directly.
|
||||
//
|
||||
// see also: https://bugs.webkit.org/show_bug.cgi?id=16768
|
||||
// see also: https://bugreports.qt-project.org/browse/QTBUG-13364
|
||||
underline_offset: Au::from_pt(self.ctfont.underline_position() as f64),
|
||||
strikeout_size: geometry::from_pt(0.0), // FIXME(Issue #942)
|
||||
strikeout_offset: geometry::from_pt(0.0), // FIXME(Issue #942)
|
||||
leading: Au::from_pt(leading),
|
||||
x_height: Au::from_pt(self.ctfont.x_height() as f64),
|
||||
em_size: em_size,
|
||||
ascent: Au::from_pt(ascent * scale),
|
||||
descent: Au::from_pt(descent * scale),
|
||||
max_advance: Au::from_pt(bounding_rect.size.width as f64),
|
||||
line_gap: Au::from_frac_px(line_gap),
|
||||
};
|
||||
debug!("Font metrics (@{:f} pt): {:?}", self.ctfont.pt_size() as f64, metrics);
|
||||
return metrics;
|
||||
}
|
||||
|
||||
fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
||||
let result: Option<CFData> = self.ctfont.get_font_table(tag);
|
||||
result.and_then(|data| {
|
||||
Some(FontTable::wrap(data))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
16
components/gfx/platform/macos/font_context.rs
Normal file
16
components/gfx/platform/macos/font_context.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* 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/. */
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct FontContextHandle {
|
||||
ctx: ()
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
impl FontContextHandle {
|
||||
// this is a placeholder until NSFontManager or whatever is bound in here.
|
||||
pub fn new() -> FontContextHandle {
|
||||
FontContextHandle { ctx: () }
|
||||
}
|
||||
}
|
37
components/gfx/platform/macos/font_list.rs
Normal file
37
components/gfx/platform/macos/font_list.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use core_foundation::base::TCFType;
|
||||
use core_foundation::string::{CFString, CFStringRef};
|
||||
use core_text::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef};
|
||||
use core_text;
|
||||
use std::mem;
|
||||
|
||||
pub fn get_available_families(callback: |String|) {
|
||||
let family_names = core_text::font_collection::get_family_names();
|
||||
for strref in family_names.iter() {
|
||||
let family_name_ref: CFStringRef = unsafe { mem::transmute(strref) };
|
||||
let family_name_cf: CFString = unsafe { TCFType::wrap_under_get_rule(family_name_ref) };
|
||||
let family_name = family_name_cf.to_string();
|
||||
callback(family_name);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_variations_for_family(family_name: &str, callback: |String|) {
|
||||
debug!("Looking for faces of family: {:s}", family_name);
|
||||
|
||||
let family_collection =
|
||||
core_text::font_collection::create_for_family(family_name.as_slice());
|
||||
let family_descriptors = family_collection.get_descriptors();
|
||||
for descref in family_descriptors.iter() {
|
||||
let descref: CTFontDescriptorRef = unsafe { mem::transmute(descref) };
|
||||
let desc: CTFontDescriptor = unsafe { TCFType::wrap_under_get_rule(descref) };
|
||||
let postscript_name = desc.font_name();
|
||||
callback(postscript_name);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_last_resort_font_families() -> Vec<String> {
|
||||
vec!("Arial Unicode MS".to_string(), "Arial".to_string())
|
||||
}
|
40
components/gfx/platform/macos/font_template.rs
Normal file
40
components/gfx/platform/macos/font_template.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use core_graphics::data_provider::CGDataProvider;
|
||||
use core_graphics::font::CGFont;
|
||||
use core_text::font::CTFont;
|
||||
use core_text;
|
||||
|
||||
/// Platform specific font representation for mac.
|
||||
/// The identifier is a PostScript font name. The
|
||||
/// CTFont object is cached here for use by the
|
||||
/// render functions that create CGFont references.
|
||||
pub struct FontTemplateData {
|
||||
pub ctfont: Option<CTFont>,
|
||||
pub identifier: String,
|
||||
}
|
||||
|
||||
impl FontTemplateData {
|
||||
pub fn new(identifier: &str, font_data: Option<Vec<u8>>) -> FontTemplateData {
|
||||
let ctfont = match font_data {
|
||||
Some(bytes) => {
|
||||
let fontprov = CGDataProvider::from_buffer(bytes.as_slice());
|
||||
let cgfont_result = CGFont::from_data_provider(fontprov);
|
||||
match cgfont_result {
|
||||
Ok(cgfont) => Some(core_text::font::new_from_CGFont(&cgfont, 0.0)),
|
||||
Err(_) => None
|
||||
}
|
||||
},
|
||||
None => {
|
||||
Some(core_text::font::new_from_name(identifier.as_slice(), 0.0).unwrap())
|
||||
}
|
||||
};
|
||||
|
||||
FontTemplateData {
|
||||
ctfont: ctfont,
|
||||
identifier: identifier.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
27
components/gfx/platform/mod.rs
Normal file
27
components/gfx/platform/mod.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* 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/. */
|
||||
|
||||
#[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")]
|
||||
#[cfg(target_os="android")]
|
||||
pub mod freetype {
|
||||
pub mod font;
|
||||
pub mod font_context;
|
||||
pub mod font_list;
|
||||
pub mod font_template;
|
||||
}
|
||||
|
||||
#[cfg(target_os="macos")]
|
||||
pub mod macos {
|
||||
pub mod font;
|
||||
pub mod font_context;
|
||||
pub mod font_list;
|
||||
pub mod font_template;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue