mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Restructure text module
This commit is contained in:
parent
2b29512ef5
commit
d7eb2ab8ac
7 changed files with 115 additions and 270 deletions
|
@ -6,6 +6,7 @@ import dl = layout::display_list;
|
|||
import azure::*;
|
||||
import azure::bindgen::*;
|
||||
import libc::size_t;
|
||||
import text::font::Font;
|
||||
import text::text_run::TextRun;
|
||||
import dom::event::{Event, ResizeEvent};
|
||||
import geom::size::Size2D;
|
||||
|
@ -14,6 +15,7 @@ import geom::point::Point2D;
|
|||
import azure_hl::AsAzureRect;
|
||||
import ptr::addr_of;
|
||||
import arc::arc;
|
||||
import azure::cairo::{cairo_font_face_t, cairo_scaled_font_t};
|
||||
|
||||
import pipes::{port, chan};
|
||||
|
||||
|
@ -177,6 +179,7 @@ fn draw_text(draw_target: AzDrawTargetRef, item: dl::display_item, text_run: Tex
|
|||
AzReleaseScaledFont,
|
||||
AzCreateColorPattern,
|
||||
AzReleaseColorPattern};
|
||||
import azure::cairo::bindgen::cairo_scaled_font_destroy;
|
||||
|
||||
let bounds = copy (*item).bounds;
|
||||
// FIXME: The font library should not be created here
|
||||
|
@ -188,8 +191,10 @@ fn draw_text(draw_target: AzDrawTargetRef, item: dl::display_item, text_run: Tex
|
|||
mFont: null()
|
||||
};
|
||||
|
||||
let azfont = AzCreateScaledFontWithCairo(addr_of(nfont), 1f as AzFloat, font.cairo_font);
|
||||
let cfont = get_cairo_font(font);
|
||||
let azfont = AzCreateScaledFontWithCairo(addr_of(nfont), 1f as AzFloat, cfont);
|
||||
assert azfont.is_not_null();
|
||||
cairo_scaled_font_destroy(cfont);
|
||||
|
||||
let color = {
|
||||
r: 0f as AzFloat,
|
||||
|
@ -231,6 +236,66 @@ fn draw_text(draw_target: AzDrawTargetRef, item: dl::display_item, text_run: Tex
|
|||
AzReleaseScaledFont(azfont);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_cairo_face(font: &Font) -> *cairo_font_face_t {
|
||||
|
||||
import libc::c_int;
|
||||
import azure::cairo_ft::bindgen::{cairo_ft_font_face_create_for_ft_face};
|
||||
|
||||
let ftface = font.native_font.face;
|
||||
let cface = cairo_ft_font_face_create_for_ft_face(ftface, 0 as c_int);
|
||||
// FIXME: error handling
|
||||
return cface;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn get_cairo_face(font: &Font) -> *cairo_font_face_t {
|
||||
import azure::cairo_quartz::bindgen::cairo_quartz_font_face_create_for_cgfont;
|
||||
|
||||
let cgfont = font.native_font.cgfont;
|
||||
let face = cairo_quartz_font_face_create_for_cgfont(cgfont);
|
||||
// FIXME: error handling
|
||||
return face;
|
||||
}
|
||||
|
||||
fn get_cairo_font(font: &Font) -> *cairo_scaled_font_t {
|
||||
|
||||
import libc::c_double;
|
||||
import azure::cairo;
|
||||
import cairo::cairo_matrix_t;
|
||||
import cairo::bindgen::{cairo_matrix_init_identity,
|
||||
cairo_matrix_scale,
|
||||
cairo_font_options_create,
|
||||
cairo_scaled_font_create,
|
||||
cairo_font_options_destroy,
|
||||
cairo_font_face_destroy};
|
||||
|
||||
// FIXME: error handling
|
||||
|
||||
let face = get_cairo_face(font);
|
||||
|
||||
let idmatrix: cairo_matrix_t = {
|
||||
xx: 0 as c_double,
|
||||
yx: 0 as c_double,
|
||||
xy: 0 as c_double,
|
||||
yy: 0 as c_double,
|
||||
x0: 0 as c_double,
|
||||
y0: 0 as c_double
|
||||
};
|
||||
cairo_matrix_init_identity(addr_of(idmatrix));
|
||||
|
||||
let fontmatrix = idmatrix;
|
||||
cairo_matrix_scale(addr_of(fontmatrix),
|
||||
20f as c_double, 20f as c_double);
|
||||
let options = cairo_font_options_create();
|
||||
let cfont = cairo_scaled_font_create(face, addr_of(fontmatrix),
|
||||
addr_of(idmatrix), options);
|
||||
cairo_font_options_destroy(options);
|
||||
cairo_font_face_destroy(face);
|
||||
|
||||
return cfont;
|
||||
}
|
||||
|
||||
fn clear(draw_target: AzDrawTargetRef) {
|
||||
|
||||
let black_color = {
|
||||
|
|
|
@ -4,22 +4,7 @@ import glyph::GlyphIndex;
|
|||
import vec_to_ptr = vec::unsafe::to_ptr;
|
||||
import libc::{ c_int, c_double, c_ulong };
|
||||
import ptr::{ null, addr_of };
|
||||
import azure::cairo::{
|
||||
cairo_font_face_t,
|
||||
cairo_scaled_font_t,
|
||||
cairo_glyph_t,
|
||||
cairo_text_extents_t,
|
||||
CAIRO_STATUS_SUCCESS,
|
||||
};
|
||||
import azure::cairo::bindgen::{
|
||||
cairo_font_face_destroy,
|
||||
cairo_scaled_font_destroy,
|
||||
cairo_scaled_font_status,
|
||||
cairo_scaled_font_text_to_glyphs,
|
||||
cairo_scaled_font_glyph_extents,
|
||||
cairo_glyph_free,
|
||||
cairo_status_to_string
|
||||
};
|
||||
import native_font::NativeFont;
|
||||
|
||||
// FIXME (rust 2708): convert this to a class
|
||||
|
||||
|
@ -29,239 +14,29 @@ and the renderer can use it to render text.
|
|||
"]
|
||||
class Font {
|
||||
let fontbuf: @~[u8];
|
||||
let cairo_font: *cairo_scaled_font_t;
|
||||
let font_dtor: fn@();
|
||||
|
||||
new(-fontbuf: ~[u8]) {
|
||||
let (cairo_font, font_dtor) = get_cairo_font(© fontbuf);
|
||||
assert cairo_font.is_not_null();
|
||||
let native_font: NativeFont;
|
||||
|
||||
new(-fontbuf: ~[u8], -native_font: NativeFont) {
|
||||
self.fontbuf = @fontbuf;
|
||||
self.cairo_font = cairo_font;
|
||||
self.font_dtor = font_dtor;
|
||||
self.native_font = native_font;
|
||||
}
|
||||
|
||||
fn buf() -> @~[u8] {
|
||||
self.fontbuf
|
||||
}
|
||||
|
||||
fn glyph_idx(codepoint: char) -> option<GlyphIndex> {
|
||||
#debug("getting glyph for codepoint %u", codepoint as uint);
|
||||
let codepoint_str = str::from_char(codepoint);
|
||||
|
||||
let mut glyphs: *cairo_glyph_t = null();
|
||||
let mut num_glyphs = 0 as c_int;
|
||||
|
||||
let status = str::as_c_str(codepoint_str, |codepoint_buf| {
|
||||
cairo_scaled_font_text_to_glyphs(
|
||||
self.cairo_font,
|
||||
0.0 as c_double, 0.0 as c_double,
|
||||
codepoint_buf, codepoint_str.len() as c_int,
|
||||
addr_of(glyphs), addr_of(num_glyphs),
|
||||
null(), null(), null()
|
||||
)
|
||||
});
|
||||
|
||||
return if status == CAIRO_STATUS_SUCCESS {
|
||||
|
||||
// This might not be true, but at least we'll know if it isn't
|
||||
assert num_glyphs == 1 as c_int;
|
||||
|
||||
let glyph_index = unsafe { *glyphs }.index as GlyphIndex;
|
||||
#debug("glyph index is %?", glyph_index);
|
||||
cairo_glyph_free(glyphs);
|
||||
some(glyph_index)
|
||||
} else {
|
||||
#error("cairo did not give me a glyph for %u", codepoint as uint);
|
||||
none
|
||||
}
|
||||
fn glyph_index(codepoint: char) -> option<GlyphIndex> {
|
||||
self.native_font.glyph_index(codepoint)
|
||||
}
|
||||
|
||||
fn glyph_h_advance(glyph: GlyphIndex) -> int {
|
||||
|
||||
#debug("getting h advance for glyph %?", glyph);
|
||||
|
||||
let glyphs: ~[cairo_glyph_t] = ~[{
|
||||
index: glyph as c_ulong,
|
||||
x: 0 as c_double,
|
||||
y: 0 as c_double,
|
||||
}];
|
||||
let extents: cairo_text_extents_t = {
|
||||
x_bearing: 0 as c_double,
|
||||
y_bearing: 0 as c_double,
|
||||
width: 0 as c_double,
|
||||
height: 0 as c_double,
|
||||
x_advance: 0 as c_double,
|
||||
y_advance: 0 as c_double,
|
||||
};
|
||||
|
||||
assert self.cairo_font.is_not_null();
|
||||
|
||||
cairo_scaled_font_glyph_extents(
|
||||
self.cairo_font, unsafe { vec_to_ptr(glyphs) },
|
||||
1 as c_int, addr_of(extents));
|
||||
|
||||
match cairo_scaled_font_status(self.cairo_font) {
|
||||
status if status == CAIRO_STATUS_SUCCESS => {
|
||||
|
||||
#debug("x_advance: %?", extents.x_advance);
|
||||
#debug("y_advance: %?", extents.y_advance);
|
||||
|
||||
return extents.x_advance as int;
|
||||
}
|
||||
status => {
|
||||
import str::unsafe::from_c_str;
|
||||
|
||||
let status_cstr = cairo_status_to_string(status);
|
||||
let status_str = unsafe { from_c_str(status_cstr) };
|
||||
|
||||
#error("cairo_scaled_font_glyph_extents status: %s", status_str);
|
||||
fail ~"failed to get glyph extents from cairo"
|
||||
}
|
||||
match self.native_font.glyph_h_advance(glyph) {
|
||||
some(adv) => adv,
|
||||
none => /* FIXME: Need fallback strategy */ 10
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cairo_font(buf: &~[u8]) -> (*cairo_scaled_font_t, fn@()) {
|
||||
|
||||
import libc::c_double;
|
||||
import azure::cairo;
|
||||
import cairo::{ cairo_matrix_t };
|
||||
import cairo::bindgen::{
|
||||
cairo_matrix_init_identity,
|
||||
cairo_matrix_scale,
|
||||
cairo_font_options_create,
|
||||
cairo_font_options_destroy,
|
||||
cairo_scaled_font_create,
|
||||
cairo_scaled_font_destroy
|
||||
};
|
||||
|
||||
import cairo::bindgen::cairo_scaled_font_create;
|
||||
|
||||
let mut (face, dtor) = get_cairo_face(buf);
|
||||
|
||||
let idmatrix: cairo_matrix_t = {
|
||||
xx: 0 as c_double,
|
||||
yx: 0 as c_double,
|
||||
xy: 0 as c_double,
|
||||
yy: 0 as c_double,
|
||||
x0: 0 as c_double,
|
||||
y0: 0 as c_double
|
||||
};
|
||||
cairo_matrix_init_identity(addr_of(idmatrix));
|
||||
|
||||
let fontmatrix = idmatrix;
|
||||
cairo_matrix_scale(addr_of(fontmatrix),
|
||||
20f as c_double, 20f as c_double);
|
||||
|
||||
let options = cairo_font_options_create();
|
||||
let cfont = cairo_scaled_font_create(face, addr_of(fontmatrix),
|
||||
addr_of(idmatrix), options);
|
||||
cairo_font_options_destroy(options);
|
||||
|
||||
// FIXME: Need negative tests
|
||||
if cfont.is_null() {
|
||||
dtor();
|
||||
fail ~"unable to create cairo scaled font";
|
||||
}
|
||||
dtor = fn@(move dtor) { cairo_scaled_font_destroy(cfont); dtor() };
|
||||
|
||||
(cfont, dtor)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_cairo_face(buf: &~[u8]) -> (*cairo_font_face_t, fn@()) {
|
||||
import freetype = azure::freetype;
|
||||
import freetype::{ FT_Error, FT_Library, FT_Face, FT_Long };
|
||||
import freetype::bindgen::{
|
||||
FT_Init_FreeType,
|
||||
FT_Done_FreeType,
|
||||
FT_New_Memory_Face,
|
||||
FT_Done_Face
|
||||
};
|
||||
import azure::cairo_ft;
|
||||
import cairo_ft::bindgen::cairo_ft_font_face_create_for_ft_face;
|
||||
|
||||
trait FTErrorMethods {
|
||||
fn for_sure();
|
||||
fn failed() -> bool;
|
||||
}
|
||||
|
||||
impl FT_Error : FTErrorMethods {
|
||||
fn for_sure() { assert !self.failed() }
|
||||
fn failed() -> bool { self != 0 as FT_Error }
|
||||
}
|
||||
|
||||
let mut dtor = fn@() { };
|
||||
|
||||
let library: FT_Library = null();
|
||||
// FIXME: Need tests for failure case
|
||||
FT_Init_FreeType(addr_of(library)).for_sure();
|
||||
dtor = fn@(move dtor) { FT_Done_FreeType(library).for_sure(); dtor() };
|
||||
|
||||
let face: FT_Face = null();
|
||||
vec::as_buf(*buf, |cbuf, len| {
|
||||
if FT_New_Memory_Face(library, cbuf, len as FT_Long,
|
||||
0 as FT_Long, addr_of(face)).failed() {
|
||||
dtor();
|
||||
fail ~"unable to create FreeType face";
|
||||
}
|
||||
});
|
||||
dtor = fn@(move dtor) { FT_Done_Face(face).for_sure(); dtor() };
|
||||
|
||||
let cface = cairo_ft_font_face_create_for_ft_face(face, 0 as c_int);
|
||||
if cface.is_null() {
|
||||
// FIXME: Need tests for failure case
|
||||
dtor();
|
||||
fail ~"unable to create cairo font face";
|
||||
}
|
||||
dtor = fn@(move dtor) { cairo_font_face_destroy(cface); dtor() };
|
||||
|
||||
(cface, dtor)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod cocoa {
|
||||
use cocoa;
|
||||
export cocoa;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn get_cairo_face(buf: &~[u8]) -> (*cairo_font_face_t, fn@()) {
|
||||
import unsafe::reinterpret_cast;
|
||||
import libc::size_t;
|
||||
import cocoa::cocoa;
|
||||
import cocoa::cg::cg::{
|
||||
CGDataProviderCreateWithData,
|
||||
CGDataProviderRelease,
|
||||
CGFontCreateWithDataProvider,
|
||||
CGFontRelease
|
||||
};
|
||||
import azure::cairo_quartz::bindgen::cairo_quartz_font_face_create_for_cgfont;
|
||||
|
||||
let mut dtor = fn@() { };
|
||||
|
||||
let fontprov = vec::as_buf(*buf, |cbuf, len| {
|
||||
CGDataProviderCreateWithData(
|
||||
null(),
|
||||
unsafe { reinterpret_cast(cbuf) },
|
||||
len as size_t,
|
||||
null()
|
||||
)
|
||||
});
|
||||
dtor = fn@(move dtor) { CGDataProviderRelease(fontprov); dtor() };
|
||||
|
||||
let cgfont = CGFontCreateWithDataProvider(fontprov);
|
||||
if cgfont.is_null() { fail ~"could not create quartz font" }
|
||||
dtor = fn@(move dtor) { CGFontRelease(cgfont); dtor() };
|
||||
|
||||
let cface = cairo_quartz_font_face_create_for_cgfont(cgfont);
|
||||
assert cface.is_not_null(); // FIXME: error handling
|
||||
dtor = fn@(move dtor) { cairo_font_face_destroy(cface); dtor() };
|
||||
|
||||
(cface, dtor)
|
||||
}
|
||||
|
||||
fn create_test_font() -> @Font {
|
||||
import font_library::FontLibrary;
|
||||
|
||||
|
@ -285,7 +60,7 @@ fn should_get_glyph_indexes() {
|
|||
#[ignore(reason = "random failures")];
|
||||
|
||||
let font = create_test_font();
|
||||
let glyph_idx = font.glyph_idx('w');
|
||||
let glyph_idx = font.glyph_index('w');
|
||||
assert glyph_idx == some(40u);
|
||||
}
|
||||
|
||||
|
@ -300,31 +75,8 @@ fn should_get_glyph_advance() {
|
|||
|
||||
fn should_be_able_to_create_instances_in_multiple_threads() {
|
||||
#[test];
|
||||
#[ignore];
|
||||
|
||||
for iter::repeat(10u) {do task::spawn {create_test_font();}}
|
||||
}
|
||||
|
||||
fn get_cairo_face_should_fail_and_not_leak_if_font_cant_be_created() {
|
||||
#[test];
|
||||
#[should_fail];
|
||||
|
||||
get_cairo_face(&~[0u8, 1u8, 2u8, 3u8]);
|
||||
}
|
||||
|
||||
fn get_cairo_face_should_return_a_new_face_and_dtor() {
|
||||
#[test];
|
||||
|
||||
let buf = test_font_bin();
|
||||
let (face, dtor) = get_cairo_face(&buf);
|
||||
assert face.is_not_null();
|
||||
dtor();
|
||||
}
|
||||
|
||||
fn get_cairo_font_should_return_a_new_font_and_dtor() {
|
||||
#[test];
|
||||
|
||||
let buf = test_font_bin();
|
||||
let (font, dtor) = get_cairo_font(&buf);
|
||||
assert font.is_not_null();
|
||||
dtor();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export FontLibrary, native;
|
||||
|
||||
import font::Font;
|
||||
import font::{Font, test_font_bin};
|
||||
import result::{result, ok, err};
|
||||
|
||||
class FontLibrary {
|
||||
let native_lib: native::NativeFontLibrary;
|
||||
|
@ -14,8 +15,10 @@ class FontLibrary {
|
|||
}
|
||||
|
||||
fn get_font() -> @Font {
|
||||
let f = Font(font::test_font_bin());
|
||||
return @f;
|
||||
match create_font(&self.native_lib) {
|
||||
ok(font) => font,
|
||||
err(*) => /* FIXME */ fail
|
||||
}
|
||||
}
|
||||
|
||||
fn get_test_font() -> @Font {
|
||||
|
@ -23,6 +26,18 @@ class FontLibrary {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
fn create_font(native_lib: &native::NativeFontLibrary) -> result<@Font, ()> {
|
||||
let font_bin = test_font_bin();
|
||||
let native_font = native_font::create(native_lib, &font_bin);
|
||||
let native_font = if native_font.is_ok() {
|
||||
result::unwrap(native_font)
|
||||
} else {
|
||||
return err(native_font.get_err());
|
||||
};
|
||||
return ok(@Font(font_bin, native_font));
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod native {
|
||||
import ptr::{null, addr_of};
|
||||
|
|
|
@ -7,7 +7,10 @@ font resources needed by the graphics layer to draw glyphs.
|
|||
|
||||
"];
|
||||
|
||||
export NativeFont;
|
||||
export NativeFont, create;
|
||||
|
||||
import result::result;
|
||||
import font_library::native::NativeFontLibrary;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
type NativeFont/& = quartz_native_font::QuartzNativeFont;
|
||||
|
@ -15,6 +18,16 @@ type NativeFont/& = quartz_native_font::QuartzNativeFont;
|
|||
#[cfg(target_os = "linux")]
|
||||
type NativeFont/& = ft_native_font::FreeTypeNativeFont;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn create(_native_lib: &NativeFontLibrary, buf: &~[u8]) -> result<NativeFont, ()> {
|
||||
quartz_native_font::create(buf)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn create(native_lib: &NativeFontLibrary, buf: &~[u8]) -> result<NativeFont, ()> {
|
||||
ft_native_font::create(*native_lib, buf)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn with_test_native_font(f: fn@(nf: &NativeFont)) {
|
||||
quartz_native_font::with_test_native_font(f);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export FreeTypeNativeFont, with_test_native_font;
|
||||
export FreeTypeNativeFont, with_test_native_font, create;
|
||||
|
||||
import vec_as_buf = vec::as_buf;
|
||||
import result::{result, ok, err};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use cocoa;
|
||||
|
||||
export QuartzNativeFont, with_test_native_font;
|
||||
export QuartzNativeFont, with_test_native_font, create;
|
||||
|
||||
import libc::size_t;
|
||||
import ptr::null;
|
||||
|
@ -50,8 +50,8 @@ class QuartzNativeFont/& {
|
|||
}
|
||||
}
|
||||
|
||||
fn create(buf: ~[u8]) -> result<QuartzNativeFont, ()> {
|
||||
let fontprov = vec::as_buf(buf, |cbuf, len| {
|
||||
fn create(buf: &~[u8]) -> result<QuartzNativeFont, ()> {
|
||||
let fontprov = vec::as_buf(*buf, |cbuf, len| {
|
||||
CGDataProviderCreateWithData(
|
||||
null(),
|
||||
unsafe { reinterpret_cast(cbuf) },
|
||||
|
@ -72,7 +72,7 @@ fn with_test_native_font(f: fn@(nf: &NativeFont)) {
|
|||
import unwrap_result = result::unwrap;
|
||||
|
||||
let buf = test_font_bin();
|
||||
let res = create(buf);
|
||||
let res = create(&buf);
|
||||
let font = unwrap_result(res);
|
||||
f(&font);
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ extern fn glyph_func(_font: *hb_font_t,
|
|||
let font: *Font = reinterpret_cast(font_data);
|
||||
assert font.is_not_null();
|
||||
|
||||
return match (*font).glyph_idx(unicode as char) {
|
||||
return match (*font).glyph_index(unicode as char) {
|
||||
some(g) => {
|
||||
*glyph = g as hb_codepoint_t;
|
||||
true
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue