aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/components/gfx/font.rs1
-rw-r--r--src/components/gfx/gfx.rc6
-rw-r--r--src/components/gfx/platform/android/font.rs331
-rw-r--r--src/components/gfx/platform/android/font_context.rs60
-rw-r--r--src/components/gfx/platform/android/font_list.rs205
-rw-r--r--src/components/gfx/platform/mod.rs7
6 files changed, 607 insertions, 3 deletions
diff --git a/src/components/gfx/font.rs b/src/components/gfx/font.rs
index c8b2680dbfb..99901cdc643 100644
--- a/src/components/gfx/font.rs
+++ b/src/components/gfx/font.rs
@@ -353,6 +353,7 @@ impl Font {
}
#[cfg(target_os="linux")]
+ #[cfg(target_os="android")]
fn create_azure_font(&self) -> ScaledFont {
let freetype_font = self.handle.face;
let size = self.style.pt_size as AzFloat;
diff --git a/src/components/gfx/gfx.rc b/src/components/gfx/gfx.rc
index 98cdee6232a..eddeb32e970 100644
--- a/src/components/gfx/gfx.rc
+++ b/src/components/gfx/gfx.rc
@@ -20,9 +20,9 @@ extern mod servo_msg (name = "msg");
// shapers. For now, however, this is a hard dependency.
extern mod harfbuzz;
-// Linux-specific library dependencies
-#[cfg(target_os="linux")] extern mod fontconfig;
-#[cfg(target_os="linux")] extern mod freetype;
+// Linux and Android-specific library dependencies
+#[cfg(target_os="linux")] #[cfg(target_os="android")] extern mod fontconfig;
+#[cfg(target_os="linux")] #[cfg(target_os="android")] extern mod freetype;
// Mac OS-specific library dependencies
#[cfg(target_os="macos")] extern mod core_foundation;
diff --git a/src/components/gfx/platform/android/font.rs b/src/components/gfx/platform/android/font.rs
new file mode 100644
index 00000000000..aff744cae2d
--- /dev/null
+++ b/src/components/gfx/platform/android/font.rs
@@ -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);
+ }
+}
+
diff --git a/src/components/gfx/platform/android/font_context.rs b/src/components/gfx/platform/android/font_context.rs
new file mode 100644
index 00000000000..5a828ee7438
--- /dev/null
+++ b/src/components/gfx/platform/android/font_context.rs
@@ -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)
+ }
+ }
+}
+
diff --git a/src/components/gfx/platform/android/font_list.rs b/src/components/gfx/platform/android/font_list.rs
new file mode 100644
index 00000000000..a598cebb316
--- /dev/null
+++ b/src/components/gfx/platform/android/font_list.rs
@@ -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))
+ }
+}
diff --git a/src/components/gfx/platform/mod.rs b/src/components/gfx/platform/mod.rs
index 2d8fb4f9ce7..34870cc2f2d 100644
--- a/src/components/gfx/platform/mod.rs
+++ b/src/components/gfx/platform/mod.rs
@@ -4,6 +4,7 @@
#[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="android")] pub use platform::android::{font, font_context, font_list};
#[cfg(target_os="linux")]
pub mod linux {
@@ -19,3 +20,9 @@ pub mod macos {
pub mod font_list;
}
+#[cfg(target_os="android")]
+pub mod android {
+ pub mod font;
+ pub mod font_context;
+ pub mod font_list;
+}