mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +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
|
import libc::{ c_int, c_double };
|
||||||
// shared by layout and the renderer
|
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 = "
|
#[doc = "
|
||||||
A font handle. Layout can use this to calculate glyph metrics
|
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/& {
|
class font/& {
|
||||||
let fontbuf: [u8];
|
let fontbuf: [u8];
|
||||||
|
let cairo_font: *cairo_scaled_font_t;
|
||||||
|
let font_dtor: fn@();
|
||||||
|
|
||||||
new(+fontbuf: [u8]) {
|
new(+fontbuf: [u8]) {
|
||||||
|
|
||||||
|
let (cairo_font, font_dtor) = get_cairo_font(&fontbuf);
|
||||||
|
assert cairo_font.is_not_null();
|
||||||
|
|
||||||
self.fontbuf = fontbuf;
|
self.fontbuf = fontbuf;
|
||||||
|
self.cairo_font = cairo_font;
|
||||||
|
self.font_dtor = font_dtor;
|
||||||
|
}
|
||||||
|
|
||||||
|
drop {
|
||||||
|
self.font_dtor();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn buf() -> &self.[u8] {
|
fn buf() -> &self.[u8] {
|
||||||
&self.fontbuf
|
&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");
|
let buf = #include_bin("JosefinSans-SemiBold.ttf");
|
||||||
font(buf)
|
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]
|
#[test]
|
||||||
fn test_shape_basic() {
|
fn test_shape_basic() {
|
||||||
let font = font::create();
|
let font = font::create_test_font();
|
||||||
shape_text2(&font, "firecracker");
|
shape_text2(&font, "firecracker");
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ class text_run {
|
||||||
line break positions.
|
line break positions.
|
||||||
"]
|
"]
|
||||||
fn shape() {
|
fn shape() {
|
||||||
let font = font::create();
|
let font = font::create_test_font();
|
||||||
self.glyphs = some(shape_text(&font, self.text));
|
self.glyphs = some(shape_text(&font, self.text));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue