mirror of
https://github.com/servo/servo.git
synced 2025-06-23 16:44:33 +01:00
Add port of Gecko's CompressedGlyph.
This commit is contained in:
parent
eaada181b1
commit
f08f56d40d
4 changed files with 202 additions and 20 deletions
|
@ -7,10 +7,10 @@ use libc::{ c_int, c_double, c_ulong };
|
||||||
use ptr::{ null, addr_of };
|
use ptr::{ null, addr_of };
|
||||||
use native_font::NativeFont;
|
use native_font::NativeFont;
|
||||||
|
|
||||||
#[doc = "
|
/**
|
||||||
A font handle. Layout can use this to calculate glyph metrics
|
A font handle. Layout can use this to calculate glyph metrics
|
||||||
and the renderer can use it to render text.
|
and the renderer can use it to render text.
|
||||||
"]
|
*/
|
||||||
struct Font {
|
struct Font {
|
||||||
// A back reference to keep the library alive
|
// A back reference to keep the library alive
|
||||||
lib: @FontCache,
|
lib: @FontCache,
|
||||||
|
@ -78,7 +78,7 @@ fn should_get_glyph_indexes() {
|
||||||
let lib = FontCache();
|
let lib = FontCache();
|
||||||
let font = lib.get_test_font();
|
let font = lib.get_test_font();
|
||||||
let glyph_idx = font.glyph_index('w');
|
let glyph_idx = font.glyph_index('w');
|
||||||
assert glyph_idx == Some(40u);
|
assert glyph_idx == Some(40u as GlyphIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_get_glyph_advance() {
|
fn should_get_glyph_advance() {
|
||||||
|
@ -86,7 +86,7 @@ fn should_get_glyph_advance() {
|
||||||
|
|
||||||
let lib = FontCache();
|
let lib = FontCache();
|
||||||
let font = lib.get_test_font();
|
let font = lib.get_test_font();
|
||||||
let x = font.glyph_h_advance(40u);
|
let x = font.glyph_h_advance(40u as GlyphIndex);
|
||||||
assert x == 15;
|
assert x == 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ fn should_get_glyph_advance_stress() {
|
||||||
do task::spawn {
|
do task::spawn {
|
||||||
let lib = FontCache();
|
let lib = FontCache();
|
||||||
let font = lib.get_test_font();
|
let font = lib.get_test_font();
|
||||||
let x = font.glyph_h_advance(40u);
|
let x = font.glyph_h_advance(40u as GlyphIndex);
|
||||||
assert x == 15;
|
assert x == 15;
|
||||||
chan.send(());
|
chan.send(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,193 @@
|
||||||
export GlyphIndex, GlyphPos, Glyph;
|
export GlyphIndex, GlyphPos, Glyph;
|
||||||
|
|
||||||
use gfx::geometry::au;
|
use au = gfx::geometry;
|
||||||
|
use au::au;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
|
|
||||||
/** The index of a particular glyph within a font */
|
/** The index of a particular glyph within a font */
|
||||||
type GlyphIndex = uint;
|
struct CompressedGlyph {
|
||||||
|
mut value : u32
|
||||||
|
}
|
||||||
|
type GlyphIndex = u32;
|
||||||
|
|
||||||
|
enum BreakTypeFlags {
|
||||||
|
BREAK_TYPE_NONE = 0x0,
|
||||||
|
BREAK_TYPE_NORMAL = 0x1,
|
||||||
|
BREAK_TYPE_HYPEN = 0x2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make this more type-safe.
|
||||||
|
|
||||||
|
const FLAG_CHAR_IS_SPACE : u32 = 0x10000000u32;
|
||||||
|
// These two bits store a BreakTypeFlags
|
||||||
|
const FLAG_CAN_BREAK_MASK : u32 = 0x60000000u32;
|
||||||
|
const FLAG_CAN_BREAK_SHIFT : u32 = 29u32;
|
||||||
|
const FLAG_IS_SIMPLE_GLYPH : u32 = 0x80000000u32;
|
||||||
|
|
||||||
|
// glyph advance; in au's.
|
||||||
|
const GLYPH_ADVANCE_MASK : u32 = 0x0FFF0000u32;
|
||||||
|
const GLYPH_ADVANCE_SHIFT : u32 = 16;
|
||||||
|
const GLYPH_ID_MASK : u32 = 0x0000FFFFu32;
|
||||||
|
|
||||||
|
// Non-simple glyphs (more than one glyph per char; missing glyph,
|
||||||
|
// newline, tab, large advance, or nonzero x/y offsets) may have one
|
||||||
|
// or more detailed glyphs associated with them. They are stored in a
|
||||||
|
// side array so that there is a 1:1 mapping of CompressedGlyph to
|
||||||
|
// unicode char.
|
||||||
|
|
||||||
|
// The number of detailed glyphs for this char. If the char couldn't
|
||||||
|
// be mapped to a glyph (!FLAG_NOT_MISSING), then this actually holds
|
||||||
|
// the UTF8 code point instead.
|
||||||
|
const GLYPH_COUNT_MASK : u32 = 0x00FFFF00u32;
|
||||||
|
const GLYPH_COUNT_SHIFT : u32 = 8;
|
||||||
|
// N.B. following Gecko, these are all inverted so that a lot of
|
||||||
|
// missing chars can be memset with zeros in one fell swoop.
|
||||||
|
const FLAG_NOT_MISSING : u32 = 0x00000001u32;
|
||||||
|
const FLAG_NOT_CLUSTER_START : u32 = 0x00000002u32;
|
||||||
|
const FLAG_NOT_LIGATURE_GROUP_START : u32 = 0x00000004u32;
|
||||||
|
|
||||||
|
const FLAG_CHAR_IS_TAB : u32 = 0x00000008u32;
|
||||||
|
const FLAG_CHAR_IS_NEWLINE : u32 = 0x00000010u32;
|
||||||
|
const FLAG_CHAR_IS_LOW_SURROGATE : u32 = 0x00000020u32;
|
||||||
|
const CHAR_IDENTITY_FLAGS_MASK : u32 = 0x00000038u32;
|
||||||
|
|
||||||
|
|
||||||
|
pure fn is_simple_glyph_id(glyphId: GlyphIndex) -> bool {
|
||||||
|
((glyphId as u32) & GLYPH_ID_MASK) == glyphId
|
||||||
|
}
|
||||||
|
|
||||||
|
pure fn is_simple_advance(advance: au) -> bool {
|
||||||
|
let unsignedAu = advance.to_int() as u32;
|
||||||
|
(unsignedAu & (GLYPH_ADVANCE_MASK >> GLYPH_ADVANCE_SHIFT)) == unsignedAu
|
||||||
|
}
|
||||||
|
|
||||||
|
type DetailedGlyphCount = u16;
|
||||||
|
|
||||||
|
enum GlyphStoreResult<T> {
|
||||||
|
Simple(T),
|
||||||
|
Detailed(u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn SimpleGlyph(index: GlyphIndex, advance: au) -> CompressedGlyph {
|
||||||
|
assert is_simple_glyph_id(index);
|
||||||
|
assert is_simple_advance(advance);
|
||||||
|
|
||||||
|
let index_mask = index as u32;
|
||||||
|
let advance_mask = (*advance as u32) << GLYPH_ADVANCE_SHIFT;
|
||||||
|
|
||||||
|
CompressedGlyph {
|
||||||
|
value: index_mask | advance_mask | FLAG_IS_SIMPLE_GLYPH
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ComplexGlyph(startsCluster: bool, startsLigature: bool, glyphCount: u16) -> CompressedGlyph {
|
||||||
|
let mut val = FLAG_NOT_MISSING;
|
||||||
|
|
||||||
|
if !startsCluster {
|
||||||
|
val |= FLAG_NOT_CLUSTER_START;
|
||||||
|
}
|
||||||
|
if !startsLigature {
|
||||||
|
val |= FLAG_NOT_LIGATURE_GROUP_START;
|
||||||
|
}
|
||||||
|
val |= (glyphCount as u32) << GLYPH_COUNT_SHIFT;
|
||||||
|
|
||||||
|
CompressedGlyph {
|
||||||
|
value: val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn MissingGlyphs(glyphCount: u16) -> CompressedGlyph {
|
||||||
|
CompressedGlyph {
|
||||||
|
value: (glyphCount as u32) << GLYPH_COUNT_SHIFT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompressedGlyph {
|
||||||
|
pure fn advance() -> GlyphStoreResult<au> {
|
||||||
|
match self.is_simple() {
|
||||||
|
true => Simple(au::from_int(((self.value & GLYPH_ADVANCE_MASK) >> GLYPH_ADVANCE_SHIFT) as int)),
|
||||||
|
false => Detailed(self.glyph_count())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pure fn glyph() -> GlyphStoreResult<GlyphIndex> {
|
||||||
|
match self.is_simple() {
|
||||||
|
true => Simple(self.value & GLYPH_ID_MASK),
|
||||||
|
false => Detailed(self.glyph_count())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pure fn offset() -> GlyphStoreResult<Point2D<au>> {
|
||||||
|
match self.is_simple() {
|
||||||
|
true => Simple(Point2D(au(0), au(0))),
|
||||||
|
false => Detailed(self.glyph_count())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getter methods
|
||||||
|
|
||||||
|
// TODO: some getters are still missing; add them as needed.
|
||||||
|
|
||||||
|
// True if original char was normal (U+0020) space. Other chars may
|
||||||
|
// map to space glyph, but this does not account for them.
|
||||||
|
pure fn char_is_space() -> bool {
|
||||||
|
self.has_flag(FLAG_CHAR_IS_SPACE)
|
||||||
|
}
|
||||||
|
|
||||||
|
pure fn char_is_tab() -> bool {
|
||||||
|
!self.is_simple() && self.has_flag(FLAG_CHAR_IS_TAB)
|
||||||
|
}
|
||||||
|
|
||||||
|
pure fn char_is_newline() -> bool {
|
||||||
|
!self.is_simple() && self.has_flag(FLAG_CHAR_IS_NEWLINE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make typesafe break enum
|
||||||
|
pure fn can_break_before() -> u8 {
|
||||||
|
((self.value & FLAG_CAN_BREAK_MASK) >> FLAG_CAN_BREAK_SHIFT) as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
// setter methods
|
||||||
|
|
||||||
|
fn set_is_space() {
|
||||||
|
self.value |= FLAG_CHAR_IS_SPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_is_tab() {
|
||||||
|
assert !self.is_simple();
|
||||||
|
self.value |= FLAG_CHAR_IS_TAB;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_is_newline() {
|
||||||
|
assert !self.is_simple();
|
||||||
|
self.value |= FLAG_CHAR_IS_NEWLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns whether the setting had changed.
|
||||||
|
fn set_can_break_before(flags: u8) -> bool {
|
||||||
|
assert flags <= 0x2;
|
||||||
|
let mask = (flags as u32) << FLAG_CAN_BREAK_SHIFT;
|
||||||
|
let toggle = mask ^ (self.value & FLAG_CAN_BREAK_MASK);
|
||||||
|
self.value ^= toggle;
|
||||||
|
|
||||||
|
toggle as bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper methods
|
||||||
|
|
||||||
|
/*priv*/ pure fn glyph_count() -> u32 {
|
||||||
|
assert !self.is_simple();
|
||||||
|
(self.value & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
/*priv*/ pure fn is_simple() -> bool {
|
||||||
|
(self.value & FLAG_IS_SIMPLE_GLYPH) == self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
/*priv*/ pure fn has_flag(flag: u32) -> bool {
|
||||||
|
(self.value & flag) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** The position of a glyph on the screen. */
|
/** The position of a glyph on the screen. */
|
||||||
struct GlyphPos {
|
struct GlyphPos {
|
||||||
|
@ -21,11 +204,11 @@ fn GlyphPos(advance: Point2D<au>, offset: Point2D<au>) -> GlyphPos {
|
||||||
|
|
||||||
/** A single glyph. */
|
/** A single glyph. */
|
||||||
struct Glyph {
|
struct Glyph {
|
||||||
index: GlyphIndex,
|
index: u32,
|
||||||
pos: GlyphPos,
|
pos: GlyphPos,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Glyph(index: GlyphIndex, pos: GlyphPos) -> Glyph {
|
fn Glyph(index: u32, pos: GlyphPos) -> Glyph {
|
||||||
Glyph {
|
Glyph {
|
||||||
index : index,
|
index : index,
|
||||||
pos : copy pos,
|
pos : copy pos,
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
#[doc = "
|
/**
|
||||||
|
|
||||||
NativeFont encapsulates access to the platform's font API,
|
NativeFont encapsulates access to the platform's font API,
|
||||||
e.g. quartz, FreeType. It provides access to metrics and tables
|
e.g. quartz, FreeType. It provides access to metrics and tables
|
||||||
needed by the text shaper as well as access to the underlying
|
needed by the text shaper as well as access to the underlying
|
||||||
font resources needed by the graphics layer to draw glyphs.
|
font resources needed by the graphics layer to draw glyphs.
|
||||||
|
*/
|
||||||
"];
|
|
||||||
|
|
||||||
export NativeFont, create;
|
export NativeFont, create;
|
||||||
|
|
||||||
|
use glyph::GlyphIndex;
|
||||||
use font_cache::native::NativeFontCache;
|
use font_cache::native::NativeFontCache;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
@ -41,7 +40,7 @@ fn with_test_native_font(f: fn@(nf: &NativeFont)) {
|
||||||
fn should_get_glyph_indexes() {
|
fn should_get_glyph_indexes() {
|
||||||
with_test_native_font(|font| {
|
with_test_native_font(|font| {
|
||||||
let idx = font.glyph_index('w');
|
let idx = font.glyph_index('w');
|
||||||
assert idx == Some(40u);
|
assert idx == Some(40u as GlyphIndex);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +56,7 @@ fn should_return_none_glyph_index_for_bad_codepoints() {
|
||||||
#[ignore(cfg(target_os = "macos"))]
|
#[ignore(cfg(target_os = "macos"))]
|
||||||
fn should_get_glyph_h_advance() {
|
fn should_get_glyph_h_advance() {
|
||||||
with_test_native_font(|font| {
|
with_test_native_font(|font| {
|
||||||
let adv = font.glyph_h_advance(40u);
|
let adv = font.glyph_h_advance(40u as GlyphIndex);
|
||||||
assert adv == Some(15);
|
assert adv == Some(15);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -66,7 +65,7 @@ fn should_get_glyph_h_advance() {
|
||||||
#[ignore(cfg(target_os = "macos"))]
|
#[ignore(cfg(target_os = "macos"))]
|
||||||
fn should_return_none_glyph_h_advance_for_bad_codepoints() {
|
fn should_return_none_glyph_h_advance_for_bad_codepoints() {
|
||||||
with_test_native_font(|font| {
|
with_test_native_font(|font| {
|
||||||
let adv = font.glyph_h_advance(-1 as uint);
|
let adv = font.glyph_h_advance(-1 as GlyphIndex);
|
||||||
assert adv == None;
|
assert adv == None;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use au = gfx::geometry;
|
||||||
use libc::types::common::c99::int32_t;
|
use libc::types::common::c99::int32_t;
|
||||||
use libc::{c_uint, c_int, c_void, c_char};
|
use libc::{c_uint, c_int, c_void, c_char};
|
||||||
use font::Font;
|
use font::Font;
|
||||||
use glyph::{Glyph, GlyphPos};
|
use glyph::{Glyph, GlyphPos, GlyphIndex};
|
||||||
use ptr::{null, addr_of, offset};
|
use ptr::{null, addr_of, offset};
|
||||||
use gfx::geometry::au;
|
use gfx::geometry::au;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
|
@ -87,7 +87,7 @@ fn shape_text(font: &Font, text: &str) -> ~[Glyph] unsafe {
|
||||||
for uint::range(0u, info_len as uint) |i| {
|
for uint::range(0u, info_len as uint) |i| {
|
||||||
let info_ = offset(info_, i);
|
let info_ = offset(info_, i);
|
||||||
let pos = offset(pos, i);
|
let pos = offset(pos, i);
|
||||||
let codepoint = (*info_).codepoint as uint;
|
let codepoint = (*info_).codepoint as u32;
|
||||||
let pos = hb_glyph_pos_to_servo_glyph_pos(&*pos);
|
let pos = hb_glyph_pos_to_servo_glyph_pos(&*pos);
|
||||||
#debug("glyph %?: codep %?, x_adv %?, y_adv %?, x_off %?, y_of %?",
|
#debug("glyph %?: codep %?, x_adv %?, y_adv %?, x_off %?, y_of %?",
|
||||||
i, codepoint, pos.advance.x, pos.advance.y, pos.offset.x, pos.offset.y);
|
i, codepoint, pos.advance.x, pos.advance.y, pos.offset.x, pos.offset.y);
|
||||||
|
@ -132,7 +132,7 @@ extern fn glyph_h_advance_func(_font: *hb_font_t,
|
||||||
let font: *Font = reinterpret_cast(&font_data);
|
let font: *Font = reinterpret_cast(&font_data);
|
||||||
assert font.is_not_null();
|
assert font.is_not_null();
|
||||||
|
|
||||||
let h_advance = (*font).glyph_h_advance(glyph as uint);
|
let h_advance = (*font).glyph_h_advance(glyph as u32);
|
||||||
#debug("h_advance for codepoint %? is %?", glyph, h_advance);
|
#debug("h_advance for codepoint %? is %?", glyph, h_advance);
|
||||||
return h_advance as hb_position_t;
|
return h_advance as hb_position_t;
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ fn should_get_glyph_indexes() {
|
||||||
let font = lib.get_test_font();
|
let font = lib.get_test_font();
|
||||||
let glyphs = shape_text(font, ~"firecracker");
|
let glyphs = shape_text(font, ~"firecracker");
|
||||||
let idxs = glyphs.map(|glyph| glyph.index);
|
let idxs = glyphs.map(|glyph| glyph.index);
|
||||||
assert idxs == ~[32u, 8u, 13u, 14u, 10u, 13u, 201u, 10u, 37u, 14u, 13u];
|
assert idxs == ~[32u32, 8u32, 13u32, 14u32, 10u32, 13u32, 201u32, 10u32, 37u32, 14u32, 13u32];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_get_glyph_h_advance() {
|
fn should_get_glyph_h_advance() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue