mirror of
https://github.com/servo/servo.git
synced 2025-06-23 08:34:42 +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 native_font::NativeFont;
|
||||
|
||||
#[doc = "
|
||||
/**
|
||||
A font handle. Layout can use this to calculate glyph metrics
|
||||
and the renderer can use it to render text.
|
||||
"]
|
||||
*/
|
||||
struct Font {
|
||||
// A back reference to keep the library alive
|
||||
lib: @FontCache,
|
||||
|
@ -78,7 +78,7 @@ fn should_get_glyph_indexes() {
|
|||
let lib = FontCache();
|
||||
let font = lib.get_test_font();
|
||||
let glyph_idx = font.glyph_index('w');
|
||||
assert glyph_idx == Some(40u);
|
||||
assert glyph_idx == Some(40u as GlyphIndex);
|
||||
}
|
||||
|
||||
fn should_get_glyph_advance() {
|
||||
|
@ -86,7 +86,7 @@ fn should_get_glyph_advance() {
|
|||
|
||||
let lib = FontCache();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ fn should_get_glyph_advance_stress() {
|
|||
do task::spawn {
|
||||
let lib = FontCache();
|
||||
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;
|
||||
chan.send(());
|
||||
}
|
||||
|
|
|
@ -1,10 +1,193 @@
|
|||
export GlyphIndex, GlyphPos, Glyph;
|
||||
|
||||
use gfx::geometry::au;
|
||||
use au = gfx::geometry;
|
||||
use au::au;
|
||||
use geom::point::Point2D;
|
||||
|
||||
/** 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. */
|
||||
struct GlyphPos {
|
||||
|
@ -21,11 +204,11 @@ fn GlyphPos(advance: Point2D<au>, offset: Point2D<au>) -> GlyphPos {
|
|||
|
||||
/** A single glyph. */
|
||||
struct Glyph {
|
||||
index: GlyphIndex,
|
||||
index: u32,
|
||||
pos: GlyphPos,
|
||||
}
|
||||
|
||||
fn Glyph(index: GlyphIndex, pos: GlyphPos) -> Glyph {
|
||||
fn Glyph(index: u32, pos: GlyphPos) -> Glyph {
|
||||
Glyph {
|
||||
index : index,
|
||||
pos : copy pos,
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
#[doc = "
|
||||
|
||||
/**
|
||||
NativeFont encapsulates access to the platform's font API,
|
||||
e.g. quartz, FreeType. It provides access to metrics and tables
|
||||
needed by the text shaper as well as access to the underlying
|
||||
font resources needed by the graphics layer to draw glyphs.
|
||||
|
||||
"];
|
||||
*/
|
||||
|
||||
export NativeFont, create;
|
||||
|
||||
use glyph::GlyphIndex;
|
||||
use font_cache::native::NativeFontCache;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@ -41,7 +40,7 @@ fn with_test_native_font(f: fn@(nf: &NativeFont)) {
|
|||
fn should_get_glyph_indexes() {
|
||||
with_test_native_font(|font| {
|
||||
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"))]
|
||||
fn should_get_glyph_h_advance() {
|
||||
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);
|
||||
})
|
||||
}
|
||||
|
@ -66,7 +65,7 @@ fn should_get_glyph_h_advance() {
|
|||
#[ignore(cfg(target_os = "macos"))]
|
||||
fn should_return_none_glyph_h_advance_for_bad_codepoints() {
|
||||
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;
|
||||
})
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use au = gfx::geometry;
|
|||
use libc::types::common::c99::int32_t;
|
||||
use libc::{c_uint, c_int, c_void, c_char};
|
||||
use font::Font;
|
||||
use glyph::{Glyph, GlyphPos};
|
||||
use glyph::{Glyph, GlyphPos, GlyphIndex};
|
||||
use ptr::{null, addr_of, offset};
|
||||
use gfx::geometry::au;
|
||||
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| {
|
||||
let info_ = offset(info_, 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);
|
||||
#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);
|
||||
|
@ -132,7 +132,7 @@ extern fn glyph_h_advance_func(_font: *hb_font_t,
|
|||
let font: *Font = reinterpret_cast(&font_data);
|
||||
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);
|
||||
return h_advance as hb_position_t;
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ fn should_get_glyph_indexes() {
|
|||
let font = lib.get_test_font();
|
||||
let glyphs = shape_text(font, ~"firecracker");
|
||||
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() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue