servo/components/gfx/platform/macos/font.rs
2014-09-08 20:21:42 -06:00

185 lines
6.3 KiB
Rust

/* 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/. */
/// Implementation of Quartz (CoreGraphics) fonts.
extern crate core_foundation;
extern crate core_graphics;
extern crate core_text;
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
use font::FontTableTag;
use font::FractionalPixel;
use servo_util::geometry::{Au, px_to_pt};
use servo_util::geometry;
use platform::macos::font_context::FontContextHandle;
use text::glyph::GlyphId;
use style::computed_values::font_weight;
use platform::font_template::FontTemplateData;
use core_foundation::base::CFIndex;
use core_foundation::data::CFData;
use core_foundation::string::UniChar;
use core_graphics::font::CGGlyph;
use core_graphics::geometry::CGRect;
use core_text::font::CTFont;
use core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
use core_text::font_descriptor::{kCTFontDefaultOrientation};
use std::ptr;
use sync::Arc;
pub struct FontTable {
data: CFData,
}
// Noncopyable.
impl Drop for FontTable {
fn drop(&mut self) {}
}
impl FontTable {
pub fn wrap(data: CFData) -> FontTable {
FontTable { data: data }
}
}
impl FontTableMethods for FontTable {
fn with_buffer(&self, blk: |*const u8, uint|) {
blk(self.data.bytes().as_ptr(), self.data.len() as uint);
}
}
pub struct FontHandle {
pub font_data: Arc<FontTemplateData>,
pub ctfont: CTFont,
}
impl FontHandleMethods for FontHandle {
fn new_from_template(_fctx: &FontContextHandle,
template: Arc<FontTemplateData>,
pt_size: Option<f64>)
-> Result<FontHandle, ()> {
let size = match pt_size {
Some(s) => s,
None => 0.0
};
match template.ctfont {
Some(ref ctfont) => {
Ok(FontHandle {
font_data: template.clone(),
ctfont: ctfont.clone_with_font_size(size),
})
}
None => {
Err(())
}
}
}
fn get_template(&self) -> Arc<FontTemplateData> {
self.font_data.clone()
}
fn family_name(&self) -> String {
self.ctfont.family_name()
}
fn face_name(&self) -> String {
self.ctfont.face_name()
}
fn is_italic(&self) -> bool {
self.ctfont.symbolic_traits().is_italic()
}
fn boldness(&self) -> font_weight::T {
// -1.0 to 1.0
let normalized = self.ctfont.all_traits().normalized_weight();
// 0.0 to 9.0
let normalized = (normalized + 1.0) / 2.0 * 9.0;
if normalized < 1.0 { return font_weight::Weight100; }
if normalized < 2.0 { return font_weight::Weight200; }
if normalized < 3.0 { return font_weight::Weight300; }
if normalized < 4.0 { return font_weight::Weight400; }
if normalized < 5.0 { return font_weight::Weight500; }
if normalized < 6.0 { return font_weight::Weight600; }
if normalized < 7.0 { return font_weight::Weight700; }
if normalized < 8.0 { return font_weight::Weight800; }
return font_weight::Weight900;
}
fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
let characters: [UniChar, ..1] = [codepoint as UniChar];
let mut glyphs: [CGGlyph, ..1] = [0 as CGGlyph];
let count: CFIndex = 1;
let result = self.ctfont.get_glyphs_for_characters(&characters[0],
&mut glyphs[0],
count);
if !result {
// No glyph for this character
return None;
}
assert!(glyphs[0] != 0); // FIXME: error handling
return Some(glyphs[0] as GlyphId);
}
fn glyph_h_kerning(&self, _first_glyph: GlyphId, _second_glyph: GlyphId)
-> FractionalPixel {
// TODO: Implement on mac
0.0
}
fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
let glyphs = [glyph as CGGlyph];
let advance = self.ctfont.get_advances_for_glyphs(kCTFontDefaultOrientation,
&glyphs[0],
ptr::mut_null(),
1);
Some(advance as FractionalPixel)
}
fn get_metrics(&self) -> FontMetrics {
let bounding_rect: CGRect = self.ctfont.bounding_box();
let ascent = self.ctfont.ascent() as f64;
let descent = self.ctfont.descent() as f64;
let em_size = Au::from_frac_px(self.ctfont.pt_size() as f64);
let leading = self.ctfont.leading() as f64;
let scale = px_to_pt(self.ctfont.pt_size() as f64) / (ascent + descent);
let line_gap = (ascent + descent + leading + 0.5).floor();
let metrics = FontMetrics {
underline_size: Au::from_pt(self.ctfont.underline_thickness() as f64),
// TODO(Issue #201): underline metrics are not reliable. Have to pull out of font table
// directly.
//
// see also: https://bugs.webkit.org/show_bug.cgi?id=16768
// see also: https://bugreports.qt-project.org/browse/QTBUG-13364
underline_offset: Au::from_pt(self.ctfont.underline_position() as f64),
strikeout_size: geometry::from_pt(0.0), // FIXME(Issue #942)
strikeout_offset: geometry::from_pt(0.0), // FIXME(Issue #942)
leading: Au::from_pt(leading),
x_height: Au::from_pt(self.ctfont.x_height() as f64),
em_size: em_size,
ascent: Au::from_pt(ascent * scale),
descent: Au::from_pt(descent * scale),
max_advance: Au::from_pt(bounding_rect.size.width as f64),
line_gap: Au::from_frac_px(line_gap),
};
debug!("Font metrics (@{:f} pt): {:?}", self.ctfont.pt_size() as f64, metrics);
return metrics;
}
fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
let result: Option<CFData> = self.ctfont.get_font_table(tag);
result.and_then(|data| {
Some(FontTable::wrap(data))
})
}
}