mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
add some android port materials into gfx
This commit is contained in:
parent
6cfc3a8546
commit
0fd7c651cb
6 changed files with 607 additions and 3 deletions
|
@ -353,6 +353,7 @@ impl Font {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os="linux")]
|
#[cfg(target_os="linux")]
|
||||||
|
#[cfg(target_os="android")]
|
||||||
fn create_azure_font(&self) -> ScaledFont {
|
fn create_azure_font(&self) -> ScaledFont {
|
||||||
let freetype_font = self.handle.face;
|
let freetype_font = self.handle.face;
|
||||||
let size = self.style.pt_size as AzFloat;
|
let size = self.style.pt_size as AzFloat;
|
||||||
|
|
|
@ -20,9 +20,9 @@ extern mod servo_msg (name = "msg");
|
||||||
// shapers. For now, however, this is a hard dependency.
|
// shapers. For now, however, this is a hard dependency.
|
||||||
extern mod harfbuzz;
|
extern mod harfbuzz;
|
||||||
|
|
||||||
// Linux-specific library dependencies
|
// Linux and Android-specific library dependencies
|
||||||
#[cfg(target_os="linux")] extern mod fontconfig;
|
#[cfg(target_os="linux")] #[cfg(target_os="android")] extern mod fontconfig;
|
||||||
#[cfg(target_os="linux")] extern mod freetype;
|
#[cfg(target_os="linux")] #[cfg(target_os="android")] extern mod freetype;
|
||||||
|
|
||||||
// Mac OS-specific library dependencies
|
// Mac OS-specific library dependencies
|
||||||
#[cfg(target_os="macos")] extern mod core_foundation;
|
#[cfg(target_os="macos")] extern mod core_foundation;
|
||||||
|
|
331
src/components/gfx/platform/android/font.rs
Normal file
331
src/components/gfx/platform/android/font.rs
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
/* 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 mod freetype;
|
||||||
|
|
||||||
|
use font::{CSSFontWeight, FontHandleMethods, FontMetrics, FontTableMethods};
|
||||||
|
use font::{FontTableTag, FractionalPixel, SpecifiedFontStyle, UsedFontStyle, FontWeight100};
|
||||||
|
use font::{FontWeight200, FontWeight300, FontWeight400, FontWeight500, FontWeight600};
|
||||||
|
use font::{FontWeight700, FontWeight800, FontWeight900};
|
||||||
|
use geometry::Au;
|
||||||
|
use geometry;
|
||||||
|
use platform::font_context::FontContextHandle;
|
||||||
|
use text::glyph::GlyphIndex;
|
||||||
|
use text::util::{float_to_fixed, fixed_to_float};
|
||||||
|
|
||||||
|
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_New_Face, 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_STYLE_FLAG_ITALIC, FT_STYLE_FLAG_BOLD};
|
||||||
|
use freetype::freetype::{FT_SizeRec, FT_UInt, FT_Size_Metrics};
|
||||||
|
use freetype::freetype::{ft_sfnt_os2};
|
||||||
|
use freetype::tt_os2::TT_OS2;
|
||||||
|
|
||||||
|
use std::cast;
|
||||||
|
use std::ptr;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
fn float_to_fixed_ft(f: float) -> i32 {
|
||||||
|
float_to_fixed(6, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fixed_to_float_ft(f: i32) -> float {
|
||||||
|
fixed_to_float(6, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FontTable {
|
||||||
|
bogus: ()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FontTableMethods for FontTable {
|
||||||
|
fn with_buffer(&self, _blk: &fn(*u8, uint)) {
|
||||||
|
fail!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum FontSource {
|
||||||
|
FontSourceMem(~[u8]),
|
||||||
|
FontSourceFile(~str)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
source: FontSource,
|
||||||
|
face: FT_Face,
|
||||||
|
handle: FontContextHandle
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe_destructor]
|
||||||
|
impl Drop for FontHandle {
|
||||||
|
fn drop(&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_buffer(fctx: &FontContextHandle,
|
||||||
|
buf: ~[u8],
|
||||||
|
style: &SpecifiedFontStyle)
|
||||||
|
-> Result<FontHandle, ()> {
|
||||||
|
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
||||||
|
if ft_ctx.is_null() { return Err(()); }
|
||||||
|
|
||||||
|
let face_result = do buf.as_imm_buf |bytes: *u8, len: uint| {
|
||||||
|
create_face_from_buffer(ft_ctx, bytes, len, style.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,
|
||||||
|
source: FontSourceMem(buf),
|
||||||
|
handle: *fctx
|
||||||
|
};
|
||||||
|
Ok(handle)
|
||||||
|
}
|
||||||
|
Err(()) => Err(())
|
||||||
|
};
|
||||||
|
|
||||||
|
fn create_face_from_buffer(lib: FT_Library,
|
||||||
|
cbuf: *u8, cbuflen: uint, pt_size: float)
|
||||||
|
-> Result<FT_Face, ()> {
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let mut face: FT_Face = ptr::null();
|
||||||
|
let face_index = 0 as FT_Long;
|
||||||
|
let result = FT_New_Memory_Face(lib, cbuf, cbuflen as FT_Long,
|
||||||
|
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
||||||
|
|
||||||
|
if !result.succeeded() || face.is_null() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
if FontHandle::set_char_size(face, pt_size).is_ok() {
|
||||||
|
Ok(face)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// an identifier usable by FontContextHandle to recreate this FontHandle.
|
||||||
|
fn face_identifier(&self) -> ~str {
|
||||||
|
/* FT_Get_Postscript_Name seems like a better choice here, but it
|
||||||
|
doesn't give usable results for fontconfig when deserializing. */
|
||||||
|
unsafe { str::raw::from_c_str((*self.face).family_name) }
|
||||||
|
}
|
||||||
|
fn family_name(&self) -> ~str {
|
||||||
|
unsafe { str::raw::from_c_str((*self.face).family_name) }
|
||||||
|
}
|
||||||
|
fn face_name(&self) -> ~str {
|
||||||
|
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) -> CSSFontWeight {
|
||||||
|
let default_weight = FontWeight400;
|
||||||
|
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 *TT_OS2;
|
||||||
|
let valid = os2.is_not_null() && (*os2).version != 0xffff;
|
||||||
|
if valid {
|
||||||
|
let weight =(*os2).usWeightClass;
|
||||||
|
match weight {
|
||||||
|
1 | 100..199 => FontWeight100,
|
||||||
|
2 | 200..299 => FontWeight200,
|
||||||
|
3 | 300..399 => FontWeight300,
|
||||||
|
4 | 400..499 => FontWeight400,
|
||||||
|
5 | 500..599 => FontWeight500,
|
||||||
|
6 | 600..699 => FontWeight600,
|
||||||
|
7 | 700..799 => FontWeight700,
|
||||||
|
8 | 800..899 => FontWeight800,
|
||||||
|
9 | 900..999 => FontWeight900,
|
||||||
|
_ => default_weight
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
default_weight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_with_style(&self,
|
||||||
|
fctx: &FontContextHandle,
|
||||||
|
style: &UsedFontStyle) -> Result<FontHandle, ()> {
|
||||||
|
match self.source {
|
||||||
|
FontSourceMem(ref buf) => {
|
||||||
|
FontHandleMethods::new_from_buffer(fctx, buf.clone(), style)
|
||||||
|
}
|
||||||
|
FontSourceFile(ref file) => {
|
||||||
|
FontHandle::new_from_file(fctx, (*file).clone(), style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn glyph_index(&self,
|
||||||
|
codepoint: char) -> Option<GlyphIndex> {
|
||||||
|
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 GlyphIndex)
|
||||||
|
} else {
|
||||||
|
debug!("Invalid codepoint: %?", codepoint);
|
||||||
|
None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn glyph_h_advance(&self,
|
||||||
|
glyph: GlyphIndex) -> 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 = cast::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 float);
|
||||||
|
let underline_offset = self.font_units_to_au(face.underline_position as float);
|
||||||
|
let em_size = self.font_units_to_au(face.units_per_EM as float);
|
||||||
|
let ascent = self.font_units_to_au(face.ascender as float);
|
||||||
|
let descent = self.font_units_to_au(face.descender as float);
|
||||||
|
let max_advance = self.font_units_to_au(face.max_advance_width as float);
|
||||||
|
|
||||||
|
return FontMetrics {
|
||||||
|
underline_size: underline_size,
|
||||||
|
underline_offset: underline_offset,
|
||||||
|
leading: geometry::from_pt(0.0), //FIXME
|
||||||
|
x_height: geometry::from_pt(0.0), //FIXME
|
||||||
|
em_size: em_size,
|
||||||
|
ascent: ascent,
|
||||||
|
descent: -descent, // linux font's seem to use the opposite sign from mac
|
||||||
|
max_advance: max_advance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_table_for_tag(&self, _: FontTableTag) -> Option<FontTable> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'self> FontHandle {
|
||||||
|
fn set_char_size(face: FT_Face, pt_size: float) -> 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(()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_from_file(fctx: &FontContextHandle, file: ~str,
|
||||||
|
style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
|
||||||
|
unsafe {
|
||||||
|
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
||||||
|
if ft_ctx.is_null() { return Err(()); }
|
||||||
|
|
||||||
|
let mut face: FT_Face = ptr::null();
|
||||||
|
let face_index = 0 as FT_Long;
|
||||||
|
do file.to_c_str().with_ref |file_str| {
|
||||||
|
FT_New_Face(ft_ctx, file_str,
|
||||||
|
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
||||||
|
}
|
||||||
|
if face.is_null() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
if FontHandle::set_char_size(face, style.pt_size).is_ok() {
|
||||||
|
Ok(FontHandle {
|
||||||
|
source: FontSourceFile(file),
|
||||||
|
face: face,
|
||||||
|
handle: *fctx
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
|
||||||
|
-> Result<FontHandle, ()> {
|
||||||
|
unsafe {
|
||||||
|
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
||||||
|
if ft_ctx.is_null() { return Err(()); }
|
||||||
|
|
||||||
|
let mut face: FT_Face = ptr::null();
|
||||||
|
let face_index = 0 as FT_Long;
|
||||||
|
do file.to_c_str().with_ref |file_str| {
|
||||||
|
FT_New_Face(ft_ctx, file_str,
|
||||||
|
face_index, ptr::to_mut_unsafe_ptr(&mut face));
|
||||||
|
}
|
||||||
|
if face.is_null() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(FontHandle {
|
||||||
|
source: FontSourceFile(file),
|
||||||
|
face: face,
|
||||||
|
handle: *fctx
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_face_rec(&'self self) -> &'self FT_FaceRec {
|
||||||
|
unsafe {
|
||||||
|
&(*self.face)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn font_units_to_au(&self, value: float) -> 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 { cast::transmute(&(*face.size)) };
|
||||||
|
let metrics: &FT_Size_Metrics = &(*size).metrics;
|
||||||
|
|
||||||
|
let em_size = face.units_per_EM as float;
|
||||||
|
let x_scale = (metrics.x_ppem as float) / em_size as float;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
60
src/components/gfx/platform/android/font_context.rs
Normal file
60
src/components/gfx/platform/android/font_context.rs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/* 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 font::UsedFontStyle;
|
||||||
|
use platform::font::FontHandle;
|
||||||
|
use font_context::FontContextHandleMethods;
|
||||||
|
use platform::font_list::path_from_identifier;
|
||||||
|
|
||||||
|
use freetype::freetype::{FTErrorMethods, FT_Library};
|
||||||
|
use freetype::freetype::{FT_Done_FreeType, FT_Init_FreeType};
|
||||||
|
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
struct FreeTypeLibraryHandle {
|
||||||
|
ctx: FT_Library,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for FreeTypeLibraryHandle {
|
||||||
|
fn drop(&self) {
|
||||||
|
assert!(self.ctx.is_not_null());
|
||||||
|
unsafe {
|
||||||
|
FT_Done_FreeType(self.ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FontContextHandle {
|
||||||
|
ctx: @FreeTypeLibraryHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FontContextHandle {
|
||||||
|
pub fn new() -> FontContextHandle {
|
||||||
|
unsafe {
|
||||||
|
let ctx: FT_Library = ptr::null();
|
||||||
|
let result = FT_Init_FreeType(ptr::to_unsafe_ptr(&ctx));
|
||||||
|
if !result.succeeded() { fail!(); }
|
||||||
|
|
||||||
|
FontContextHandle {
|
||||||
|
ctx: @FreeTypeLibraryHandle { ctx: ctx },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FontContextHandleMethods for FontContextHandle {
|
||||||
|
fn clone(&self) -> FontContextHandle {
|
||||||
|
FontContextHandle { ctx: self.ctx }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle)
|
||||||
|
-> Result<FontHandle, ()> {
|
||||||
|
debug!("Creating font handle for %s", name);
|
||||||
|
do path_from_identifier(name, &style).chain |file_name| {
|
||||||
|
debug!("Opening font face %s", file_name);
|
||||||
|
FontHandle::new_from_file(self, file_name, &style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
205
src/components/gfx/platform/android/font_list.rs
Normal file
205
src/components/gfx/platform/android/font_list.rs
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
/* 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 mod freetype;
|
||||||
|
extern mod fontconfig;
|
||||||
|
|
||||||
|
use fontconfig::fontconfig::{
|
||||||
|
FcChar8, FcResultMatch, FcSetSystem, FcPattern,
|
||||||
|
FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD
|
||||||
|
};
|
||||||
|
use fontconfig::fontconfig::{
|
||||||
|
FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
|
||||||
|
FcPatternDestroy, FcFontSetDestroy, FcConfigSubstitute,
|
||||||
|
FcDefaultSubstitute, FcPatternCreate, FcPatternAddString, FcPatternAddInteger,
|
||||||
|
FcFontMatch, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
|
||||||
|
FcObjectSetAdd, FcPatternGetInteger
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
use font::{FontHandleMethods, UsedFontStyle};
|
||||||
|
use font_context::FontContextHandleMethods;
|
||||||
|
use font_list::{FontEntry, FontFamily, FontFamilyMap};
|
||||||
|
use platform::font::FontHandle;
|
||||||
|
use platform::font_context::FontContextHandle;
|
||||||
|
|
||||||
|
use std::hashmap::HashMap;
|
||||||
|
use std::libc;
|
||||||
|
use std::libc::{c_int, c_char};
|
||||||
|
use std::ptr;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
pub struct FontListHandle {
|
||||||
|
fctx: FontContextHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FontListHandle {
|
||||||
|
pub fn new(fctx: &FontContextHandle) -> FontListHandle {
|
||||||
|
FontListHandle { fctx: fctx.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_available_families(&self) -> FontFamilyMap {
|
||||||
|
let mut family_map : FontFamilyMap = HashMap::new();
|
||||||
|
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 family: *FcChar8 = ptr::null();
|
||||||
|
let mut v: c_int = 0;
|
||||||
|
do "family".to_c_str().with_ref |FC_FAMILY| {
|
||||||
|
while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
|
||||||
|
let family_name = str::raw::from_c_str(family as *c_char);
|
||||||
|
debug!("Creating new FontFamily for family: %s", family_name);
|
||||||
|
let new_family = @mut FontFamily::new(family_name);
|
||||||
|
family_map.insert(family_name, new_family);
|
||||||
|
v += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return family_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_variations_for_family(&self, family: @mut FontFamily) {
|
||||||
|
debug!("getting variations for %?", family);
|
||||||
|
unsafe {
|
||||||
|
let config = FcConfigGetCurrent();
|
||||||
|
let font_set = FcConfigGetFonts(config, FcSetSystem);
|
||||||
|
let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set);
|
||||||
|
let pattern = FcPatternCreate();
|
||||||
|
assert!(pattern.is_not_null());
|
||||||
|
do "family".to_c_str().with_ref |FC_FAMILY| {
|
||||||
|
do family.family_name.to_c_str().with_ref |family_name| {
|
||||||
|
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
|
||||||
|
assert!(ok != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let object_set = FcObjectSetCreate();
|
||||||
|
assert!(object_set.is_not_null());
|
||||||
|
|
||||||
|
do "file".to_c_str().with_ref |FC_FILE| {
|
||||||
|
FcObjectSetAdd(object_set, FC_FILE);
|
||||||
|
}
|
||||||
|
do "index".to_c_str().with_ref |FC_INDEX| {
|
||||||
|
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 file = do "file".to_c_str().with_ref |FC_FILE| {
|
||||||
|
let file: *FcChar8 = ptr::null();
|
||||||
|
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
|
||||||
|
str::raw::from_c_str(file as *libc::c_char)
|
||||||
|
} else {
|
||||||
|
fail!();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let index = do "index".to_c_str().with_ref |FC_INDEX| {
|
||||||
|
let index: libc::c_int = 0;
|
||||||
|
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
|
||||||
|
index
|
||||||
|
} else {
|
||||||
|
fail!();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("variation file: %?", file);
|
||||||
|
debug!("variation index: %?", index);
|
||||||
|
|
||||||
|
let font_handle = FontHandle::new_from_file_unstyled(&self.fctx,
|
||||||
|
file);
|
||||||
|
let font_handle = font_handle.unwrap();
|
||||||
|
|
||||||
|
debug!("Creating new FontEntry for face: %s", font_handle.face_name());
|
||||||
|
let entry = @FontEntry::new(font_handle);
|
||||||
|
family.entries.push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
FcFontSetDestroy(matches);
|
||||||
|
FcPatternDestroy(pattern);
|
||||||
|
FcObjectSetDestroy(object_set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_last_resort_font_families() -> ~[~str] {
|
||||||
|
~[~"Roboto"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AutoPattern {
|
||||||
|
pattern: *FcPattern
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for AutoPattern {
|
||||||
|
fn drop(&self) {
|
||||||
|
unsafe {
|
||||||
|
FcPatternDestroy(self.pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
|
||||||
|
unsafe {
|
||||||
|
let config = FcConfigGetCurrent();
|
||||||
|
let wrapper = AutoPattern { pattern: FcPatternCreate() };
|
||||||
|
let pattern = wrapper.pattern;
|
||||||
|
let res = do "family".to_c_str().with_ref |FC_FAMILY| {
|
||||||
|
do name.to_c_str().with_ref |family| {
|
||||||
|
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if res != 1 {
|
||||||
|
debug!("adding family to pattern failed");
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if style.italic {
|
||||||
|
let res = do "slant".to_c_str().with_ref |FC_SLANT| {
|
||||||
|
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
|
||||||
|
};
|
||||||
|
if res != 1 {
|
||||||
|
debug!("adding slant to pattern failed");
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if style.weight.is_bold() {
|
||||||
|
let res = do "weight".to_c_str().with_ref |FC_WEIGHT| {
|
||||||
|
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
|
||||||
|
};
|
||||||
|
if res != 1 {
|
||||||
|
debug!("adding weight to pattern failed");
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if FcConfigSubstitute(config, pattern, FcMatchPattern) != 1 {
|
||||||
|
debug!("substitution failed");
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
FcDefaultSubstitute(pattern);
|
||||||
|
let result = FcResultNoMatch;
|
||||||
|
let result_wrapper = AutoPattern { pattern: FcFontMatch(config, pattern, &result) };
|
||||||
|
let result_pattern = result_wrapper.pattern;
|
||||||
|
if result != FcResultMatch && result_pattern.is_null() {
|
||||||
|
debug!("obtaining match to pattern failed");
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let file: *FcChar8 = ptr::null();
|
||||||
|
let res = do "file".to_c_str().with_ref |FC_FILE| {
|
||||||
|
FcPatternGetString(result_pattern, FC_FILE, 0, &file)
|
||||||
|
};
|
||||||
|
if res != FcResultMatch {
|
||||||
|
debug!("getting filename for font failed");
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
Ok(str::raw::from_c_str(file as *c_char))
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#[cfg(target_os="linux")] pub use platform::linux::{font, font_context, font_list};
|
#[cfg(target_os="linux")] pub use platform::linux::{font, font_context, font_list};
|
||||||
#[cfg(target_os="macos")] pub use platform::macos::{font, font_context, font_list};
|
#[cfg(target_os="macos")] pub use platform::macos::{font, font_context, font_list};
|
||||||
|
#[cfg(target_os="android")] pub use platform::android::{font, font_context, font_list};
|
||||||
|
|
||||||
#[cfg(target_os="linux")]
|
#[cfg(target_os="linux")]
|
||||||
pub mod linux {
|
pub mod linux {
|
||||||
|
@ -19,3 +20,9 @@ pub mod macos {
|
||||||
pub mod font_list;
|
pub mod font_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os="android")]
|
||||||
|
pub mod android {
|
||||||
|
pub mod font;
|
||||||
|
pub mod font_context;
|
||||||
|
pub mod font_list;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue