mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Merge remote-tracking branch 'pcwalton/refactor-gfx'
Conflicts: src/servo-gfx/font.rs src/servo-gfx/font_context.rs src/servo-gfx/font_list.rs src/servo-gfx/freetype_impl/font_context.rs src/servo-gfx/image/encode/tga.rs src/servo-gfx/native.rs src/servo-gfx/platform/linux/font.rs src/servo-gfx/platform/linux/font_list.rs src/servo-gfx/platform/macos/font.rs src/servo-gfx/quartz/font_context.rs src/servo-gfx/quartz/font_list.rs src/servo-gfx/servo_gfx.rc src/servo-gfx/text/glyph.rs src/servo-gfx/text/mod.rs src/servo-gfx/text/shaper.rs src/servo-gfx/text/shaping/harfbuzz.rs src/servo-gfx/text/text_run.rs
This commit is contained in:
commit
d64d987e1d
16 changed files with 806 additions and 664 deletions
|
@ -5,36 +5,28 @@
|
||||||
use color::Color;
|
use color::Color;
|
||||||
use font_context::FontContext;
|
use font_context::FontContext;
|
||||||
use geometry::Au;
|
use geometry::Au;
|
||||||
|
use platform::font_context::FontContextHandle;
|
||||||
|
use platform::font::{FontHandle, FontTable};
|
||||||
use render_context::RenderContext;
|
use render_context::RenderContext;
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
use text::glyph::{GlyphStore, GlyphIndex};
|
use text::glyph::{GlyphStore, GlyphIndex};
|
||||||
use text::shaper::ShaperMethods;
|
use text::shaping::ShaperMethods;
|
||||||
use text::{Shaper, TextRun};
|
use text::{Shaper, TextRun};
|
||||||
use text::shaper::ShaperMethods;
|
|
||||||
|
|
||||||
use azure::{AzFloat, AzScaledFontRef};
|
use azure::{AzFloat, AzScaledFontRef};
|
||||||
use azure::scaled_font::ScaledFont;
|
use azure::scaled_font::ScaledFont;
|
||||||
use azure::azure_hl::{BackendType, ColorPattern};
|
use azure::azure_hl::{BackendType, ColorPattern};
|
||||||
use geom::{Point2D, Rect, Size2D};
|
use geom::{Point2D, Rect, Size2D};
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
use quartz;
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
use freetype_impl;
|
|
||||||
use native;
|
|
||||||
|
|
||||||
// FontHandle encapsulates access to the platform's font API,
|
// FontHandle 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 font
|
// needed by the text shaper as well as access to the underlying font
|
||||||
// resources needed by the graphics layer to draw glyphs.
|
// resources needed by the graphics layer to draw glyphs.
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub type FontHandle = quartz::font::QuartzFontHandle;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub type FontHandle = freetype_impl::font::FreeTypeFontHandle;
|
|
||||||
|
|
||||||
pub trait FontHandleMethods {
|
pub trait FontHandleMethods {
|
||||||
|
fn new_from_buffer(fctx: &FontContextHandle, buf: ~[u8], style: &SpecifiedFontStyle)
|
||||||
|
-> Result<Self,()>;
|
||||||
|
|
||||||
// an identifier usable by FontContextHandle to recreate this FontHandle.
|
// an identifier usable by FontContextHandle to recreate this FontHandle.
|
||||||
fn face_identifier(&self) -> ~str;
|
fn face_identifier(&self) -> ~str;
|
||||||
fn family_name(&self) -> ~str;
|
fn family_name(&self) -> ~str;
|
||||||
|
@ -42,36 +34,14 @@ pub trait FontHandleMethods {
|
||||||
fn is_italic(&self) -> bool;
|
fn is_italic(&self) -> bool;
|
||||||
fn boldness(&self) -> CSSFontWeight;
|
fn boldness(&self) -> CSSFontWeight;
|
||||||
|
|
||||||
fn clone_with_style(&self, fctx: &native::FontContextHandle, style: &UsedFontStyle) -> Result<FontHandle, ()>;
|
fn clone_with_style(&self, fctx: &FontContextHandle, style: &UsedFontStyle)
|
||||||
|
-> Result<FontHandle, ()>;
|
||||||
fn glyph_index(&self, codepoint: char) -> Option<GlyphIndex>;
|
fn glyph_index(&self, codepoint: char) -> Option<GlyphIndex>;
|
||||||
fn glyph_h_advance(&self, GlyphIndex) -> Option<FractionalPixel>;
|
fn glyph_h_advance(&self, GlyphIndex) -> Option<FractionalPixel>;
|
||||||
fn get_metrics(&self) -> FontMetrics;
|
fn get_metrics(&self) -> FontMetrics;
|
||||||
fn get_table_for_tag(&self, FontTableTag) -> Option<FontTable>;
|
fn get_table_for_tag(&self, FontTableTag) -> Option<FontTable>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(Issue #163): this is a workaround for static methods and
|
|
||||||
// typedefs not working well together. It should be removed.
|
|
||||||
//
|
|
||||||
// `new` should be part of trait FontHandleMethods.
|
|
||||||
|
|
||||||
pub impl FontHandle {
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub fn new_from_buffer(fctx: &native::FontContextHandle,
|
|
||||||
buf: ~[u8],
|
|
||||||
style: &SpecifiedFontStyle)
|
|
||||||
-> Result<FontHandle, ()> {
|
|
||||||
quartz::font::QuartzFontHandle::new_from_buffer(fctx, buf, style)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub fn new_from_buffer(fctx: &native::FontContextHandle,
|
|
||||||
buf: ~[u8],
|
|
||||||
style: &SpecifiedFontStyle)
|
|
||||||
-> Result<FontHandle, ()> {
|
|
||||||
freetype_impl::font::FreeTypeFontHandle::new_from_buffer(fctx, @buf, style)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to abstract over the shaper's choice of fixed int representation.
|
// Used to abstract over the shaper's choice of fixed int representation.
|
||||||
pub type FractionalPixel = float;
|
pub type FractionalPixel = float;
|
||||||
|
|
||||||
|
@ -93,12 +63,6 @@ impl FontTableTagConversions for FontTableTag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub type FontTable = quartz::font::QuartzFontTable;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub type FontTable = freetype_impl::font::FreeTypeFontTable;
|
|
||||||
|
|
||||||
pub trait FontTableMethods {
|
pub trait FontTableMethods {
|
||||||
fn with_buffer(&self, &fn(*u8, uint));
|
fn with_buffer(&self, &fn(*u8, uint));
|
||||||
}
|
}
|
||||||
|
@ -251,8 +215,8 @@ pub impl Font {
|
||||||
style: &SpecifiedFontStyle,
|
style: &SpecifiedFontStyle,
|
||||||
backend: BackendType)
|
backend: BackendType)
|
||||||
-> Result<@mut Font, ()> {
|
-> Result<@mut Font, ()> {
|
||||||
let handle = FontHandle::new_from_buffer(&ctx.handle, buffer, style);
|
let handle = FontHandleMethods::new_from_buffer(&ctx.handle, buffer, style);
|
||||||
let handle = if handle.is_ok() {
|
let handle: FontHandle = if handle.is_ok() {
|
||||||
result::unwrap(handle)
|
result::unwrap(handle)
|
||||||
} else {
|
} else {
|
||||||
return Err(handle.get_err());
|
return Err(handle.get_err());
|
||||||
|
|
|
@ -4,20 +4,16 @@
|
||||||
|
|
||||||
use font::{Font, FontDescriptor, FontGroup, FontStyle, SelectorPlatformIdentifier};
|
use font::{Font, FontDescriptor, FontGroup, FontStyle, SelectorPlatformIdentifier};
|
||||||
use font::{SelectorStubDummy, SpecifiedFontStyle, UsedFontStyle};
|
use font::{SelectorStubDummy, SpecifiedFontStyle, UsedFontStyle};
|
||||||
|
use font_context;
|
||||||
use font_list::FontList;
|
use font_list::FontList;
|
||||||
use native::FontHandle;
|
|
||||||
use servo_util::cache::Cache;
|
use servo_util::cache::Cache;
|
||||||
use servo_util::cache::MonoCache;
|
use servo_util::cache::MonoCache;
|
||||||
|
use platform::font::FontHandle;
|
||||||
|
use platform::font_context::FontContextHandle;
|
||||||
|
|
||||||
use azure::azure_hl::BackendType;
|
use azure::azure_hl::BackendType;
|
||||||
use core::hashmap::HashMap;
|
use core::hashmap::HashMap;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
use quartz;
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
use freetype_impl;
|
|
||||||
use font_context;
|
|
||||||
|
|
||||||
// TODO(Issue #164): delete, and get default font from font list
|
// TODO(Issue #164): delete, and get default font from font list
|
||||||
static TEST_FONT: [u8, ..33004] = include_bin!("JosefinSans-SemiBold.ttf");
|
static TEST_FONT: [u8, ..33004] = include_bin!("JosefinSans-SemiBold.ttf");
|
||||||
|
|
||||||
|
@ -38,31 +34,11 @@ pub fn dummy_style() -> FontStyle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
type FontContextHandle = quartz::font_context::QuartzFontContextHandle;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
type FontContextHandle = freetype_impl::font_context::FreeTypeFontContextHandle;
|
|
||||||
|
|
||||||
pub trait FontContextHandleMethods {
|
pub trait FontContextHandleMethods {
|
||||||
fn clone(&self) -> FontContextHandle;
|
fn clone(&self) -> FontContextHandle;
|
||||||
fn create_font_from_identifier(&self, ~str, UsedFontStyle) -> Result<FontHandle, ()>;
|
fn create_font_from_identifier(&self, ~str, UsedFontStyle) -> Result<FontHandle, ()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(Issue #163): this is a workaround for static methods, traits,
|
|
||||||
// and typedefs not working well together. It should be removed.
|
|
||||||
pub impl FontContextHandle {
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub fn new() -> FontContextHandle {
|
|
||||||
quartz::font_context::QuartzFontContextHandle::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub fn new() -> FontContextHandle {
|
|
||||||
freetype_impl::font_context::FreeTypeFontContextHandle::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
pub struct FontContext {
|
pub struct FontContext {
|
||||||
instance_cache: MonoCache<FontDescriptor, @mut Font>,
|
instance_cache: MonoCache<FontDescriptor, @mut Font>,
|
||||||
|
|
|
@ -4,60 +4,38 @@
|
||||||
|
|
||||||
use font::{CSSFontWeight, SpecifiedFontStyle};
|
use font::{CSSFontWeight, SpecifiedFontStyle};
|
||||||
use gfx_font::FontHandleMethods;
|
use gfx_font::FontHandleMethods;
|
||||||
use native::FontHandle;
|
use platform::font::FontHandle;
|
||||||
use gfx_font::FontHandleMethods;
|
use platform::font_context::FontContextHandle;
|
||||||
|
use platform::font_list::FontListHandle;
|
||||||
use core::hashmap::HashMap;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
use fontconfig;
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
use quartz;
|
|
||||||
use native;
|
|
||||||
use servo_util::time::time;
|
use servo_util::time::time;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
use core::hashmap::HashMap;
|
||||||
type FontListHandle = quartz::font_list::QuartzFontListHandle;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
type FontListHandle = fontconfig::font_list::FontconfigFontListHandle;
|
|
||||||
|
|
||||||
pub impl FontListHandle {
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub fn new(fctx: &native::FontContextHandle) -> Result<FontListHandle, ()> {
|
|
||||||
Ok(quartz::font_list::QuartzFontListHandle::new(fctx))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub fn new(fctx: &native::FontContextHandle) -> Result<FontListHandle, ()> {
|
|
||||||
Ok(fontconfig::font_list::FontconfigFontListHandle::new(fctx))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type FontFamilyMap = HashMap<~str, @mut FontFamily>;
|
pub type FontFamilyMap = HashMap<~str, @mut FontFamily>;
|
||||||
|
|
||||||
trait FontListHandleMethods {
|
trait FontListHandleMethods {
|
||||||
fn get_available_families(&self, fctx: &native::FontContextHandle) -> FontFamilyMap;
|
fn get_available_families(&self, fctx: &FontContextHandle) -> FontFamilyMap;
|
||||||
fn load_variations_for_family(&self, family: @mut FontFamily);
|
fn load_variations_for_family(&self, family: @mut FontFamily);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The platform-independent font list abstraction.
|
||||||
pub struct FontList {
|
pub struct FontList {
|
||||||
family_map: FontFamilyMap,
|
family_map: FontFamilyMap,
|
||||||
handle: FontListHandle,
|
handle: FontListHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl FontList {
|
pub impl FontList {
|
||||||
fn new(fctx: &native::FontContextHandle) -> FontList {
|
fn new(fctx: &FontContextHandle) -> FontList {
|
||||||
let handle = result::unwrap(FontListHandle::new(fctx));
|
let handle = FontListHandle::new(fctx);
|
||||||
let mut list = FontList {
|
let mut list = FontList {
|
||||||
handle: handle,
|
handle: handle,
|
||||||
family_map: HashMap::new(),
|
family_map: HashMap::new(),
|
||||||
};
|
};
|
||||||
list.refresh(fctx);
|
list.refresh(fctx);
|
||||||
return list;
|
list
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn refresh(&mut self, _fctx: &native::FontContextHandle) {
|
priv fn refresh(&mut self, _: &FontContextHandle) {
|
||||||
// TODO(Issue #186): don't refresh unless something actually
|
// TODO(Issue #186): don't refresh unless something actually
|
||||||
// changed. Does OSX have a notification for this event?
|
// changed. Does OSX have a notification for this event?
|
||||||
//
|
//
|
||||||
|
@ -71,19 +49,24 @@ pub impl FontList {
|
||||||
family_name: &str,
|
family_name: &str,
|
||||||
style: &SpecifiedFontStyle) -> Option<@FontEntry> {
|
style: &SpecifiedFontStyle) -> Option<@FontEntry> {
|
||||||
let family = self.find_family(family_name);
|
let family = self.find_family(family_name);
|
||||||
let mut result : Option<@FontEntry> = None;
|
|
||||||
|
|
||||||
// TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
|
// TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
|
||||||
|
|
||||||
// if such family exists, try to match style to a font
|
// if such family exists, try to match style to a font
|
||||||
|
let mut result: Option<@FontEntry> = None;
|
||||||
for family.each |fam| {
|
for family.each |fam| {
|
||||||
result = fam.find_font_for_style(&self.handle, style);
|
result = fam.find_font_for_style(&self.handle, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
let decision = if result.is_some() { "Found" } else { "Couldn't find" };
|
let decision = if result.is_some() {
|
||||||
|
"Found"
|
||||||
|
} else {
|
||||||
|
"Couldn't find"
|
||||||
|
};
|
||||||
|
|
||||||
debug!("FontList: %s font face in family[%s] matching style", decision, family_name);
|
debug!("FontList: %s font face in family[%s] matching style", decision, family_name);
|
||||||
|
|
||||||
return result;
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn find_family(&self, family_name: &str) -> Option<@mut FontFamily> {
|
priv fn find_family(&self, family_name: &str) -> Option<@mut FontFamily> {
|
||||||
|
@ -104,23 +87,23 @@ pub struct FontFamily {
|
||||||
entries: ~[@FontEntry],
|
entries: ~[@FontEntry],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl FontFamily {
|
impl FontFamily {
|
||||||
fn new(family_name: &str) -> FontFamily {
|
pub fn new(family_name: &str) -> FontFamily {
|
||||||
FontFamily {
|
FontFamily {
|
||||||
family_name: str::from_slice(family_name),
|
family_name: str::from_slice(family_name),
|
||||||
entries: ~[],
|
entries: ~[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn load_family_variations(@mut self, list: &native::FontListHandle) {
|
fn load_family_variations(@mut self, list: &FontListHandle) {
|
||||||
let this : &mut FontFamily = self; // FIXME: borrow checker workaround
|
let this : &mut FontFamily = self; // FIXME: borrow checker workaround
|
||||||
if this.entries.len() > 0 { return; }
|
if this.entries.len() > 0 { return; }
|
||||||
list.load_variations_for_family(self);
|
list.load_variations_for_family(self);
|
||||||
assert!(this.entries.len() > 0);
|
assert!(this.entries.len() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_font_for_style(@mut self, list: &native::FontListHandle, style: &SpecifiedFontStyle) -> Option<@FontEntry> {
|
pub fn find_font_for_style(@mut self, list: &FontListHandle, style: &SpecifiedFontStyle)
|
||||||
|
-> Option<@FontEntry> {
|
||||||
self.load_family_variations(list);
|
self.load_family_variations(list);
|
||||||
|
|
||||||
// TODO(Issue #189): optimize lookup for
|
// TODO(Issue #189): optimize lookup for
|
||||||
|
@ -129,7 +112,7 @@ pub impl FontFamily {
|
||||||
|
|
||||||
// TODO(Issue #190): if not in the fast path above, do
|
// TODO(Issue #190): if not in the fast path above, do
|
||||||
// expensive matching of weights, etc.
|
// expensive matching of weights, etc.
|
||||||
let this : &mut FontFamily = self; // FIXME: borrow checker workaround
|
let this: &mut FontFamily = self; // FIXME: borrow checker workaround
|
||||||
for this.entries.each |entry| {
|
for this.entries.each |entry| {
|
||||||
if (style.weight.is_bold() == entry.is_bold()) &&
|
if (style.weight.is_bold() == entry.is_bold()) &&
|
||||||
(style.italic == entry.is_italic()) {
|
(style.italic == entry.is_italic()) {
|
||||||
|
@ -138,15 +121,15 @@ pub impl FontFamily {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This struct summarizes an available font's features. In the future,
|
/// This struct summarizes an available font's features. In the future, this will include fiddly
|
||||||
// this will include fiddly settings such as special font table handling.
|
/// settings such as special font table handling.
|
||||||
|
///
|
||||||
// In the common case, each FontFamily will have a singleton FontEntry, or
|
/// In the common case, each FontFamily will have a singleton FontEntry, or it will have the
|
||||||
// it will have the standard four faces: Normal, Bold, Italic, BoldItalic.
|
/// standard four faces: Normal, Bold, Italic, BoldItalic.
|
||||||
pub struct FontEntry {
|
pub struct FontEntry {
|
||||||
family: @mut FontFamily,
|
family: @mut FontFamily,
|
||||||
face_name: ~str,
|
face_name: ~str,
|
||||||
|
@ -156,8 +139,8 @@ pub struct FontEntry {
|
||||||
// TODO: array of OpenType features, etc.
|
// TODO: array of OpenType features, etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl FontEntry {
|
impl FontEntry {
|
||||||
fn new(family: @mut FontFamily, handle: FontHandle) -> FontEntry {
|
pub fn new(family: @mut FontFamily, handle: FontHandle) -> FontEntry {
|
||||||
FontEntry {
|
FontEntry {
|
||||||
family: family,
|
family: family,
|
||||||
face_name: handle.face_name(),
|
face_name: handle.face_name(),
|
||||||
|
@ -167,9 +150,12 @@ pub impl FontEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_bold(&self) -> bool {
|
pub fn is_bold(&self) -> bool {
|
||||||
self.weight.is_bold()
|
self.weight.is_bold()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_italic(&self) -> bool { self.italic }
|
pub fn is_italic(&self) -> bool {
|
||||||
|
self.italic
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,60 +4,27 @@
|
||||||
|
|
||||||
extern mod freetype;
|
extern mod freetype;
|
||||||
|
|
||||||
use native;
|
|
||||||
use freetype_impl::font_context::FreeTypeFontContextHandle;
|
use freetype_impl::font_context::FreeTypeFontContextHandle;
|
||||||
use gfx_font::{
|
use font::{CSSFontWeight, FontHandleMethods, FontMetrics, FontTableMethods};
|
||||||
CSSFontWeight,
|
use font::{FontTableTag, FractionalPixel, SpecifiedFontStyle, UsedFontStyle, FontWeight100};
|
||||||
FontHandleMethods,
|
use font::{FontWeight200, FontWeight300, FontWeight400, FontWeight500, FontWeight600};
|
||||||
FontMetrics,
|
use font::{FontWeight700, FontWeight800, FontWeight900};
|
||||||
FontTable,
|
|
||||||
FontTableMethods,
|
|
||||||
FontTableTag,
|
|
||||||
FractionalPixel,
|
|
||||||
SpecifiedFontStyle,
|
|
||||||
UsedFontStyle,
|
|
||||||
FontWeight100,
|
|
||||||
FontWeight200,
|
|
||||||
FontWeight300,
|
|
||||||
FontWeight400,
|
|
||||||
FontWeight500,
|
|
||||||
FontWeight600,
|
|
||||||
FontWeight700,
|
|
||||||
FontWeight800,
|
|
||||||
FontWeight900,
|
|
||||||
};
|
|
||||||
use geometry;
|
|
||||||
use geometry::Au;
|
use geometry::Au;
|
||||||
|
use geometry;
|
||||||
|
use platform::font_context::FontContextHandle;
|
||||||
use text::glyph::GlyphIndex;
|
use text::glyph::GlyphIndex;
|
||||||
use text::util::{float_to_fixed, fixed_to_float};
|
use text::util::{float_to_fixed, fixed_to_float};
|
||||||
|
|
||||||
use self::freetype::freetype::{
|
use freetype::freetype::bindgen::{FT_Get_Char_Index, FT_Get_Postscript_Name};
|
||||||
FTErrorMethods,
|
use freetype::freetype::bindgen::{FT_Load_Glyph, FT_Set_Char_Size};
|
||||||
FT_F26Dot6,
|
use freetype::freetype::bindgen::{FT_New_Face, FT_Get_Sfnt_Table};
|
||||||
FT_Face,
|
use freetype::freetype::bindgen::{FT_New_Memory_Face, FT_Done_Face};
|
||||||
FT_FaceRec,
|
use freetype::freetype::{FTErrorMethods, FT_F26Dot6, FT_Face, FT_FaceRec};
|
||||||
FT_GlyphSlot,
|
use freetype::freetype::{FT_GlyphSlot, FT_Library, FT_Long, FT_ULong};
|
||||||
FT_Library,
|
use freetype::freetype::{FT_STYLE_FLAG_ITALIC, FT_STYLE_FLAG_BOLD};
|
||||||
FT_Long,
|
use freetype::freetype::{FT_SizeRec, FT_UInt, FT_Size_Metrics};
|
||||||
FT_ULong,
|
use freetype::freetype::{ft_sfnt_os2};
|
||||||
FT_SizeRec,
|
use freetype::tt_os2::TT_OS2;
|
||||||
FT_UInt,
|
|
||||||
FT_Size_Metrics,
|
|
||||||
FT_STYLE_FLAG_ITALIC,
|
|
||||||
FT_STYLE_FLAG_BOLD,
|
|
||||||
ft_sfnt_os2
|
|
||||||
};
|
|
||||||
use self::freetype::freetype::bindgen::{
|
|
||||||
FT_New_Memory_Face,
|
|
||||||
FT_Done_Face,
|
|
||||||
FT_Get_Char_Index,
|
|
||||||
FT_Get_Postscript_Name,
|
|
||||||
FT_Load_Glyph,
|
|
||||||
FT_Set_Char_Size,
|
|
||||||
FT_New_Face,
|
|
||||||
FT_Get_Sfnt_Table
|
|
||||||
};
|
|
||||||
use self::freetype::tt_os2::TT_OS2;
|
|
||||||
|
|
||||||
fn float_to_fixed_ft(f: float) -> i32 {
|
fn float_to_fixed_ft(f: float) -> i32 {
|
||||||
float_to_fixed(6, f)
|
float_to_fixed(6, f)
|
||||||
|
@ -67,22 +34,22 @@ fn fixed_to_float_ft(f: i32) -> float {
|
||||||
fixed_to_float(6, f)
|
fixed_to_float(6, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FreeTypeFontTable {
|
pub struct FontTable {
|
||||||
bogus: ()
|
bogus: ()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontTableMethods for FreeTypeFontTable {
|
impl FontTableMethods for FontTable {
|
||||||
fn with_buffer(&self, _blk: &fn(*u8, uint)) {
|
fn with_buffer(&self, _blk: &fn(*u8, uint)) {
|
||||||
fail!()
|
fail!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FontSource {
|
enum FontSource {
|
||||||
FontSourceMem(@~[u8]),
|
FontSourceMem(~[u8]),
|
||||||
FontSourceFile(~str)
|
FontSourceFile(~str)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FreeTypeFontHandle {
|
pub struct FontHandle {
|
||||||
// The font binary. This must stay valid for the lifetime of the font,
|
// The font binary. This must stay valid for the lifetime of the font,
|
||||||
// if the font is created using FT_Memory_Face.
|
// if the font is created using FT_Memory_Face.
|
||||||
source: FontSource,
|
source: FontSource,
|
||||||
|
@ -90,7 +57,7 @@ pub struct FreeTypeFontHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe_destructor]
|
#[unsafe_destructor]
|
||||||
impl Drop for FreeTypeFontHandle {
|
impl Drop for FontHandle {
|
||||||
fn finalize(&self) {
|
fn finalize(&self) {
|
||||||
assert!(self.face.is_not_null());
|
assert!(self.face.is_not_null());
|
||||||
if !FT_Done_Face(self.face).succeeded() {
|
if !FT_Done_Face(self.face).succeeded() {
|
||||||
|
@ -99,62 +66,15 @@ impl Drop for FreeTypeFontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl FreeTypeFontHandle {
|
impl FontHandleMethods for FontHandle {
|
||||||
priv fn set_char_size(face: FT_Face, pt_size: float) -> Result<(), ()>{
|
pub fn new_from_buffer(fctx: &FontContextHandle,
|
||||||
let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
|
buf: ~[u8],
|
||||||
let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
|
style: &SpecifiedFontStyle)
|
||||||
let h_dpi = 72;
|
-> Result<FontHandle, ()> {
|
||||||
let v_dpi = 72;
|
|
||||||
|
|
||||||
let result = FT_Set_Char_Size(face, char_width, char_height, h_dpi, v_dpi);
|
|
||||||
if result.succeeded() { Ok(()) } else { Err(()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_from_file(fctx: &FreeTypeFontContextHandle, file: ~str,
|
|
||||||
style: &SpecifiedFontStyle) -> Result<FreeTypeFontHandle, ()> {
|
|
||||||
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
||||||
if ft_ctx.is_null() { return Err(()); }
|
if ft_ctx.is_null() { return Err(()); }
|
||||||
|
|
||||||
let mut face: FT_Face = ptr::null();
|
let face_result = do vec::as_imm_buf(buf) |bytes: *u8, len: uint| {
|
||||||
let face_index = 0 as FT_Long;
|
|
||||||
do str::as_c_str(file) |file_str| {
|
|
||||||
FT_New_Face(ft_ctx, file_str,
|
|
||||||
face_index, ptr::to_unsafe_ptr(&face));
|
|
||||||
}
|
|
||||||
if face.is_null() {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
if FreeTypeFontHandle::set_char_size(face, style.pt_size).is_ok() {
|
|
||||||
Ok(FreeTypeFontHandle { source: FontSourceFile(file), face: face })
|
|
||||||
} else {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_from_file_unstyled(fctx: &FreeTypeFontContextHandle, file: ~str)
|
|
||||||
-> Result<FreeTypeFontHandle, ()> {
|
|
||||||
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
|
||||||
if ft_ctx.is_null() { return Err(()); }
|
|
||||||
|
|
||||||
let mut face: FT_Face = ptr::null();
|
|
||||||
let face_index = 0 as FT_Long;
|
|
||||||
do str::as_c_str(file) |file_str| {
|
|
||||||
FT_New_Face(ft_ctx, file_str,
|
|
||||||
face_index, ptr::to_unsafe_ptr(&face));
|
|
||||||
}
|
|
||||||
if face.is_null() {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(FreeTypeFontHandle { source: FontSourceFile(file), face: face })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_from_buffer(fctx: &FreeTypeFontContextHandle,
|
|
||||||
buf: @~[u8], style: &SpecifiedFontStyle) -> Result<FreeTypeFontHandle, ()> {
|
|
||||||
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
|
||||||
if ft_ctx.is_null() { return Err(()); }
|
|
||||||
|
|
||||||
let face_result = do vec::as_imm_buf(*buf) |bytes: *u8, len: uint| {
|
|
||||||
create_face_from_buffer(ft_ctx, bytes, len, style.pt_size)
|
create_face_from_buffer(ft_ctx, bytes, len, style.pt_size)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,7 +82,7 @@ pub impl FreeTypeFontHandle {
|
||||||
// and moving buf into the struct ctor, but cant' move out of
|
// and moving buf into the struct ctor, but cant' move out of
|
||||||
// captured binding.
|
// captured binding.
|
||||||
return match face_result {
|
return match face_result {
|
||||||
Ok(face) => Ok(FreeTypeFontHandle { face: face, source: FontSourceMem(buf) }),
|
Ok(face) => Ok(FontHandle { face: face, source: FontSourceMem(buf) }),
|
||||||
Err(()) => Err(())
|
Err(()) => Err(())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -178,16 +98,14 @@ pub impl FreeTypeFontHandle {
|
||||||
if !result.succeeded() || face.is_null() {
|
if !result.succeeded() || face.is_null() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
if FreeTypeFontHandle::set_char_size(face, pt_size).is_ok() {
|
if FontHandle::set_char_size(face, pt_size).is_ok() {
|
||||||
Ok(face)
|
Ok(face)
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl FontHandleMethods for FreeTypeFontHandle {
|
|
||||||
// an identifier usable by FontContextHandle to recreate this FontHandle.
|
// an identifier usable by FontContextHandle to recreate this FontHandle.
|
||||||
fn face_identifier(&self) -> ~str {
|
fn face_identifier(&self) -> ~str {
|
||||||
/* FT_Get_Postscript_Name seems like a better choice here, but it
|
/* FT_Get_Postscript_Name seems like a better choice here, but it
|
||||||
|
@ -231,14 +149,14 @@ impl FontHandleMethods for FreeTypeFontHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_with_style(&self,
|
fn clone_with_style(&self,
|
||||||
fctx: &native::FontContextHandle,
|
fctx: &FontContextHandle,
|
||||||
style: &UsedFontStyle) -> Result<FreeTypeFontHandle, ()> {
|
style: &UsedFontStyle) -> Result<FontHandle, ()> {
|
||||||
match self.source {
|
match self.source {
|
||||||
FontSourceMem(buf) => {
|
FontSourceMem(ref buf) => {
|
||||||
FreeTypeFontHandle::new_from_buffer(fctx, buf, style)
|
FontHandleMethods::new_from_buffer(fctx, buf.clone(), style)
|
||||||
}
|
}
|
||||||
FontSourceFile(copy file) => {
|
FontSourceFile(copy file) => {
|
||||||
FreeTypeFontHandle::new_from_file(fctx, file, style)
|
FontHandle::new_from_file(fctx, file, style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,12 +217,61 @@ impl FontHandleMethods for FreeTypeFontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_table_for_tag(&self, _tag: FontTableTag) -> Option<FontTable> {
|
fn get_table_for_tag(&self, _: FontTableTag) -> Option<FontTable> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl FreeTypeFontHandle {
|
pub impl FontHandle {
|
||||||
|
priv fn set_char_size(face: FT_Face, pt_size: float) -> Result<(), ()>{
|
||||||
|
let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
|
||||||
|
let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
|
||||||
|
let h_dpi = 72;
|
||||||
|
let v_dpi = 72;
|
||||||
|
|
||||||
|
let result = FT_Set_Char_Size(face, char_width, char_height, h_dpi, v_dpi);
|
||||||
|
if result.succeeded() { Ok(()) } else { Err(()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_from_file(fctx: &FontContextHandle, file: ~str,
|
||||||
|
style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
|
||||||
|
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
||||||
|
if ft_ctx.is_null() { return Err(()); }
|
||||||
|
|
||||||
|
let mut face: FT_Face = ptr::null();
|
||||||
|
let face_index = 0 as FT_Long;
|
||||||
|
do str::as_c_str(file) |file_str| {
|
||||||
|
FT_New_Face(ft_ctx, file_str,
|
||||||
|
face_index, ptr::to_unsafe_ptr(&face));
|
||||||
|
}
|
||||||
|
if face.is_null() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
if FontHandle::set_char_size(face, style.pt_size).is_ok() {
|
||||||
|
Ok(FontHandle { source: FontSourceFile(file), face: face })
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
|
||||||
|
-> Result<FontHandle, ()> {
|
||||||
|
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
||||||
|
if ft_ctx.is_null() { return Err(()); }
|
||||||
|
|
||||||
|
let mut face: FT_Face = ptr::null();
|
||||||
|
let face_index = 0 as FT_Long;
|
||||||
|
do str::as_c_str(file) |file_str| {
|
||||||
|
FT_New_Face(ft_ctx, file_str,
|
||||||
|
face_index, ptr::to_unsafe_ptr(&face));
|
||||||
|
}
|
||||||
|
if face.is_null() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(FontHandle { source: FontSourceFile(file), face: face })
|
||||||
|
}
|
||||||
|
|
||||||
priv fn get_face_rec(&self) -> &'self FT_FaceRec {
|
priv fn get_face_rec(&self) -> &'self FT_FaceRec {
|
||||||
unsafe {
|
unsafe {
|
||||||
&(*self.face)
|
&(*self.face)
|
||||||
|
@ -312,7 +279,6 @@ pub impl FreeTypeFontHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn font_units_to_au(&self, value: float) -> Au {
|
priv fn font_units_to_au(&self, value: float) -> Au {
|
||||||
|
|
||||||
let face = self.get_face_rec();
|
let face = self.get_face_rec();
|
||||||
|
|
||||||
// face.size is a *c_void in the bindings, presumably to avoid
|
// face.size is a *c_void in the bindings, presumably to avoid
|
||||||
|
@ -329,3 +295,4 @@ pub impl FreeTypeFontHandle {
|
||||||
return geometry::from_frac_px(value * x_scale);
|
return geometry::from_frac_px(value * x_scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
55
src/servo-gfx/platform/linux/font_context.rs
Normal file
55
src/servo-gfx/platform/linux/font_context.rs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use font::UsedFontStyle;
|
||||||
|
use platform::font::FontHandle;
|
||||||
|
use font_context::FontContextHandleMethods;
|
||||||
|
use platform::font_list::path_from_identifier;
|
||||||
|
|
||||||
|
use freetype::freetype::{FTErrorMethods, FT_Library};
|
||||||
|
use freetype::freetype::bindgen::{FT_Done_FreeType, FT_Init_FreeType};
|
||||||
|
|
||||||
|
|
||||||
|
struct FreeTypeLibraryHandle {
|
||||||
|
ctx: FT_Library,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for FreeTypeLibraryHandle {
|
||||||
|
fn finalize(&self) {
|
||||||
|
assert!(self.ctx.is_not_null());
|
||||||
|
FT_Done_FreeType(self.ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FontContextHandle {
|
||||||
|
ctx: @FreeTypeLibraryHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub impl FontContextHandle {
|
||||||
|
pub fn new() -> FontContextHandle {
|
||||||
|
let ctx: FT_Library = ptr::null();
|
||||||
|
let result = FT_Init_FreeType(ptr::to_unsafe_ptr(&ctx));
|
||||||
|
if !result.succeeded() { fail!(); }
|
||||||
|
|
||||||
|
FontContextHandle {
|
||||||
|
ctx: @FreeTypeLibraryHandle { ctx: ctx },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FontContextHandleMethods for FontContextHandle {
|
||||||
|
fn clone(&self) -> FontContextHandle {
|
||||||
|
FontContextHandle { ctx: self.ctx }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle)
|
||||||
|
-> Result<FontHandle, ()> {
|
||||||
|
debug!("Creating font handle for %s", name);
|
||||||
|
do path_from_identifier(name).chain |file_name| {
|
||||||
|
debug!("Opening font face %s", file_name);
|
||||||
|
FontHandle::new_from_file(self, file_name, &style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,9 +5,6 @@
|
||||||
extern mod freetype;
|
extern mod freetype;
|
||||||
extern mod fontconfig;
|
extern mod fontconfig;
|
||||||
|
|
||||||
use gfx_font::FontHandleMethods;
|
|
||||||
use gfx_font_list::{FontEntry, FontFamily, FontFamilyMap};
|
|
||||||
use gfx_font_context::FontContextHandleMethods;
|
|
||||||
use freetype_impl::font_context::FreeTypeFontContextHandle;
|
use freetype_impl::font_context::FreeTypeFontContextHandle;
|
||||||
use freetype_impl::font::FreeTypeFontHandle;
|
use freetype_impl::font::FreeTypeFontHandle;
|
||||||
use self::fontconfig::fontconfig::{FcChar8, FcResultMatch, FcSetSystem,
|
use self::fontconfig::fontconfig::{FcChar8, FcResultMatch, FcSetSystem,
|
||||||
|
@ -20,18 +17,40 @@ use self::fontconfig::fontconfig::bindgen::{
|
||||||
FcObjectSetAdd, FcPatternGetInteger
|
FcObjectSetAdd, FcPatternGetInteger
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
use font::FontHandleMethods;
|
||||||
|
use font_context::FontContextHandleMethods;
|
||||||
|
use font_list::{FontEntry, FontFamily, FontFamilyMap};
|
||||||
|
use platform::font::FontHandle;
|
||||||
|
use platform::font_context::FontContextHandle;
|
||||||
|
|
||||||
use core::hashmap::HashMap;
|
use core::hashmap::HashMap;
|
||||||
use core::libc::c_int;
|
use core::libc::c_int;
|
||||||
use core::ptr::Ptr;
|
use core::ptr::Ptr;
|
||||||
use native;
|
use fontconfig::fontconfig::bindgen::{FcConfigGetCurrent};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcConfigGetFonts};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcDefaultSubstitute};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcPatternCreate};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcFontSetDestroy};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcConfigSubstitute};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcFontSetList};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcObjectSetCreate};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcObjectSetDestroy};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcObjectSetAdd};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcPatternAddString, FcFontMatch};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcPatternGetInteger};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcPatternGetString};
|
||||||
|
use fontconfig::fontconfig::bindgen::{FcPatternDestroy};
|
||||||
|
use fontconfig::fontconfig::{FcChar8, FcResultMatch, FcSetSystem};
|
||||||
|
use fontconfig::fontconfig::{FcMatchPattern, FcResultNoMatch};
|
||||||
|
|
||||||
pub struct FontconfigFontListHandle {
|
pub struct FontListHandle {
|
||||||
fctx: FreeTypeFontContextHandle,
|
fctx: FontContextHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl FontconfigFontListHandle {
|
pub impl FontListHandle {
|
||||||
pub fn new(fctx: &native::FontContextHandle) -> FontconfigFontListHandle {
|
pub fn new(fctx: &FontContextHandle) -> FontListHandle {
|
||||||
FontconfigFontListHandle { fctx: fctx.clone() }
|
FontListHandle { fctx: fctx.clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_available_families(&self) -> FontFamilyMap {
|
fn get_available_families(&self) -> FontFamilyMap {
|
||||||
|
@ -103,7 +122,8 @@ pub impl FontconfigFontListHandle {
|
||||||
debug!("variation file: %?", file);
|
debug!("variation file: %?", file);
|
||||||
debug!("variation index: %?", index);
|
debug!("variation index: %?", index);
|
||||||
|
|
||||||
let font_handle = FreeTypeFontHandle::new_from_file_unstyled(&self.fctx, file);
|
let font_handle = FontHandle::new_from_file_unstyled(&self.fctx,
|
||||||
|
file);
|
||||||
let font_handle = font_handle.unwrap();
|
let font_handle = font_handle.unwrap();
|
||||||
|
|
||||||
debug!("Creating new FontEntry for face: %s", font_handle.face_name());
|
debug!("Creating new FontEntry for face: %s", font_handle.face_name());
|
|
@ -8,74 +8,58 @@ extern mod core_foundation;
|
||||||
extern mod core_graphics;
|
extern mod core_graphics;
|
||||||
extern mod core_text;
|
extern mod core_text;
|
||||||
|
|
||||||
|
use font::{CSSFontWeight, FontHandleMethods, FontMetrics, FontTableMethods};
|
||||||
|
use font::{FontTableTag, FontWeight100, FontWeight200, FontWeight300, FontWeight400};
|
||||||
|
use font::{FontWeight500, FontWeight600, FontWeight700, FontWeight800, FontWeight900};
|
||||||
|
use font::{FractionalPixel, SpecifiedFontStyle};
|
||||||
use geometry::Au;
|
use geometry::Au;
|
||||||
use gfx_font::{CSSFontWeight, FontHandleMethods, FontMetrics, FontTable, FontTableMethods};
|
use platform::macos::font_context::FontContextHandle;
|
||||||
use gfx_font::{FontTableTag, FontWeight100, FontWeight200, FontWeight300, FontWeight400};
|
|
||||||
use gfx_font::{FontWeight500, FontWeight600, FontWeight700, FontWeight800, FontWeight900};
|
|
||||||
use gfx_font::{FractionalPixel, SpecifiedFontStyle};
|
|
||||||
use quartz::font::core_foundation::base::{CFIndex, CFWrapper};
|
|
||||||
use quartz::font::core_foundation::data::CFData;
|
|
||||||
use quartz::font::core_foundation::string::UniChar;
|
|
||||||
use quartz::font::core_graphics::data_provider::CGDataProvider;
|
|
||||||
use quartz::font::core_graphics::font::{CGFont, CGGlyph};
|
|
||||||
use quartz::font::core_graphics::geometry::CGRect;
|
|
||||||
use quartz::font::core_text::font::{CTFont, CTFontMethods, CTFontMethodsPrivate};
|
|
||||||
use quartz::font::core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
|
|
||||||
use quartz::font::core_text::font_descriptor::kCTFontDefaultOrientation;
|
|
||||||
use quartz::font_context::QuartzFontContextHandle;
|
|
||||||
use quartz;
|
|
||||||
use text::glyph::GlyphIndex;
|
use text::glyph::GlyphIndex;
|
||||||
|
|
||||||
struct QuartzFontTable {
|
use core_foundation::base::{CFIndex, CFWrapper};
|
||||||
|
use core_foundation::data::CFData;
|
||||||
|
use core_foundation::string::UniChar;
|
||||||
|
use core_graphics::data_provider::CGDataProvider;
|
||||||
|
use core_graphics::font::{CGFont, CGGlyph};
|
||||||
|
use core_graphics::geometry::CGRect;
|
||||||
|
use core_graphics;
|
||||||
|
use core_text::font::{CTFont, CTFontMethods, CTFontMethodsPrivate};
|
||||||
|
use core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
|
||||||
|
use core_text::font_descriptor::{kCTFontDefaultOrientation};
|
||||||
|
use core_text;
|
||||||
|
|
||||||
|
pub struct FontTable {
|
||||||
data: CFData,
|
data: CFData,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Noncopyable.
|
// Noncopyable.
|
||||||
impl Drop for QuartzFontTable { fn finalize(&self) {} }
|
impl Drop for FontTable {
|
||||||
|
fn finalize(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
pub impl QuartzFontTable {
|
pub impl FontTable {
|
||||||
fn wrap(data: CFData) -> QuartzFontTable {
|
fn wrap(data: CFData) -> FontTable {
|
||||||
QuartzFontTable { data: data }
|
FontTable { data: data }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontTableMethods for QuartzFontTable {
|
impl FontTableMethods for FontTable {
|
||||||
fn with_buffer(&self, blk: &fn(*u8, uint)) {
|
fn with_buffer(&self, blk: &fn(*u8, uint)) {
|
||||||
blk(self.data.bytes(), self.data.len());
|
blk(self.data.bytes(), self.data.len());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct QuartzFontHandle {
|
pub struct FontHandle {
|
||||||
priv cgfont: Option<CGFont>,
|
priv cgfont: Option<CGFont>,
|
||||||
ctfont: CTFont,
|
ctfont: CTFont,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl QuartzFontHandle {
|
pub impl FontHandle {
|
||||||
fn new_from_buffer(_fctx: &QuartzFontContextHandle, buf: ~[u8],
|
fn new_from_CTFont(_: &FontContextHandle, ctfont: CTFont) -> Result<FontHandle, ()> {
|
||||||
style: &SpecifiedFontStyle) -> Result<QuartzFontHandle, ()> {
|
Ok(FontHandle {
|
||||||
let fontprov : CGDataProvider = vec::as_imm_buf(buf, |cbuf, len| {
|
|
||||||
quartz::font::core_graphics::data_provider::new_from_buffer(cbuf, len)
|
|
||||||
});
|
|
||||||
|
|
||||||
let cgfont = quartz::font::core_graphics::font::create_with_data_provider(&fontprov);
|
|
||||||
let ctfont = quartz::font::core_text::font::new_from_CGFont(&cgfont, style.pt_size);
|
|
||||||
|
|
||||||
let result = Ok(QuartzFontHandle {
|
|
||||||
cgfont: Some(cgfont),
|
|
||||||
ctfont: ctfont,
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_from_CTFont(_fctx: &QuartzFontContextHandle, ctfont: CTFont) -> Result<QuartzFontHandle, ()> {
|
|
||||||
let result = Ok(QuartzFontHandle {
|
|
||||||
mut cgfont: None,
|
mut cgfont: None,
|
||||||
ctfont: ctfont,
|
ctfont: ctfont,
|
||||||
});
|
})
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_CGFont(&mut self) -> CGFont {
|
fn get_CGFont(&mut self) -> CGFont {
|
||||||
|
@ -90,7 +74,24 @@ pub impl QuartzFontHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontHandleMethods for QuartzFontHandle {
|
impl FontHandleMethods for FontHandle {
|
||||||
|
fn new_from_buffer(_: &FontContextHandle, buf: ~[u8], style: &SpecifiedFontStyle)
|
||||||
|
-> Result<FontHandle, ()> {
|
||||||
|
let fontprov : CGDataProvider = vec::as_imm_buf(buf, |cbuf, len| {
|
||||||
|
core_graphics::data_provider::new_from_buffer(cbuf, len)
|
||||||
|
});
|
||||||
|
|
||||||
|
let cgfont = core_graphics::font::create_with_data_provider(&fontprov);
|
||||||
|
let ctfont = core_text::font::new_from_CGFont(&cgfont, style.pt_size);
|
||||||
|
|
||||||
|
let result = Ok(FontHandle {
|
||||||
|
cgfont: Some(cgfont),
|
||||||
|
ctfont: ctfont,
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
fn family_name(&self) -> ~str {
|
fn family_name(&self) -> ~str {
|
||||||
self.ctfont.family_name()
|
self.ctfont.family_name()
|
||||||
}
|
}
|
||||||
|
@ -119,11 +120,10 @@ impl FontHandleMethods for QuartzFontHandle {
|
||||||
return FontWeight900;
|
return FontWeight900;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_with_style(&self, fctx: &QuartzFontContextHandle,
|
fn clone_with_style(&self, fctx: &FontContextHandle, style: &SpecifiedFontStyle)
|
||||||
style: &SpecifiedFontStyle)
|
-> Result<FontHandle,()> {
|
||||||
-> Result<QuartzFontHandle,()> {
|
|
||||||
let new_font = self.ctfont.clone_with_font_size(style.pt_size);
|
let new_font = self.ctfont.clone_with_font_size(style.pt_size);
|
||||||
return QuartzFontHandle::new_from_CTFont(fctx, new_font);
|
return FontHandle::new_from_CTFont(fctx, new_font);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn glyph_index(&self, codepoint: char) -> Option<GlyphIndex> {
|
fn glyph_index(&self, codepoint: char) -> Option<GlyphIndex> {
|
||||||
|
@ -181,9 +181,9 @@ impl FontHandleMethods for QuartzFontHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
||||||
let result : Option<CFData> = self.ctfont.get_font_table(tag);
|
let result: Option<CFData> = self.ctfont.get_font_table(tag);
|
||||||
result.chain(|data| {
|
result.chain(|data| {
|
||||||
Some(QuartzFontTable::wrap(data))
|
Some(FontTable::wrap(data))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
38
src/servo-gfx/platform/macos/font_context.rs
Normal file
38
src/servo-gfx/platform/macos/font_context.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use font::UsedFontStyle;
|
||||||
|
use font_context::FontContextHandleMethods;
|
||||||
|
use platform::macos::font::FontHandle;
|
||||||
|
|
||||||
|
use core_text;
|
||||||
|
|
||||||
|
pub struct FontContextHandle {
|
||||||
|
ctx: ()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub impl FontContextHandle {
|
||||||
|
// this is a placeholder until NSFontManager or whatever is bound in here.
|
||||||
|
pub fn new() -> FontContextHandle {
|
||||||
|
FontContextHandle { ctx: () }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FontContextHandleMethods for FontContextHandle {
|
||||||
|
fn clone(&self) -> FontContextHandle {
|
||||||
|
FontContextHandle {
|
||||||
|
ctx: self.ctx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_font_from_identifier(&self,
|
||||||
|
name: ~str,
|
||||||
|
style: UsedFontStyle)
|
||||||
|
-> Result<FontHandle, ()> {
|
||||||
|
let ctfont_result = core_text::font::new_from_name(name, style.pt_size);
|
||||||
|
do result::chain(ctfont_result) |ctfont| {
|
||||||
|
FontHandle::new_from_CTFont(self, ctfont)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
src/servo-gfx/platform/macos/font_list.rs
Normal file
60
src/servo-gfx/platform/macos/font_list.rs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use font::FontHandleMethods;
|
||||||
|
use font_context::FontContextHandleMethods;
|
||||||
|
use font_list::{FontEntry, FontFamily, FontFamilyMap};
|
||||||
|
use platform::macos::font::FontHandle;
|
||||||
|
use platform::macos::font_context::FontContextHandle;
|
||||||
|
|
||||||
|
use core_foundation::array::CFArray;
|
||||||
|
use core_foundation::base::CFWrapper;
|
||||||
|
use core_foundation::string::{CFString, CFStringRef};
|
||||||
|
use core_text::font_collection::CTFontCollectionMethods;
|
||||||
|
use core_text::font_descriptor::CTFontDescriptorRef;
|
||||||
|
use core_text;
|
||||||
|
|
||||||
|
use core::hashmap::HashMap;
|
||||||
|
|
||||||
|
pub struct FontListHandle {
|
||||||
|
fctx: FontContextHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub impl FontListHandle {
|
||||||
|
fn new(fctx: &FontContextHandle) -> FontListHandle {
|
||||||
|
FontListHandle {
|
||||||
|
fctx: fctx.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_available_families(&self) -> FontFamilyMap {
|
||||||
|
let family_names: CFArray<CFStringRef> = core_text::font_collection::get_family_names();
|
||||||
|
let mut family_map : FontFamilyMap = HashMap::new();
|
||||||
|
for family_names.each |&strref: &CFStringRef| {
|
||||||
|
let family_name = CFString::wrap_extern(strref).to_str();
|
||||||
|
debug!("Creating new FontFamily for family: %s", family_name);
|
||||||
|
|
||||||
|
let new_family = @mut FontFamily::new(family_name);
|
||||||
|
family_map.insert(family_name, new_family);
|
||||||
|
}
|
||||||
|
return family_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_variations_for_family(&self, family: @mut FontFamily) {
|
||||||
|
let fam : &mut FontFamily = family; // FIXME: borrow checker workaround
|
||||||
|
let family_name = &fam.family_name;
|
||||||
|
debug!("Looking for faces of family: %s", *family_name);
|
||||||
|
|
||||||
|
let family_collection = core_text::font_collection::create_for_family(*family_name);
|
||||||
|
for family_collection.get_descriptors().each |descref: &CTFontDescriptorRef| {
|
||||||
|
let desc = CFWrapper::wrap_shared(*descref);
|
||||||
|
let font = core_text::font::new_from_descriptor(&desc, 0.0);
|
||||||
|
let handle = result::unwrap(FontHandle::new_from_CTFont(&self.fctx, font));
|
||||||
|
|
||||||
|
debug!("Creating new FontEntry for face: %s", handle.face_name());
|
||||||
|
let entry = @FontEntry::new(family, handle);
|
||||||
|
family.entries.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
src/servo-gfx/platform/mod.rs
Normal file
21
src/servo-gfx/platform/mod.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#[cfg(target_os="linux")] pub use platform::linux::{font, font_context, font_list};
|
||||||
|
#[cfg(target_os="macos")] pub use platform::macos::{font, font_context, font_list};
|
||||||
|
|
||||||
|
#[cfg(target_os="linux")]
|
||||||
|
pub mod linux {
|
||||||
|
pub mod font;
|
||||||
|
pub mod font_context;
|
||||||
|
pub mod font_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os="macos")]
|
||||||
|
pub mod macos {
|
||||||
|
pub mod font;
|
||||||
|
pub mod font_context;
|
||||||
|
pub mod font_list;
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,19 @@ extern mod stb_image;
|
||||||
extern mod std;
|
extern mod std;
|
||||||
extern mod servo_util (name = "servo_util");
|
extern mod servo_util (name = "servo_util");
|
||||||
|
|
||||||
|
// Eventually we would like the shaper to be pluggable, as many operating systems have their own
|
||||||
|
// shapers. For now, however, this is a hard dependency.
|
||||||
|
extern mod harfbuzz;
|
||||||
|
|
||||||
|
// Linux-specific library dependencies
|
||||||
|
#[cfg(target_os="linux")] extern mod fontconfig;
|
||||||
|
#[cfg(target_os="linux")] extern mod freetype;
|
||||||
|
|
||||||
|
// Mac OS-specific library dependencies
|
||||||
|
#[cfg(target_os="macos")] extern mod core_foundation;
|
||||||
|
#[cfg(target_os="macos")] extern mod core_graphics;
|
||||||
|
#[cfg(target_os="macos")] extern mod core_text;
|
||||||
|
|
||||||
pub use gfx_font = font;
|
pub use gfx_font = font;
|
||||||
pub use gfx_font_context = font_context;
|
pub use gfx_font_context = font_context;
|
||||||
pub use gfx_font_list = font_list;
|
pub use gfx_font_list = font_list;
|
||||||
|
@ -40,34 +53,13 @@ pub mod font_list;
|
||||||
// Misc.
|
// Misc.
|
||||||
pub mod opts;
|
pub mod opts;
|
||||||
|
|
||||||
// Pub-uses for multiple implementations. Platform selection happens in
|
// Platform-specific implementations.
|
||||||
// font.rs, font_list.rs, font_context.rs
|
#[path="platform/mod.rs"]
|
||||||
pub mod native;
|
pub mod platform;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub mod quartz {
|
|
||||||
pub mod font;
|
|
||||||
pub mod font_context;
|
|
||||||
pub mod font_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub mod freetype_impl {
|
|
||||||
pub mod font;
|
|
||||||
pub mod font_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub mod fontconfig {
|
|
||||||
pub mod font_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Images
|
// Images
|
||||||
pub mod image {
|
pub mod image {
|
||||||
pub mod base;
|
pub mod base;
|
||||||
pub mod encode {
|
|
||||||
pub mod tga;
|
|
||||||
}
|
|
||||||
pub mod holder;
|
pub mod holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,4 +76,3 @@ pub mod resource {
|
||||||
pub mod resource_task;
|
pub mod resource_task;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,35 +2,86 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use geometry::Au;
|
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
use servo_util::vec::*;
|
use servo_util::vec::*;
|
||||||
|
use servo_util::range::Range;
|
||||||
|
|
||||||
|
use geometry::Au;
|
||||||
use geometry;
|
use geometry;
|
||||||
use core;
|
|
||||||
use core::cmp::{Ord, Eq};
|
use core::cmp::{Ord, Eq};
|
||||||
use core::num::NumCast;
|
use core::num::NumCast;
|
||||||
use core::u16;
|
use core::u16;
|
||||||
|
use core;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use std::sort;
|
use std::sort;
|
||||||
|
|
||||||
|
/// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
|
||||||
// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing
|
///
|
||||||
// glyph data compactly.
|
/// In the common case (reasonable glyph advances, no offsets from the font em-box, and one glyph
|
||||||
//
|
/// per character), we pack glyph advance, glyph id, and some flags into a single u32.
|
||||||
// In the common case (reasonable glyph advances, no offsets from the
|
///
|
||||||
// font em-box, and one glyph per character), we pack glyph advance,
|
/// In the uncommon case (multiple glyphs per unicode character, large glyph index/advance, or
|
||||||
// glyph id, and some flags into a single u32.
|
/// glyph offsets), we pack the glyph count into GlyphEntry, and store the other glyph information
|
||||||
//
|
/// in DetailedGlyphStore.
|
||||||
// In the uncommon case (multiple glyphs per unicode character, large
|
|
||||||
// glyph index/advance, or glyph offsets), we pack the glyph count
|
|
||||||
// into GlyphEntry, and store the other glyph information in
|
|
||||||
// DetailedGlyphStore.
|
|
||||||
struct GlyphEntry {
|
struct GlyphEntry {
|
||||||
value : u32
|
value: u32
|
||||||
}
|
}
|
||||||
|
|
||||||
fn GlyphEntry(value: u32) -> GlyphEntry { GlyphEntry { value: value } }
|
impl GlyphEntry {
|
||||||
|
fn new(value: u32) -> GlyphEntry {
|
||||||
|
GlyphEntry {
|
||||||
|
value: value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initial() -> GlyphEntry {
|
||||||
|
GlyphEntry::new(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a GlyphEntry for the common case
|
||||||
|
fn simple(index: GlyphIndex, advance: Au) -> GlyphEntry {
|
||||||
|
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;
|
||||||
|
|
||||||
|
GlyphEntry::new(index_mask | advance_mask | FLAG_IS_SIMPLE_GLYPH)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a GlyphEntry for uncommon case; should be accompanied by
|
||||||
|
// initialization of the actual DetailedGlyph data in DetailedGlyphStore
|
||||||
|
fn complex(starts_cluster: bool, starts_ligature: bool, glyph_count: uint) -> GlyphEntry {
|
||||||
|
assert!(glyph_count <= u16::max_value as uint);
|
||||||
|
|
||||||
|
debug!("creating complex glyph entry: starts_cluster=%?, starts_ligature=%?, \
|
||||||
|
glyph_count=%?",
|
||||||
|
starts_cluster,
|
||||||
|
starts_ligature,
|
||||||
|
glyph_count);
|
||||||
|
|
||||||
|
let mut val = FLAG_NOT_MISSING;
|
||||||
|
|
||||||
|
if !starts_cluster {
|
||||||
|
val |= FLAG_NOT_CLUSTER_START;
|
||||||
|
}
|
||||||
|
if !starts_ligature {
|
||||||
|
val |= FLAG_NOT_LIGATURE_GROUP_START;
|
||||||
|
}
|
||||||
|
val |= (glyph_count as u32) << GLYPH_COUNT_SHIFT;
|
||||||
|
|
||||||
|
GlyphEntry::new(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a GlyphEntry for the case where glyphs couldn't be found for the specified
|
||||||
|
/// character.
|
||||||
|
fn missing(glyph_count: uint) -> GlyphEntry {
|
||||||
|
assert!(glyph_count <= u16::max_value as uint);
|
||||||
|
|
||||||
|
GlyphEntry::new((glyph_count as u32) << GLYPH_COUNT_SHIFT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The index of a particular glyph within a font
|
/// The index of a particular glyph within a font
|
||||||
pub type GlyphIndex = u32;
|
pub type GlyphIndex = u32;
|
||||||
|
@ -43,19 +94,23 @@ pub enum BreakType {
|
||||||
BreakTypeHyphen
|
BreakTypeHyphen
|
||||||
}
|
}
|
||||||
|
|
||||||
static BREAK_TYPE_NONE : u8 = 0x0u8;
|
static BREAK_TYPE_NONE: u8 = 0x0;
|
||||||
static BREAK_TYPE_NORMAL : u8 = 0x1u8;
|
static BREAK_TYPE_NORMAL: u8 = 0x1;
|
||||||
static BREAK_TYPE_HYPHEN : u8 = 0x2u8;
|
static BREAK_TYPE_HYPHEN: u8 = 0x2;
|
||||||
|
|
||||||
fn break_flag_to_enum(flag: u8) -> BreakType {
|
fn break_flag_to_enum(flag: u8) -> BreakType {
|
||||||
if (flag & BREAK_TYPE_NORMAL) != 0 { return BreakTypeNormal; }
|
if (flag & BREAK_TYPE_NORMAL) != 0 {
|
||||||
if (flag & BREAK_TYPE_HYPHEN) != 0 { return BreakTypeHyphen; }
|
return BreakTypeNormal;
|
||||||
|
}
|
||||||
|
if (flag & BREAK_TYPE_HYPHEN) != 0 {
|
||||||
|
return BreakTypeHyphen;
|
||||||
|
}
|
||||||
BreakTypeNone
|
BreakTypeNone
|
||||||
}
|
}
|
||||||
|
|
||||||
fn break_enum_to_flag(e: BreakType) -> u8 {
|
fn break_enum_to_flag(e: BreakType) -> u8 {
|
||||||
match e {
|
match e {
|
||||||
BreakTypeNone => BREAK_TYPE_NONE,
|
BreakTypeNone => BREAK_TYPE_NONE,
|
||||||
BreakTypeNormal => BREAK_TYPE_NORMAL,
|
BreakTypeNormal => BREAK_TYPE_NORMAL,
|
||||||
BreakTypeHyphen => BREAK_TYPE_HYPHEN,
|
BreakTypeHyphen => BREAK_TYPE_HYPHEN,
|
||||||
}
|
}
|
||||||
|
@ -63,16 +118,16 @@ fn break_enum_to_flag(e: BreakType) -> u8 {
|
||||||
|
|
||||||
// TODO: make this more type-safe.
|
// TODO: make this more type-safe.
|
||||||
|
|
||||||
static FLAG_CHAR_IS_SPACE : u32 = 0x10000000u32;
|
static FLAG_CHAR_IS_SPACE: u32 = 0x10000000;
|
||||||
// These two bits store some BREAK_TYPE_* flags
|
// These two bits store some BREAK_TYPE_* flags
|
||||||
static FLAG_CAN_BREAK_MASK : u32 = 0x60000000u32;
|
static FLAG_CAN_BREAK_MASK: u32 = 0x60000000;
|
||||||
static FLAG_CAN_BREAK_SHIFT : u32 = 29;
|
static FLAG_CAN_BREAK_SHIFT: u32 = 29;
|
||||||
static FLAG_IS_SIMPLE_GLYPH : u32 = 0x80000000u32;
|
static FLAG_IS_SIMPLE_GLYPH: u32 = 0x80000000;
|
||||||
|
|
||||||
// glyph advance; in Au's.
|
// glyph advance; in Au's.
|
||||||
static GLYPH_ADVANCE_MASK : u32 = 0x0FFF0000u32;
|
static GLYPH_ADVANCE_MASK: u32 = 0x0FFF0000;
|
||||||
static GLYPH_ADVANCE_SHIFT : u32 = 16;
|
static GLYPH_ADVANCE_SHIFT: u32 = 16;
|
||||||
static GLYPH_ID_MASK : u32 = 0x0000FFFFu32;
|
static GLYPH_ID_MASK: u32 = 0x0000FFFF;
|
||||||
|
|
||||||
// Non-simple glyphs (more than one glyph per char; missing glyph,
|
// Non-simple glyphs (more than one glyph per char; missing glyph,
|
||||||
// newline, tab, large advance, or nonzero x/y offsets) may have one
|
// newline, tab, large advance, or nonzero x/y offsets) may have one
|
||||||
|
@ -83,18 +138,18 @@ static GLYPH_ID_MASK : u32 = 0x0000FFFFu32;
|
||||||
// The number of detailed glyphs for this char. If the char couldn't
|
// 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
|
// be mapped to a glyph (!FLAG_NOT_MISSING), then this actually holds
|
||||||
// the UTF8 code point instead.
|
// the UTF8 code point instead.
|
||||||
static GLYPH_COUNT_MASK : u32 = 0x00FFFF00u32;
|
static GLYPH_COUNT_MASK: u32 = 0x00FFFF00;
|
||||||
static GLYPH_COUNT_SHIFT : u32 = 8;
|
static GLYPH_COUNT_SHIFT: u32 = 8;
|
||||||
// N.B. following Gecko, these are all inverted so that a lot of
|
// N.B. following Gecko, these are all inverted so that a lot of
|
||||||
// missing chars can be memset with zeros in one fell swoop.
|
// missing chars can be memset with zeros in one fell swoop.
|
||||||
static FLAG_NOT_MISSING : u32 = 0x00000001u32;
|
static FLAG_NOT_MISSING: u32 = 0x00000001;
|
||||||
static FLAG_NOT_CLUSTER_START : u32 = 0x00000002u32;
|
static FLAG_NOT_CLUSTER_START: u32 = 0x00000002;
|
||||||
static FLAG_NOT_LIGATURE_GROUP_START : u32 = 0x00000004u32;
|
static FLAG_NOT_LIGATURE_GROUP_START: u32 = 0x00000004;
|
||||||
|
|
||||||
static FLAG_CHAR_IS_TAB : u32 = 0x00000008u32;
|
static FLAG_CHAR_IS_TAB: u32 = 0x00000008;
|
||||||
static FLAG_CHAR_IS_NEWLINE : u32 = 0x00000010u32;
|
static FLAG_CHAR_IS_NEWLINE: u32 = 0x00000010;
|
||||||
static FLAG_CHAR_IS_LOW_SURROGATE : u32 = 0x00000020u32;
|
static FLAG_CHAR_IS_LOW_SURROGATE: u32 = 0x00000020;
|
||||||
static CHAR_IDENTITY_FLAGS_MASK : u32 = 0x00000038u32;
|
static CHAR_IDENTITY_FLAGS_MASK: u32 = 0x00000038;
|
||||||
|
|
||||||
fn is_simple_glyph_id(glyphId: GlyphIndex) -> bool {
|
fn is_simple_glyph_id(glyphId: GlyphIndex) -> bool {
|
||||||
((glyphId as u32) & GLYPH_ID_MASK) == glyphId
|
((glyphId as u32) & GLYPH_ID_MASK) == glyphId
|
||||||
|
@ -107,73 +162,20 @@ fn is_simple_advance(advance: Au) -> bool {
|
||||||
|
|
||||||
type DetailedGlyphCount = u16;
|
type DetailedGlyphCount = u16;
|
||||||
|
|
||||||
fn InitialGlyphEntry() -> GlyphEntry {
|
|
||||||
GlyphEntry { value: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a GlyphEntry for the common case
|
|
||||||
fn SimpleGlyphEntry(index: GlyphIndex, advance: Au) -> GlyphEntry {
|
|
||||||
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;
|
|
||||||
|
|
||||||
GlyphEntry {
|
|
||||||
value: index_mask | advance_mask | FLAG_IS_SIMPLE_GLYPH
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a GlyphEntry for uncommon case; should be accompanied by
|
|
||||||
// initialization of the actual DetailedGlyph data in DetailedGlyphStore
|
|
||||||
fn ComplexGlyphEntry(startsCluster: bool, startsLigature: bool, glyphCount: uint) -> GlyphEntry {
|
|
||||||
assert!(glyphCount <= u16::max_value as uint);
|
|
||||||
|
|
||||||
debug!("Creating complex glyph entry: startsCluster=%?, startsLigature=%?, glyphCount=%?",
|
|
||||||
startsCluster, startsLigature, glyphCount);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
GlyphEntry {
|
|
||||||
value: val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a GlyphEntry for the case where glyphs couldn't be found
|
|
||||||
// for the specified character.
|
|
||||||
fn MissingGlyphsEntry(glyphCount: uint) -> GlyphEntry {
|
|
||||||
assert!(glyphCount <= u16::max_value as uint);
|
|
||||||
|
|
||||||
GlyphEntry {
|
|
||||||
value: (glyphCount as u32) << GLYPH_COUNT_SHIFT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getters and setters for GlyphEntry. Setter methods are functional,
|
// Getters and setters for GlyphEntry. Setter methods are functional,
|
||||||
// because GlyphEntry is immutable and only a u32 in size.
|
// because GlyphEntry is immutable and only a u32 in size.
|
||||||
impl GlyphEntry {
|
impl GlyphEntry {
|
||||||
// getter methods
|
// getter methods
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn advance(&self) -> Au {
|
fn advance(&self) -> Au {
|
||||||
//assert!(self.is_simple());
|
|
||||||
NumCast::from((self.value & GLYPH_ADVANCE_MASK) >> GLYPH_ADVANCE_SHIFT)
|
NumCast::from((self.value & GLYPH_ADVANCE_MASK) >> GLYPH_ADVANCE_SHIFT)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index(&self) -> GlyphIndex {
|
fn index(&self) -> GlyphIndex {
|
||||||
//assert!(self.is_simple());
|
|
||||||
self.value & GLYPH_ID_MASK
|
self.value & GLYPH_ID_MASK
|
||||||
}
|
}
|
||||||
|
|
||||||
fn offset(&self) -> Point2D<Au> {
|
fn offset(&self) -> Point2D<Au> {
|
||||||
//assert!(self.is_simple());
|
|
||||||
Point2D(Au(0), Au(0))
|
Point2D(Au(0), Au(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,30 +209,30 @@ impl GlyphEntry {
|
||||||
// setter methods
|
// setter methods
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set_char_is_space(&self) -> GlyphEntry {
|
fn set_char_is_space(&self) -> GlyphEntry {
|
||||||
GlyphEntry(self.value | FLAG_CHAR_IS_SPACE)
|
GlyphEntry::new(self.value | FLAG_CHAR_IS_SPACE)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set_char_is_tab(&self) -> GlyphEntry {
|
fn set_char_is_tab(&self) -> GlyphEntry {
|
||||||
assert!(!self.is_simple());
|
assert!(!self.is_simple());
|
||||||
GlyphEntry(self.value | FLAG_CHAR_IS_TAB)
|
GlyphEntry::new(self.value | FLAG_CHAR_IS_TAB)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set_char_is_newline(&self) -> GlyphEntry {
|
fn set_char_is_newline(&self) -> GlyphEntry {
|
||||||
assert!(!self.is_simple());
|
assert!(!self.is_simple());
|
||||||
GlyphEntry(self.value | FLAG_CHAR_IS_NEWLINE)
|
GlyphEntry::new(self.value | FLAG_CHAR_IS_NEWLINE)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set_can_break_before(&self, e: BreakType) -> GlyphEntry {
|
fn set_can_break_before(&self, e: BreakType) -> GlyphEntry {
|
||||||
let flag = (break_enum_to_flag(e) as u32) << FLAG_CAN_BREAK_SHIFT;
|
let flag = (break_enum_to_flag(e) as u32) << FLAG_CAN_BREAK_SHIFT;
|
||||||
GlyphEntry(self.value | flag)
|
GlyphEntry::new(self.value | flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper methods
|
// helper methods
|
||||||
|
|
||||||
/*priv*/ fn glyph_count(&self) -> u16 {
|
fn glyph_count(&self) -> u16 {
|
||||||
assert!(!self.is_simple());
|
assert!(!self.is_simple());
|
||||||
((self.value & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT) as u16
|
((self.value & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT) as u16
|
||||||
}
|
}
|
||||||
|
@ -241,7 +243,7 @@ impl GlyphEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
/*priv*/ fn has_flag(&self, flag: u32) -> bool {
|
fn has_flag(&self, flag: u32) -> bool {
|
||||||
(self.value & flag) != 0
|
(self.value & flag) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,13 +263,13 @@ struct DetailedGlyph {
|
||||||
offset: Point2D<Au>
|
offset: Point2D<Au>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DetailedGlyph {
|
||||||
fn DetailedGlyph(index: GlyphIndex,
|
fn new(index: GlyphIndex, advance: Au, offset: Point2D<Au>) -> DetailedGlyph {
|
||||||
advance: Au, offset: Point2D<Au>) -> DetailedGlyph {
|
DetailedGlyph {
|
||||||
DetailedGlyph {
|
index: index,
|
||||||
index: index,
|
advance: advance,
|
||||||
advance: advance,
|
offset: offset
|
||||||
offset: offset
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,15 +306,15 @@ struct DetailedGlyphStore {
|
||||||
lookup_is_sorted: bool,
|
lookup_is_sorted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn DetailedGlyphStore() -> DetailedGlyphStore {
|
|
||||||
DetailedGlyphStore {
|
|
||||||
detail_buffer: ~[], // TODO: default size?
|
|
||||||
detail_lookup: ~[],
|
|
||||||
lookup_is_sorted: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DetailedGlyphStore {
|
impl DetailedGlyphStore {
|
||||||
|
fn new() -> DetailedGlyphStore {
|
||||||
|
DetailedGlyphStore {
|
||||||
|
detail_buffer: ~[], // TODO: default size?
|
||||||
|
detail_lookup: ~[],
|
||||||
|
lookup_is_sorted: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn add_detailed_glyphs_for_entry(&mut self, entry_offset: uint, glyphs: &[DetailedGlyph]) {
|
fn add_detailed_glyphs_for_entry(&mut self, entry_offset: uint, glyphs: &[DetailedGlyph]) {
|
||||||
let entry = DetailedGlyphRecord {
|
let entry = DetailedGlyphRecord {
|
||||||
entry_offset: entry_offset,
|
entry_offset: entry_offset,
|
||||||
|
@ -337,7 +339,8 @@ impl DetailedGlyphStore {
|
||||||
self.lookup_is_sorted = false;
|
self.lookup_is_sorted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_detailed_glyphs_for_entry(&self, entry_offset: uint, count: u16) -> &'self [DetailedGlyph] {
|
fn get_detailed_glyphs_for_entry(&self, entry_offset: uint, count: u16)
|
||||||
|
-> &'self [DetailedGlyph] {
|
||||||
debug!("Requesting detailed glyphs[n=%u] for entry[off=%u]", count as uint, entry_offset);
|
debug!("Requesting detailed glyphs[n=%u] for entry[off=%u]", count as uint, entry_offset);
|
||||||
|
|
||||||
// FIXME: Is this right? --pcwalton
|
// FIXME: Is this right? --pcwalton
|
||||||
|
@ -379,7 +382,7 @@ impl DetailedGlyphStore {
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: This is a workaround for borrow of self.detail_lookup not getting inferred.
|
// FIXME: This is a workaround for borrow of self.detail_lookup not getting inferred.
|
||||||
let records : &[DetailedGlyphRecord] = self.detail_lookup;
|
let records: &[DetailedGlyphRecord] = self.detail_lookup;
|
||||||
match records.binary_search_index(&key) {
|
match records.binary_search_index(&key) {
|
||||||
None => fail!(~"Invalid index not found in detailed glyph lookup table!"),
|
None => fail!(~"Invalid index not found in detailed glyph lookup table!"),
|
||||||
Some(i) => {
|
Some(i) => {
|
||||||
|
@ -399,7 +402,7 @@ impl DetailedGlyphStore {
|
||||||
// immutable locations thus don't play well with freezing.
|
// immutable locations thus don't play well with freezing.
|
||||||
|
|
||||||
// Thar be dragons here. You have been warned. (Tips accepted.)
|
// Thar be dragons here. You have been warned. (Tips accepted.)
|
||||||
let mut unsorted_records : ~[DetailedGlyphRecord] = ~[];
|
let mut unsorted_records: ~[DetailedGlyphRecord] = ~[];
|
||||||
core::util::swap(&mut self.detail_lookup, &mut unsorted_records);
|
core::util::swap(&mut self.detail_lookup, &mut unsorted_records);
|
||||||
let mut mut_records : ~[DetailedGlyphRecord] = unsorted_records;
|
let mut mut_records : ~[DetailedGlyphRecord] = unsorted_records;
|
||||||
sort::quick_sort3(mut_records);
|
sort::quick_sort3(mut_records);
|
||||||
|
@ -421,24 +424,27 @@ pub struct GlyphData {
|
||||||
ligature_start: bool,
|
ligature_start: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GlyphData(index: GlyphIndex,
|
impl GlyphData {
|
||||||
advance: Au,
|
pub fn new(index: GlyphIndex,
|
||||||
offset: Option<Point2D<Au>>,
|
advance: Au,
|
||||||
is_missing: bool,
|
offset: Option<Point2D<Au>>,
|
||||||
cluster_start: bool,
|
is_missing: bool,
|
||||||
ligature_start: bool) -> GlyphData {
|
cluster_start: bool,
|
||||||
let _offset = match offset {
|
ligature_start: bool)
|
||||||
None => geometry::zero_point(),
|
-> GlyphData {
|
||||||
Some(o) => o
|
let offset = match offset {
|
||||||
};
|
None => geometry::zero_point(),
|
||||||
|
Some(o) => o
|
||||||
|
};
|
||||||
|
|
||||||
GlyphData {
|
GlyphData {
|
||||||
index: index,
|
index: index,
|
||||||
advance: advance,
|
advance: advance,
|
||||||
offset: _offset,
|
offset: offset,
|
||||||
is_missing: is_missing,
|
is_missing: is_missing,
|
||||||
cluster_start: cluster_start,
|
cluster_start: cluster_start,
|
||||||
ligature_start: ligature_start,
|
ligature_start: ligature_start,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,7 +461,9 @@ impl<'self> GlyphInfo<'self> {
|
||||||
fn index(self) -> GlyphIndex {
|
fn index(self) -> GlyphIndex {
|
||||||
match self {
|
match self {
|
||||||
SimpleGlyphInfo(store, entry_i) => store.entry_buffer[entry_i].index(),
|
SimpleGlyphInfo(store, entry_i) => store.entry_buffer[entry_i].index(),
|
||||||
DetailGlyphInfo(store, entry_i, detail_j) => store.detail_store.get_detailed_glyph_with_index(entry_i, detail_j).index
|
DetailGlyphInfo(store, entry_i, detail_j) => {
|
||||||
|
store.detail_store.get_detailed_glyph_with_index(entry_i, detail_j).index
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,14 +471,18 @@ impl<'self> GlyphInfo<'self> {
|
||||||
fn advance(self) -> Au {
|
fn advance(self) -> Au {
|
||||||
match self {
|
match self {
|
||||||
SimpleGlyphInfo(store, entry_i) => store.entry_buffer[entry_i].advance(),
|
SimpleGlyphInfo(store, entry_i) => store.entry_buffer[entry_i].advance(),
|
||||||
DetailGlyphInfo(store, entry_i, detail_j) => store.detail_store.get_detailed_glyph_with_index(entry_i, detail_j).advance
|
DetailGlyphInfo(store, entry_i, detail_j) => {
|
||||||
|
store.detail_store.get_detailed_glyph_with_index(entry_i, detail_j).advance
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn offset(self) -> Option<Point2D<Au>> {
|
fn offset(self) -> Option<Point2D<Au>> {
|
||||||
match self {
|
match self {
|
||||||
SimpleGlyphInfo(_, _) => None,
|
SimpleGlyphInfo(_, _) => None,
|
||||||
DetailGlyphInfo(store, entry_i, detail_j) => Some(store.detail_store.get_detailed_glyph_with_index(entry_i, detail_j).offset)
|
DetailGlyphInfo(store, entry_i, detail_j) => {
|
||||||
|
Some(store.detail_store.get_detailed_glyph_with_index(entry_i, detail_j).offset)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,7 +503,6 @@ impl<'self> GlyphInfo<'self> {
|
||||||
|
|
||||||
// Public data structure and API for storing and retrieving glyph data
|
// Public data structure and API for storing and retrieving glyph data
|
||||||
pub struct GlyphStore {
|
pub struct GlyphStore {
|
||||||
// we use a DVec here instead of a mut vec, since this is much safer.
|
|
||||||
entry_buffer: ~[GlyphEntry],
|
entry_buffer: ~[GlyphEntry],
|
||||||
detail_store: DetailedGlyphStore,
|
detail_store: DetailedGlyphStore,
|
||||||
}
|
}
|
||||||
|
@ -503,8 +514,8 @@ pub impl GlyphStore {
|
||||||
assert!(length > 0);
|
assert!(length > 0);
|
||||||
|
|
||||||
GlyphStore {
|
GlyphStore {
|
||||||
entry_buffer: vec::from_elem(length, InitialGlyphEntry()),
|
entry_buffer: vec::from_elem(length, GlyphEntry::initial()),
|
||||||
detail_store: DetailedGlyphStore(),
|
detail_store: DetailedGlyphStore::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,7 +524,6 @@ pub impl GlyphStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_glyph_for_char_index(&mut self, i: uint, data: &GlyphData) {
|
fn add_glyph_for_char_index(&mut self, i: uint, data: &GlyphData) {
|
||||||
|
|
||||||
fn glyph_is_compressible(data: &GlyphData) -> bool {
|
fn glyph_is_compressible(data: &GlyphData) -> bool {
|
||||||
is_simple_glyph_id(data.index)
|
is_simple_glyph_id(data.index)
|
||||||
&& is_simple_advance(data.advance)
|
&& is_simple_advance(data.advance)
|
||||||
|
@ -525,12 +535,12 @@ pub impl GlyphStore {
|
||||||
assert!(i < self.entry_buffer.len());
|
assert!(i < self.entry_buffer.len());
|
||||||
|
|
||||||
let entry = match (data.is_missing, glyph_is_compressible(data)) {
|
let entry = match (data.is_missing, glyph_is_compressible(data)) {
|
||||||
(true, _) => MissingGlyphsEntry(1),
|
(true, _) => GlyphEntry::missing(1),
|
||||||
(false, true) => { SimpleGlyphEntry(data.index, data.advance) },
|
(false, true) => GlyphEntry::simple(data.index, data.advance),
|
||||||
(false, false) => {
|
(false, false) => {
|
||||||
let glyph = [DetailedGlyph(data.index, data.advance, data.offset)];
|
let glyph = [DetailedGlyph::new(data.index, data.advance, data.offset)];
|
||||||
self.detail_store.add_detailed_glyphs_for_entry(i, glyph);
|
self.detail_store.add_detailed_glyphs_for_entry(i, glyph);
|
||||||
ComplexGlyphEntry(data.cluster_start, data.ligature_start, 1)
|
GlyphEntry::complex(data.cluster_start, data.ligature_start, 1)
|
||||||
}
|
}
|
||||||
}.adapt_character_flags_of_entry(self.entry_buffer[i]);
|
}.adapt_character_flags_of_entry(self.entry_buffer[i]);
|
||||||
|
|
||||||
|
@ -545,18 +555,18 @@ pub impl GlyphStore {
|
||||||
|
|
||||||
let first_glyph_data = data_for_glyphs[0];
|
let first_glyph_data = data_for_glyphs[0];
|
||||||
let entry = match first_glyph_data.is_missing {
|
let entry = match first_glyph_data.is_missing {
|
||||||
true => MissingGlyphsEntry(glyph_count),
|
true => GlyphEntry::missing(glyph_count),
|
||||||
false => {
|
false => {
|
||||||
let glyphs_vec = vec::from_fn(glyph_count, |i| {
|
let glyphs_vec = vec::from_fn(glyph_count, |i| {
|
||||||
DetailedGlyph(data_for_glyphs[i].index,
|
DetailedGlyph::new(data_for_glyphs[i].index,
|
||||||
data_for_glyphs[i].advance,
|
data_for_glyphs[i].advance,
|
||||||
data_for_glyphs[i].offset)
|
data_for_glyphs[i].offset)
|
||||||
});
|
});
|
||||||
|
|
||||||
self.detail_store.add_detailed_glyphs_for_entry(i, glyphs_vec);
|
self.detail_store.add_detailed_glyphs_for_entry(i, glyphs_vec);
|
||||||
ComplexGlyphEntry(first_glyph_data.cluster_start,
|
GlyphEntry::complex(first_glyph_data.cluster_start,
|
||||||
first_glyph_data.ligature_start,
|
first_glyph_data.ligature_start,
|
||||||
glyph_count)
|
glyph_count)
|
||||||
}
|
}
|
||||||
}.adapt_character_flags_of_entry(self.entry_buffer[i]);
|
}.adapt_character_flags_of_entry(self.entry_buffer[i]);
|
||||||
|
|
||||||
|
@ -569,13 +579,16 @@ pub impl GlyphStore {
|
||||||
fn add_nonglyph_for_char_index(&mut self, i: uint, cluster_start: bool, ligature_start: bool) {
|
fn add_nonglyph_for_char_index(&mut self, i: uint, cluster_start: bool, ligature_start: bool) {
|
||||||
assert!(i < self.entry_buffer.len());
|
assert!(i < self.entry_buffer.len());
|
||||||
|
|
||||||
let entry = ComplexGlyphEntry(cluster_start, ligature_start, 0);
|
let entry = GlyphEntry::complex(cluster_start, ligature_start, 0);
|
||||||
debug!("adding spacer for chracter without associated glyph[idx=%u]", i);
|
debug!("adding spacer for chracter without associated glyph[idx=%u]", i);
|
||||||
|
|
||||||
self.entry_buffer[i] = entry;
|
self.entry_buffer[i] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_glyphs_for_char_index(&self, i: uint, cb: &fn(uint, &GlyphInfo<'self>) -> bool) -> bool {
|
fn iter_glyphs_for_char_index(&self,
|
||||||
|
i: uint,
|
||||||
|
cb: &fn(uint, &GlyphInfo<'self>) -> bool)
|
||||||
|
-> bool {
|
||||||
assert!(i < self.entry_buffer.len());
|
assert!(i < self.entry_buffer.len());
|
||||||
|
|
||||||
let entry = &self.entry_buffer[i];
|
let entry = &self.entry_buffer[i];
|
||||||
|
@ -593,7 +606,7 @@ pub impl GlyphStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_glyphs_for_char_range(&self, range: &Range, cb: &fn(uint, &GlyphInfo<'self>) -> bool) {
|
fn iter_glyphs_for_char_range(&self, range: &Range, cb: &fn(uint, &GlyphInfo<'self>) -> bool) {
|
||||||
|
@ -607,13 +620,17 @@ pub impl GlyphStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
for range.eachi |i| {
|
for range.eachi |i| {
|
||||||
if !self.iter_glyphs_for_char_index(i, cb) { break; }
|
if !self.iter_glyphs_for_char_index(i, cb) {
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_all_glyphs(&self, cb: &fn(uint, &GlyphInfo<'self>) -> bool) {
|
fn iter_all_glyphs(&self, cb: &fn(uint, &GlyphInfo<'self>) -> bool) {
|
||||||
for uint::range(0, self.entry_buffer.len()) |i| {
|
for uint::range(0, self.entry_buffer.len()) |i| {
|
||||||
if !self.iter_glyphs_for_char_index(i, cb) { break; }
|
if !self.iter_glyphs_for_char_index(i, cb) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,16 +8,12 @@
|
||||||
Note that you still must define each of the files as a module in
|
Note that you still must define each of the files as a module in
|
||||||
servo.rc. This is not ideal and may be changed in the future. */
|
servo.rc. This is not ideal and may be changed in the future. */
|
||||||
|
|
||||||
pub use text::shaper::Shaper;
|
pub use text::shaping::Shaper;
|
||||||
pub use text::text_run::TextRun;
|
|
||||||
pub use text::text_run::SendableTextRun;
|
pub use text::text_run::SendableTextRun;
|
||||||
|
pub use text::text_run::TextRun;
|
||||||
|
|
||||||
pub mod glyph;
|
pub mod glyph;
|
||||||
|
#[path="shaping/mod.rs"] pub mod shaping;
|
||||||
pub mod text_run;
|
pub mod text_run;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
pub mod shaper;
|
|
||||||
|
|
||||||
// Below are the actual platform-specific parts.
|
|
||||||
pub mod harfbuzz {
|
|
||||||
pub mod shaper;
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,62 +6,59 @@ extern mod harfbuzz;
|
||||||
|
|
||||||
use geom::Point2D;
|
use geom::Point2D;
|
||||||
|
|
||||||
|
use font::{Font, FontHandleMethods, FontTableMethods, FontTableTag};
|
||||||
use geometry::Au;
|
use geometry::Au;
|
||||||
|
use platform::font::FontTable;
|
||||||
use font::{Font, FontTable, FontTableMethods, FontTableTag};
|
|
||||||
|
|
||||||
use text::glyph::{GlyphStore, GlyphIndex, GlyphData};
|
use text::glyph::{GlyphStore, GlyphIndex, GlyphData};
|
||||||
use text::shaper::ShaperMethods;
|
use text::shaping::ShaperMethods;
|
||||||
use gfx_font::{FontHandleMethods, FontTableMethods};
|
|
||||||
|
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
|
|
||||||
use core::libc::{c_uint, c_int, c_void, c_char};
|
|
||||||
use core::util::ignore;
|
|
||||||
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::{HB_MEMORY_MODE_READONLY, HB_DIRECTION_LTR, hb_blob_t};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::{hb_face_t, hb_font_t};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::{hb_font_funcs_t, hb_buffer_t, hb_codepoint_t, hb_bool_t};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::{hb_glyph_position_t};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::{hb_glyph_info_t, hb_position_t};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::hb_blob_create;
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::hb_face_destroy;
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_create, hb_font_destroy};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_create};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_destroy};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_add_utf8, hb_shape};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_get_glyph_infos};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_get_glyph_positions};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_set_ppem};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_set_scale};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_buffer_set_direction};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_funcs_create};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_funcs_destroy};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_set_funcs};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_funcs_set_glyph_h_advance_func};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_font_funcs_set_glyph_func};
|
|
||||||
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::{HB_MEMORY_MODE_READONLY, HB_DIRECTION_LTR};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::{hb_blob_t, hb_face_t, hb_font_t, hb_font_funcs_t};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::{hb_buffer_t, hb_codepoint_t, hb_bool_t};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::{hb_glyph_position_t, hb_glyph_info_t};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::{hb_position_t, hb_tag_t};
|
|
||||||
use text::harfbuzz::shaper::harfbuzz::bindgen::{hb_blob_create,
|
|
||||||
hb_face_create_for_tables, hb_face_destroy,
|
|
||||||
hb_font_create, hb_font_destroy,
|
|
||||||
hb_buffer_create, hb_buffer_destroy,
|
|
||||||
hb_buffer_add_utf8, hb_shape,
|
|
||||||
hb_buffer_get_glyph_infos,
|
|
||||||
hb_buffer_get_glyph_positions,
|
|
||||||
hb_font_set_ppem, hb_font_set_scale,
|
|
||||||
hb_buffer_set_direction,
|
|
||||||
hb_font_funcs_create, hb_font_funcs_destroy,
|
|
||||||
hb_font_set_funcs,
|
|
||||||
hb_font_funcs_set_glyph_h_advance_func,
|
|
||||||
hb_font_funcs_set_glyph_func};
|
|
||||||
|
|
||||||
use text::util::{float_to_fixed, fixed_to_float, fixed_to_rounded_int};
|
use text::util::{float_to_fixed, fixed_to_float, fixed_to_rounded_int};
|
||||||
|
|
||||||
|
use core::cast::transmute;
|
||||||
|
use core::libc::{c_uint, c_int, c_void, c_char};
|
||||||
|
use core::ptr::null;
|
||||||
|
use core::util::ignore;
|
||||||
|
use geom::Point2D;
|
||||||
|
use harfbuzz::bindgen::{hb_blob_create, hb_face_create_for_tables};
|
||||||
|
use harfbuzz::bindgen::{hb_buffer_add_utf8, hb_shape};
|
||||||
|
use harfbuzz::bindgen::{hb_buffer_create};
|
||||||
|
use harfbuzz::bindgen::{hb_buffer_destroy, hb_buffer_add_utf8};
|
||||||
|
use harfbuzz::bindgen::{hb_buffer_get_glyph_infos};
|
||||||
|
use harfbuzz::bindgen::{hb_buffer_get_glyph_positions};
|
||||||
|
use harfbuzz::bindgen::{hb_buffer_get_glyph_positions};
|
||||||
|
use harfbuzz::bindgen::{hb_buffer_set_direction};
|
||||||
|
use harfbuzz::bindgen::{hb_buffer_set_direction};
|
||||||
|
use harfbuzz::bindgen::{hb_face_destroy, hb_font_create};
|
||||||
|
use harfbuzz::bindgen::{hb_face_destroy};
|
||||||
|
use harfbuzz::bindgen::{hb_font_create, hb_font_destroy};
|
||||||
|
use harfbuzz::bindgen::{hb_font_destroy, hb_buffer_create};
|
||||||
|
use harfbuzz::bindgen::{hb_font_funcs_create, hb_font_funcs_destroy};
|
||||||
|
use harfbuzz::bindgen::{hb_font_funcs_create};
|
||||||
|
use harfbuzz::bindgen::{hb_font_funcs_destroy};
|
||||||
|
use harfbuzz::bindgen::{hb_font_funcs_set_glyph_func};
|
||||||
|
use harfbuzz::bindgen::{hb_font_funcs_set_glyph_func};
|
||||||
|
use harfbuzz::bindgen::{hb_font_funcs_set_glyph_h_advance_func};
|
||||||
|
use harfbuzz::bindgen::{hb_font_funcs_set_glyph_h_advance_func};
|
||||||
|
use harfbuzz::bindgen::{hb_font_set_funcs};
|
||||||
|
use harfbuzz::bindgen::{hb_font_set_funcs};
|
||||||
|
use harfbuzz::bindgen::{hb_font_set_ppem, hb_font_set_scale};
|
||||||
|
use harfbuzz::bindgen::{hb_font_set_ppem};
|
||||||
|
use harfbuzz::bindgen::{hb_font_set_scale};
|
||||||
|
use harfbuzz::bindgen::{hb_shape, hb_buffer_get_glyph_infos};
|
||||||
|
use harfbuzz::{HB_MEMORY_MODE_READONLY, HB_DIRECTION_LTR, hb_blob_t};
|
||||||
|
use harfbuzz::{HB_MEMORY_MODE_READONLY, HB_DIRECTION_LTR};
|
||||||
|
use harfbuzz::{hb_blob_t, hb_face_t, hb_font_t, hb_font_funcs_t};
|
||||||
|
use harfbuzz::{hb_buffer_t, hb_codepoint_t, hb_bool_t};
|
||||||
|
use harfbuzz::{hb_face_t, hb_font_t};
|
||||||
|
use harfbuzz::{hb_font_funcs_t, hb_buffer_t, hb_codepoint_t};
|
||||||
|
use harfbuzz::{hb_glyph_info_t, hb_position_t};
|
||||||
|
use harfbuzz::{hb_glyph_position_t, hb_glyph_info_t};
|
||||||
|
use harfbuzz::{hb_glyph_position_t};
|
||||||
|
use harfbuzz::{hb_position_t, hb_tag_t};
|
||||||
|
|
||||||
|
static NO_GLYPH: i32 = -1;
|
||||||
|
static CONTINUATION_BYTE: i32 = -2;
|
||||||
|
|
||||||
pub struct ShapedGlyphData {
|
pub struct ShapedGlyphData {
|
||||||
count: uint,
|
count: uint,
|
||||||
glyph_infos: *hb_glyph_info_t,
|
glyph_infos: *hb_glyph_info_t,
|
||||||
|
@ -75,15 +72,15 @@ pub struct ShapedGlyphEntry {
|
||||||
offset: Option<Point2D<Au>>,
|
offset: Option<Point2D<Au>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl ShapedGlyphData {
|
impl ShapedGlyphData {
|
||||||
fn new(buffer: *hb_buffer_t) -> ShapedGlyphData {
|
pub fn new(buffer: *hb_buffer_t) -> ShapedGlyphData {
|
||||||
unsafe {
|
unsafe {
|
||||||
let glyph_count = 0 as c_uint;
|
let glyph_count = 0;
|
||||||
let glyph_infos = hb_buffer_get_glyph_infos(buffer, ptr::to_unsafe_ptr(&glyph_count));
|
let glyph_infos = hb_buffer_get_glyph_infos(buffer, &glyph_count);
|
||||||
let glyph_count = glyph_count as uint;
|
let glyph_count = glyph_count as uint;
|
||||||
assert!(glyph_infos.is_not_null());
|
assert!(glyph_infos.is_not_null());
|
||||||
let pos_count = 0 as c_uint;
|
let pos_count = 0;
|
||||||
let pos_infos = hb_buffer_get_glyph_positions(buffer, ptr::to_unsafe_ptr(&pos_count));
|
let pos_infos = hb_buffer_get_glyph_positions(buffer, &pos_count);
|
||||||
assert!(pos_infos.is_not_null());
|
assert!(pos_infos.is_not_null());
|
||||||
assert!(glyph_count == pos_count as uint);
|
assert!(glyph_count == pos_count as uint);
|
||||||
|
|
||||||
|
@ -96,7 +93,7 @@ pub impl ShapedGlyphData {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
priv fn byte_offset_of_glyph(&self, i: uint) -> uint {
|
fn byte_offset_of_glyph(&self, i: uint) -> uint {
|
||||||
assert!(i < self.count);
|
assert!(i < self.count);
|
||||||
|
|
||||||
let glyph_info_i = ptr::offset(self.glyph_infos, i);
|
let glyph_info_i = ptr::offset(self.glyph_infos, i);
|
||||||
|
@ -105,31 +102,38 @@ pub impl ShapedGlyphData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn len(&self) -> uint { self.count }
|
pub fn len(&self) -> uint {
|
||||||
|
self.count
|
||||||
|
}
|
||||||
|
|
||||||
// Returns shaped glyph data for one glyph, and updates the y-position of the pen.
|
/// Returns shaped glyph data for one glyph, and updates the y-position of the pen.
|
||||||
fn get_entry_for_glyph(&self, i: uint, y_pos: &mut Au) -> ShapedGlyphEntry {
|
pub fn get_entry_for_glyph(&self, i: uint, y_pos: &mut Au) -> ShapedGlyphEntry {
|
||||||
assert!(i < self.count);
|
assert!(i < self.count);
|
||||||
|
|
||||||
let glyph_info_i = ptr::offset(self.glyph_infos, i);
|
|
||||||
let pos_info_i = ptr::offset(self.pos_infos, i);
|
|
||||||
let x_offset = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_i).x_offset)) };
|
|
||||||
let y_offset = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_i).y_offset)) };
|
|
||||||
let x_advance = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_i).x_advance)) };
|
|
||||||
let y_advance = unsafe { Au::from_frac_px(HarfbuzzShaper::fixed_to_float((*pos_info_i).y_advance)) };
|
|
||||||
let offset = if x_offset == Au(0)
|
|
||||||
&& y_offset == Au(0)
|
|
||||||
&& y_advance == Au(0) { None }
|
|
||||||
else {
|
|
||||||
// adjust the pen..
|
|
||||||
if y_advance > Au(0) {
|
|
||||||
*y_pos -= y_advance;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Point2D(x_offset, *y_pos - y_offset))
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let glyph_info_i = ptr::offset(self.glyph_infos, i);
|
||||||
|
let pos_info_i = ptr::offset(self.pos_infos, i);
|
||||||
|
let x_offset = Shaper::fixed_to_float((*pos_info_i).x_offset);
|
||||||
|
let y_offset = Shaper::fixed_to_float((*pos_info_i).y_offset);
|
||||||
|
let x_advance = Shaper::fixed_to_float((*pos_info_i).x_advance);
|
||||||
|
let y_advance = Shaper::fixed_to_float((*pos_info_i).y_advance);
|
||||||
|
|
||||||
|
let x_offset = Au::from_frac_px(x_offset);
|
||||||
|
let y_offset = Au::from_frac_px(y_offset);
|
||||||
|
let x_advance = Au::from_frac_px(x_advance);
|
||||||
|
let y_advance = Au::from_frac_px(y_advance);
|
||||||
|
|
||||||
|
let offset = if x_offset == Au(0) && y_offset == Au(0) && y_advance == Au(0) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// adjust the pen..
|
||||||
|
if y_advance > Au(0) {
|
||||||
|
*y_pos -= y_advance;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Point2D(x_offset, *y_pos - y_offset))
|
||||||
|
};
|
||||||
|
|
||||||
ShapedGlyphEntry {
|
ShapedGlyphEntry {
|
||||||
cluster: (*glyph_info_i).cluster as uint,
|
cluster: (*glyph_info_i).cluster as uint,
|
||||||
codepoint: (*glyph_info_i).codepoint as GlyphIndex,
|
codepoint: (*glyph_info_i).codepoint as GlyphIndex,
|
||||||
|
@ -140,7 +144,7 @@ pub impl ShapedGlyphData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HarfbuzzShaper {
|
pub struct Shaper {
|
||||||
font: @mut Font,
|
font: @mut Font,
|
||||||
priv hb_face: *hb_face_t,
|
priv hb_face: *hb_face_t,
|
||||||
priv hb_font: *hb_font_t,
|
priv hb_font: *hb_font_t,
|
||||||
|
@ -148,7 +152,7 @@ pub struct HarfbuzzShaper {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe_destructor]
|
#[unsafe_destructor]
|
||||||
impl Drop for HarfbuzzShaper {
|
impl Drop for Shaper {
|
||||||
fn finalize(&self) {
|
fn finalize(&self) {
|
||||||
assert!(self.hb_face.is_not_null());
|
assert!(self.hb_face.is_not_null());
|
||||||
hb_face_destroy(self.hb_face);
|
hb_face_destroy(self.hb_face);
|
||||||
|
@ -161,102 +165,106 @@ impl Drop for HarfbuzzShaper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl HarfbuzzShaper {
|
impl Shaper {
|
||||||
pub fn new(font: @mut Font) -> HarfbuzzShaper {
|
pub fn new(font: @mut Font) -> Shaper {
|
||||||
let hb_face: *hb_face_t = hb_face_create_for_tables(get_font_table_func, ptr::to_unsafe_ptr(font) as *c_void, ptr::null());
|
|
||||||
let hb_font: *hb_font_t = hb_font_create(hb_face);
|
|
||||||
// Set points-per-em. if zero, performs no hinting in that direction.
|
|
||||||
let pt_size = font.style.pt_size;
|
|
||||||
hb_font_set_ppem(hb_font, pt_size as c_uint, pt_size as c_uint);
|
|
||||||
// Set scaling. Note that this takes 16.16 fixed point.
|
|
||||||
hb_font_set_scale(hb_font,
|
|
||||||
HarfbuzzShaper::float_to_fixed(pt_size) as c_int,
|
|
||||||
HarfbuzzShaper::float_to_fixed(pt_size) as c_int);
|
|
||||||
|
|
||||||
// configure static function callbacks.
|
|
||||||
// NB. This funcs structure could be reused globally, as it never changes.
|
|
||||||
let hb_funcs: *hb_font_funcs_t = hb_font_funcs_create();
|
|
||||||
hb_font_funcs_set_glyph_func(hb_funcs, glyph_func, ptr::null(), ptr::null());
|
|
||||||
hb_font_funcs_set_glyph_h_advance_func(hb_funcs, glyph_h_advance_func, ptr::null(), ptr::null());
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let font_data: *c_void = ptr::addr_of(font) as *c_void;
|
let font_ptr: *mut Font = &mut *font;
|
||||||
hb_font_set_funcs(hb_font, hb_funcs, font_data, ptr::null());
|
let hb_face: *hb_face_t = hb_face_create_for_tables(get_font_table_func,
|
||||||
};
|
font_ptr as *c_void,
|
||||||
|
null());
|
||||||
|
let hb_font: *hb_font_t = hb_font_create(hb_face);
|
||||||
|
|
||||||
HarfbuzzShaper {
|
// Set points-per-em. if zero, performs no hinting in that direction.
|
||||||
font: font,
|
let pt_size = font.style.pt_size;
|
||||||
hb_face: hb_face,
|
hb_font_set_ppem(hb_font, pt_size as c_uint, pt_size as c_uint);
|
||||||
hb_font: hb_font,
|
|
||||||
hb_funcs: hb_funcs,
|
// Set scaling. Note that this takes 16.16 fixed point.
|
||||||
|
hb_font_set_scale(hb_font,
|
||||||
|
Shaper::float_to_fixed(pt_size) as c_int,
|
||||||
|
Shaper::float_to_fixed(pt_size) as c_int);
|
||||||
|
|
||||||
|
// configure static function callbacks.
|
||||||
|
// NB. This funcs structure could be reused globally, as it never changes.
|
||||||
|
let hb_funcs: *hb_font_funcs_t = hb_font_funcs_create();
|
||||||
|
hb_font_funcs_set_glyph_func(hb_funcs, glyph_func, null(), null());
|
||||||
|
hb_font_funcs_set_glyph_h_advance_func(hb_funcs, glyph_h_advance_func, null(), null());
|
||||||
|
hb_font_set_funcs(hb_font, hb_funcs, font_ptr as *c_void, null());
|
||||||
|
|
||||||
|
Shaper {
|
||||||
|
font: font,
|
||||||
|
hb_face: hb_face,
|
||||||
|
hb_font: hb_font,
|
||||||
|
hb_funcs: hb_funcs,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn float_to_fixed(f: float) -> i32 {
|
fn float_to_fixed(f: float) -> i32 {
|
||||||
float_to_fixed(16, f)
|
float_to_fixed(16, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn fixed_to_float(i: hb_position_t) -> float {
|
fn fixed_to_float(i: hb_position_t) -> float {
|
||||||
fixed_to_float(16, i)
|
fixed_to_float(16, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn fixed_to_rounded_int(f: hb_position_t) -> int {
|
fn fixed_to_rounded_int(f: hb_position_t) -> int {
|
||||||
fixed_to_rounded_int(16, f)
|
fixed_to_rounded_int(16, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShaperMethods for HarfbuzzShaper {
|
impl ShaperMethods for Shaper {
|
||||||
/**
|
/// Calculate the layout metrics associated with the given text when rendered in a specific
|
||||||
Calculate the layout metrics associated with a some given text
|
/// font.
|
||||||
when rendered in a specific font.
|
|
||||||
*/
|
|
||||||
fn shape_text(&self, text: &str, glyphs: &mut GlyphStore) {
|
fn shape_text(&self, text: &str, glyphs: &mut GlyphStore) {
|
||||||
let hb_buffer: *hb_buffer_t = hb_buffer_create();
|
let hb_buffer: *hb_buffer_t = hb_buffer_create();
|
||||||
hb_buffer_set_direction(hb_buffer, HB_DIRECTION_LTR);
|
hb_buffer_set_direction(hb_buffer, HB_DIRECTION_LTR);
|
||||||
|
|
||||||
// Using as_buf because it never does a copy - we don't need the trailing null
|
// Using as_buf because it never does a copy - we don't need the trailing null
|
||||||
str::as_buf(text, |ctext: *u8, _l: uint| {
|
do str::as_buf(text) |ctext: *u8, _: uint| {
|
||||||
hb_buffer_add_utf8(hb_buffer,
|
hb_buffer_add_utf8(hb_buffer,
|
||||||
ctext as *c_char,
|
ctext as *c_char,
|
||||||
text.len() as c_int,
|
text.len() as c_int,
|
||||||
0 as c_uint,
|
0,
|
||||||
text.len() as c_int);
|
text.len() as c_int);
|
||||||
});
|
}
|
||||||
|
|
||||||
hb_shape(self.hb_font, hb_buffer, ptr::null(), 0 as c_uint);
|
hb_shape(self.hb_font, hb_buffer, null(), 0);
|
||||||
self.save_glyph_results(text, glyphs, hb_buffer);
|
self.save_glyph_results(text, glyphs, hb_buffer);
|
||||||
hb_buffer_destroy(hb_buffer);
|
hb_buffer_destroy(hb_buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl HarfbuzzShaper {
|
impl Shaper {
|
||||||
|
fn save_glyph_results(&self, text: &str, glyphs: &mut GlyphStore, buffer: *hb_buffer_t) {
|
||||||
priv fn save_glyph_results(&self, text: &str, glyphs: &mut GlyphStore, buffer: *hb_buffer_t) {
|
|
||||||
let glyph_data = ShapedGlyphData::new(buffer);
|
let glyph_data = ShapedGlyphData::new(buffer);
|
||||||
let glyph_count = glyph_data.len();
|
let glyph_count = glyph_data.len();
|
||||||
let byte_max = text.len();
|
let byte_max = text.len();
|
||||||
let char_max = str::char_len(text);
|
let char_max = str::char_len(text);
|
||||||
|
|
||||||
// GlyphStore records are indexed by character, not byte offset.
|
// GlyphStore records are indexed by character, not byte offset.
|
||||||
// so, we must be careful to increment this when saving glyph entries.
|
// so, we must be careful to increment this when saving glyph entries.
|
||||||
let mut char_idx = 0;
|
let mut char_idx = 0;
|
||||||
|
|
||||||
assert!(glyph_count <= char_max);
|
assert!(glyph_count <= char_max);
|
||||||
|
|
||||||
debug!("Shaped text[char count=%u], got back %u glyph info records.", char_max, glyph_count);
|
debug!("Shaped text[char count=%u], got back %u glyph info records.",
|
||||||
|
char_max,
|
||||||
|
glyph_count);
|
||||||
|
|
||||||
if char_max != glyph_count {
|
if char_max != glyph_count {
|
||||||
debug!("NOTE: Since these are not equal, we probably have been given some complex glyphs.");
|
debug!("NOTE: Since these are not equal, we probably have been given some complex \
|
||||||
|
glyphs.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// make map of what chars have glyphs
|
// make map of what chars have glyphs
|
||||||
static NO_GLYPH : i32 = -1;
|
let mut byteToGlyph: ~[i32];
|
||||||
static CONTINUATION_BYTE : i32 = -2;
|
|
||||||
let mut byteToGlyph : ~[i32];
|
|
||||||
|
|
||||||
// fast path: all chars are single-byte.
|
// fast path: all chars are single-byte.
|
||||||
if byte_max == char_max {
|
if byte_max == char_max {
|
||||||
byteToGlyph = vec::from_elem(byte_max, NO_GLYPH);
|
byteToGlyph = vec::from_elem(byte_max, NO_GLYPH);
|
||||||
} else {
|
} else {
|
||||||
byteToGlyph = vec::from_elem(byte_max, CONTINUATION_BYTE);
|
byteToGlyph = vec::from_elem(byte_max, CONTINUATION_BYTE);
|
||||||
let mut i = 0u;
|
let mut i = 0;
|
||||||
while i < byte_max {
|
while i < byte_max {
|
||||||
byteToGlyph[i] = NO_GLYPH;
|
byteToGlyph[i] = NO_GLYPH;
|
||||||
let range = str::char_range_at(text, i);
|
let range = str::char_range_at(text, i);
|
||||||
|
@ -272,8 +280,11 @@ pub impl HarfbuzzShaper {
|
||||||
if loc < byte_max {
|
if loc < byte_max {
|
||||||
assert!(byteToGlyph[loc] != CONTINUATION_BYTE);
|
assert!(byteToGlyph[loc] != CONTINUATION_BYTE);
|
||||||
byteToGlyph[loc] = i as i32;
|
byteToGlyph[loc] = i as i32;
|
||||||
|
} else {
|
||||||
|
debug!("ERROR: tried to set out of range byteToGlyph: idx=%u, glyph idx=%u",
|
||||||
|
loc,
|
||||||
|
i);
|
||||||
}
|
}
|
||||||
else { debug!("ERROR: tried to set out of range byteToGlyph: idx=%u, glyph idx=%u", loc, i); }
|
|
||||||
debug!("%u -> %u", i, loc);
|
debug!("%u -> %u", i, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,14 +298,15 @@ pub impl HarfbuzzShaper {
|
||||||
}
|
}
|
||||||
|
|
||||||
// some helpers
|
// some helpers
|
||||||
let mut glyph_span : Range = Range::empty();
|
let mut glyph_span: Range = Range::empty();
|
||||||
// this span contains first byte of first char, to last byte of last char in range.
|
// this span contains first byte of first char, to last byte of last char in range.
|
||||||
// so, end() points to first byte of last+1 char, if it's less than byte_max.
|
// so, end() points to first byte of last+1 char, if it's less than byte_max.
|
||||||
let mut char_byte_span : Range = Range::empty();
|
let mut char_byte_span: Range = Range::empty();
|
||||||
let mut y_pos = Au(0);
|
let mut y_pos = Au(0);
|
||||||
|
|
||||||
// main loop over each glyph. each iteration usually processes 1 glyph and 1+ chars.
|
// main loop over each glyph. each iteration usually processes 1 glyph and 1+ chars.
|
||||||
// in cases with complex glyph-character assocations, 2+ glyphs and 1+ chars can be processed.
|
// in cases with complex glyph-character assocations, 2+ glyphs and 1+ chars can be
|
||||||
|
// processed.
|
||||||
while glyph_span.begin() < glyph_count {
|
while glyph_span.begin() < glyph_count {
|
||||||
// start by looking at just one glyph.
|
// start by looking at just one glyph.
|
||||||
glyph_span.extend_by(1);
|
glyph_span.extend_by(1);
|
||||||
|
@ -313,8 +325,10 @@ pub impl HarfbuzzShaper {
|
||||||
debug!("Processing char byte span: off=%u, len=%u for glyph idx=%u",
|
debug!("Processing char byte span: off=%u, len=%u for glyph idx=%u",
|
||||||
char_byte_span.begin(), char_byte_span.length(), glyph_span.begin());
|
char_byte_span.begin(), char_byte_span.length(), glyph_span.begin());
|
||||||
|
|
||||||
while char_byte_span.end() != byte_max && byteToGlyph[char_byte_span.end()] == NO_GLYPH {
|
while char_byte_span.end() != byte_max &&
|
||||||
debug!("Extending char byte span to include byte offset=%u with no associated glyph", char_byte_span.end());
|
byteToGlyph[char_byte_span.end()] == NO_GLYPH {
|
||||||
|
debug!("Extending char byte span to include byte offset=%u with no associated \
|
||||||
|
glyph", char_byte_span.end());
|
||||||
let range = str::char_range_at(text, char_byte_span.end());
|
let range = str::char_range_at(text, char_byte_span.end());
|
||||||
ignore(range.ch);
|
ignore(range.ch);
|
||||||
char_byte_span.extend_to(range.next);
|
char_byte_span.extend_to(range.next);
|
||||||
|
@ -331,7 +345,8 @@ pub impl HarfbuzzShaper {
|
||||||
|
|
||||||
if max_glyph_idx > glyph_span.end() {
|
if max_glyph_idx > glyph_span.end() {
|
||||||
glyph_span.extend_to(max_glyph_idx);
|
glyph_span.extend_to(max_glyph_idx);
|
||||||
debug!("Extended glyph span (off=%u, len=%u) to cover char byte span's max glyph index",
|
debug!("Extended glyph span (off=%u, len=%u) to cover char byte span's max \
|
||||||
|
glyph index",
|
||||||
glyph_span.begin(), glyph_span.length());
|
glyph_span.begin(), glyph_span.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,7 +357,8 @@ pub impl HarfbuzzShaper {
|
||||||
// if no glyphs were found yet, extend the char byte range more.
|
// if no glyphs were found yet, extend the char byte range more.
|
||||||
if glyph_span.length() == 0 { loop; }
|
if glyph_span.length() == 0 { loop; }
|
||||||
|
|
||||||
debug!("Complex (multi-glyph to multi-char) association found. This case probably doesn't work.");
|
debug!("Complex (multi-glyph to multi-char) association found. This case \
|
||||||
|
probably doesn't work.");
|
||||||
|
|
||||||
let mut all_glyphs_are_within_cluster: bool = true;
|
let mut all_glyphs_are_within_cluster: bool = true;
|
||||||
do glyph_span.eachi |j| {
|
do glyph_span.eachi |j| {
|
||||||
|
@ -353,7 +369,8 @@ pub impl HarfbuzzShaper {
|
||||||
all_glyphs_are_within_cluster // if true, keep checking. else, stop.
|
all_glyphs_are_within_cluster // if true, keep checking. else, stop.
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("All glyphs within char_byte_span cluster?: %?", all_glyphs_are_within_cluster);
|
debug!("All glyphs within char_byte_span cluster?: %?",
|
||||||
|
all_glyphs_are_within_cluster);
|
||||||
|
|
||||||
// found a valid range; stop extending char_span.
|
// found a valid range; stop extending char_span.
|
||||||
if all_glyphs_are_within_cluster { break; }
|
if all_glyphs_are_within_cluster { break; }
|
||||||
|
@ -375,10 +392,11 @@ pub impl HarfbuzzShaper {
|
||||||
// gspan: [-]
|
// gspan: [-]
|
||||||
// cspan: [-]
|
// cspan: [-]
|
||||||
// covsp: [---------------]
|
// covsp: [---------------]
|
||||||
|
|
||||||
let mut covered_byte_span = copy char_byte_span;
|
let mut covered_byte_span = copy char_byte_span;
|
||||||
// extend, clipping at end of text range.
|
// extend, clipping at end of text range.
|
||||||
while covered_byte_span.end() < byte_max
|
while covered_byte_span.end() < byte_max
|
||||||
&& byteToGlyph[covered_byte_span.end()] == NO_GLYPH {
|
&& byteToGlyph[covered_byte_span.end()] == NO_GLYPH {
|
||||||
let range = str::char_range_at(text, covered_byte_span.end());
|
let range = str::char_range_at(text, covered_byte_span.end());
|
||||||
ignore(range.ch);
|
ignore(range.ch);
|
||||||
covered_byte_span.extend_to(range.next);
|
covered_byte_span.extend_to(range.next);
|
||||||
|
@ -404,7 +422,12 @@ pub impl HarfbuzzShaper {
|
||||||
// (i.e., pretend there are no combining character sequences).
|
// (i.e., pretend there are no combining character sequences).
|
||||||
// 1-to-1 mapping of character to glyph also treated as ligature start.
|
// 1-to-1 mapping of character to glyph also treated as ligature start.
|
||||||
let shape = glyph_data.get_entry_for_glyph(glyph_span.begin(), &mut y_pos);
|
let shape = glyph_data.get_entry_for_glyph(glyph_span.begin(), &mut y_pos);
|
||||||
let data = GlyphData(shape.codepoint, shape.advance, shape.offset, false, true, true);
|
let data = GlyphData::new(shape.codepoint,
|
||||||
|
shape.advance,
|
||||||
|
shape.offset,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
glyphs.add_glyph_for_char_index(char_idx, &data);
|
glyphs.add_glyph_for_char_index(char_idx, &data);
|
||||||
} else {
|
} else {
|
||||||
// collect all glyphs to be assigned to the first character.
|
// collect all glyphs to be assigned to the first character.
|
||||||
|
@ -412,12 +435,13 @@ pub impl HarfbuzzShaper {
|
||||||
|
|
||||||
for glyph_span.eachi |glyph_i| {
|
for glyph_span.eachi |glyph_i| {
|
||||||
let shape = glyph_data.get_entry_for_glyph(glyph_i, &mut y_pos);
|
let shape = glyph_data.get_entry_for_glyph(glyph_i, &mut y_pos);
|
||||||
datas.push(GlyphData(shape.codepoint,
|
datas.push(GlyphData::new(shape.codepoint,
|
||||||
shape.advance,
|
shape.advance,
|
||||||
shape.offset,
|
shape.offset,
|
||||||
false, // not missing
|
false, // not missing
|
||||||
true, // treat as cluster start
|
true, // treat as cluster start
|
||||||
glyph_i > glyph_span.begin())); // all but first are ligature continuations
|
glyph_i > glyph_span.begin()));
|
||||||
|
// all but first are ligature continuations
|
||||||
}
|
}
|
||||||
|
|
||||||
// now add the detailed glyph entry.
|
// now add the detailed glyph entry.
|
||||||
|
@ -450,57 +474,65 @@ pub impl HarfbuzzShaper {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Callbacks from Harfbuzz when font map and glyph advance lookup needed.
|
/// Callbacks from Harfbuzz when font map and glyph advance lookup needed.
|
||||||
extern fn glyph_func(_font: *hb_font_t,
|
extern fn glyph_func(_: *hb_font_t,
|
||||||
font_data: *c_void,
|
font_data: *c_void,
|
||||||
unicode: hb_codepoint_t,
|
unicode: hb_codepoint_t,
|
||||||
_variant_selector: hb_codepoint_t,
|
_: hb_codepoint_t,
|
||||||
glyph: *mut hb_codepoint_t,
|
glyph: *mut hb_codepoint_t,
|
||||||
_user_data: *c_void) -> hb_bool_t {
|
_: *c_void)
|
||||||
|
-> hb_bool_t {
|
||||||
let font: *Font = font_data as *Font;
|
let font: *Font = font_data as *Font;
|
||||||
assert!(font.is_not_null());
|
assert!(font.is_not_null());
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
return match (*font).glyph_index(unicode as char) {
|
match (*font).glyph_index(unicode as char) {
|
||||||
Some(g) => { *glyph = g as hb_codepoint_t; true },
|
Some(g) => {
|
||||||
None => false
|
*glyph = g as hb_codepoint_t;
|
||||||
} as hb_bool_t;
|
true as hb_bool_t
|
||||||
|
}
|
||||||
|
None => false as hb_bool_t
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn glyph_h_advance_func(_font: *hb_font_t,
|
extern fn glyph_h_advance_func(_: *hb_font_t,
|
||||||
font_data: *c_void,
|
font_data: *c_void,
|
||||||
glyph: hb_codepoint_t,
|
glyph: hb_codepoint_t,
|
||||||
_user_data: *c_void) -> hb_position_t {
|
_: *c_void)
|
||||||
|
-> hb_position_t {
|
||||||
let font: *Font = font_data as *Font;
|
let font: *Font = font_data as *Font;
|
||||||
assert!(font.is_not_null());
|
assert!(font.is_not_null());
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let advance = (*font).glyph_h_advance(glyph as GlyphIndex);
|
let advance = (*font).glyph_h_advance(glyph as GlyphIndex);
|
||||||
HarfbuzzShaper::float_to_fixed(advance)
|
Shaper::float_to_fixed(advance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback to get a font table out of a font.
|
// Callback to get a font table out of a font.
|
||||||
extern fn get_font_table_func(_face: *hb_face_t, tag: hb_tag_t, user_data: *c_void) -> *hb_blob_t {
|
extern fn get_font_table_func(_: *hb_face_t, tag: hb_tag_t, user_data: *c_void) -> *hb_blob_t {
|
||||||
unsafe {
|
unsafe {
|
||||||
let font: *Font = user_data as *Font;
|
let font: *Font = user_data as *Font;
|
||||||
assert!(font.is_not_null());
|
assert!(font.is_not_null());
|
||||||
|
|
||||||
// TODO(Issue #197): reuse font table data, which will change the unsound trickery here.
|
// TODO(Issue #197): reuse font table data, which will change the unsound trickery here.
|
||||||
match (*font).get_table_for_tag(tag as FontTableTag) {
|
match (*font).get_table_for_tag(tag as FontTableTag) {
|
||||||
None => return ptr::null(),
|
None => null(),
|
||||||
Some(ref font_table) => {
|
Some(ref font_table) => {
|
||||||
let skinny_font_table = ~font_table;
|
let skinny_font_table_ptr: *FontTable = font_table; // private context
|
||||||
let skinny_font_table_ptr = ptr::to_unsafe_ptr(skinny_font_table);
|
|
||||||
let mut blob: *hb_blob_t = ptr::null();
|
let mut blob: *hb_blob_t = null();
|
||||||
(*skinny_font_table_ptr).with_buffer(|buf: *u8, len: uint| {
|
do (*skinny_font_table_ptr).with_buffer |buf: *u8, len: uint| {
|
||||||
|
// HarfBuzz calls `destroy_blob_func` when the buffer is no longer needed.
|
||||||
blob = hb_blob_create(buf as *c_char,
|
blob = hb_blob_create(buf as *c_char,
|
||||||
len as c_uint,
|
len as c_uint,
|
||||||
HB_MEMORY_MODE_READONLY,
|
HB_MEMORY_MODE_READONLY,
|
||||||
cast::transmute(skinny_font_table_ptr), // private context for below.
|
transmute(skinny_font_table_ptr),
|
||||||
destroy_blob_func); // HarfBuzz calls this when blob not needed.
|
destroy_blob_func);
|
||||||
});
|
}
|
||||||
|
|
||||||
assert!(blob.is_not_null());
|
assert!(blob.is_not_null());
|
||||||
return blob;
|
blob
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -510,7 +542,7 @@ extern fn get_font_table_func(_face: *hb_face_t, tag: hb_tag_t, user_data: *c_vo
|
||||||
// In particular, we'll need to cast to a boxed, rather than owned, FontTable.
|
// In particular, we'll need to cast to a boxed, rather than owned, FontTable.
|
||||||
|
|
||||||
// even better, should cache the harfbuzz blobs directly instead of recreating a lot.
|
// even better, should cache the harfbuzz blobs directly instead of recreating a lot.
|
||||||
extern fn destroy_blob_func(user_data: *c_void) {
|
extern fn destroy_blob_func(_: *c_void) {
|
||||||
// this will cause drop to run.
|
// TODO: Previous code here was broken. Rewrite.
|
||||||
let _wrapper : &~FontTable = unsafe { cast::transmute(user_data) };
|
|
||||||
}
|
}
|
||||||
|
|
19
src/servo-gfx/text/shaping/mod.rs
Normal file
19
src/servo-gfx/text/shaping/mod.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Shaper encapsulates a specific shaper, such as Harfbuzz,
|
||||||
|
/// Uniscribe, Pango, or Coretext.
|
||||||
|
///
|
||||||
|
/// Currently, only harfbuzz bindings are implemented.
|
||||||
|
|
||||||
|
use text::glyph::GlyphStore;
|
||||||
|
|
||||||
|
pub use Shaper = text::shaping::harfbuzz::Shaper;
|
||||||
|
|
||||||
|
pub mod harfbuzz;
|
||||||
|
|
||||||
|
pub trait ShaperMethods {
|
||||||
|
fn shape_text(&self, text: &str, glyphs: &mut GlyphStore);
|
||||||
|
}
|
||||||
|
|
|
@ -5,17 +5,17 @@
|
||||||
use font_context::FontContext;
|
use font_context::FontContext;
|
||||||
use geometry::Au;
|
use geometry::Au;
|
||||||
use text::glyph::{BreakTypeNormal, GlyphStore};
|
use text::glyph::{BreakTypeNormal, GlyphStore};
|
||||||
use servo_gfx_font::{Font, FontDescriptor, RunMetrics};
|
use font::{Font, FontDescriptor, RunMetrics};
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
|
|
||||||
|
/// A text run.
|
||||||
pub struct TextRun {
|
pub struct TextRun {
|
||||||
text: ~str,
|
text: ~str,
|
||||||
font: @mut Font,
|
font: @mut Font,
|
||||||
glyphs: GlyphStore,
|
glyphs: GlyphStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a hack until TextRuns are normally sendable, or
|
/// This is a hack until TextRuns are normally sendable, or we instead use ARC<TextRun> everywhere.
|
||||||
// we instead use ARC<TextRun> everywhere.
|
|
||||||
pub struct SendableTextRun {
|
pub struct SendableTextRun {
|
||||||
text: ~str,
|
text: ~str,
|
||||||
font: FontDescriptor,
|
font: FontDescriptor,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue