mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Teach text::font how to find a glyph index on linux
This commit is contained in:
parent
3d4d7eabfe
commit
c1af1b833c
3 changed files with 211 additions and 6 deletions
|
@ -1,7 +1,19 @@
|
|||
export font, create;
|
||||
export font, create_test_font;
|
||||
|
||||
// FIXME: This probably needs to be an arc type so it can be
|
||||
// shared by layout and the renderer
|
||||
import libc::{ c_int, c_double };
|
||||
import ptr::{ null, addr_of };
|
||||
import azure::cairo::{
|
||||
cairo_font_face_t,
|
||||
cairo_scaled_font_t,
|
||||
cairo_glyph_t,
|
||||
CAIRO_STATUS_SUCCESS,
|
||||
};
|
||||
import azure::cairo::bindgen::{
|
||||
cairo_font_face_destroy,
|
||||
cairo_scaled_font_destroy,
|
||||
cairo_scaled_font_text_to_glyphs,
|
||||
cairo_glyph_free,
|
||||
};
|
||||
|
||||
#[doc = "
|
||||
A font handle. Layout can use this to calculate glyph metrics
|
||||
|
@ -9,17 +21,210 @@ 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();
|
||||
|
||||
self.fontbuf = fontbuf;
|
||||
self.cairo_font = cairo_font;
|
||||
self.font_dtor = font_dtor;
|
||||
}
|
||||
|
||||
drop {
|
||||
self.font_dtor();
|
||||
}
|
||||
|
||||
fn buf() -> &self.[u8] {
|
||||
&self.fontbuf
|
||||
}
|
||||
|
||||
fn get_glyph_idx(codepoint: char) -> option<uint> {
|
||||
#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()
|
||||
)
|
||||
};
|
||||
|
||||
ret 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 uint;
|
||||
#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 create() -> font {
|
||||
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),
|
||||
300f as c_double, 400f 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;
|
||||
|
||||
impl methods for FT_Error {
|
||||
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|
|
||||
if FT_New_Memory_Face(library, cbuf, (*buf).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")]
|
||||
fn get_cairo_face(buf: &[u8]) -> (*cairo_font_face_t, fn@()) {
|
||||
fail
|
||||
}
|
||||
|
||||
fn create_test_font() -> font {
|
||||
let buf = #include_bin("JosefinSans-SemiBold.ttf");
|
||||
font(buf)
|
||||
}
|
||||
|
||||
fn should_destruct_on_fail_without_leaking() {
|
||||
#[test];
|
||||
#[should_fail];
|
||||
|
||||
let _font = create_test_font();
|
||||
fail;
|
||||
}
|
||||
|
||||
fn should_get_glyph_indexes() {
|
||||
#[test];
|
||||
|
||||
let font = create_test_font();
|
||||
let glyph_idx = font.get_glyph_idx('w');
|
||||
assert glyph_idx == some(40u);
|
||||
}
|
||||
|
||||
fn should_be_threadsafe() {
|
||||
#[test];
|
||||
|
||||
iter::repeat(10u) {||
|
||||
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 = #include_bin("JosefinSans-SemiBold.ttf");
|
||||
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 = #include_bin("JosefinSans-SemiBold.ttf");
|
||||
let (font, dtor) = get_cairo_font(&buf);
|
||||
assert font.is_not_null();
|
||||
dtor();
|
||||
}
|
||||
|
|
|
@ -139,6 +139,6 @@ fn hb_glyph_pos_to_servo_glyph_pos(hb_pos: hb_glyph_position_t) -> glyph_pos {
|
|||
|
||||
#[test]
|
||||
fn test_shape_basic() {
|
||||
let font = font::create();
|
||||
let font = font::create_test_font();
|
||||
shape_text2(&font, "firecracker");
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ class text_run {
|
|||
line break positions.
|
||||
"]
|
||||
fn shape() {
|
||||
let font = font::create();
|
||||
let font = font::create_test_font();
|
||||
self.glyphs = some(shape_text(&font, self.text));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue