summaryrefslogtreecommitdiffstats
path: root/font
diff options
context:
space:
mode:
authorJoe Wilm <joe@jwilm.com>2016-06-24 21:52:32 -0700
committerJoe Wilm <joe@jwilm.com>2016-06-24 21:58:13 -0700
commit23dbf721547f652d4afa42e505c7703dfb927a47 (patch)
tree9945fc35fee64498cc0e0e56ff502cfbd28274d0 /font
parent078dd41e371a9bd905b7d99fa757baafad6a4733 (diff)
Fix subpixel rendering for macOS
This adds a bunch of APIs to CGContext (and supporting types) that aren't actually necessary to turn on subpixel rendering. The key for subpixel rendering were the options passed to bitmap_context_create(). Specifically, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host are necessary to enable it.
Diffstat (limited to 'font')
-rw-r--r--font/Cargo.toml2
-rw-r--r--font/src/darwin/byte_order.rs34
-rw-r--r--font/src/darwin/cg_color.rs79
-rw-r--r--font/src/darwin/mod.rs147
-rw-r--r--font/src/lib.rs3
5 files changed, 234 insertions, 31 deletions
diff --git a/font/Cargo.toml b/font/Cargo.toml
index 8345af73..d6cfcc38 100644
--- a/font/Cargo.toml
+++ b/font/Cargo.toml
@@ -7,11 +7,11 @@ license = "Apache-2.0"
[dependencies]
euclid = "0.6.8"
+libc = "0.2.11"
[target.'cfg(not(target_os = "macos"))'.dependencies]
servo-fontconfig = { git = "https://github.com/jwilm/rust-fontconfig" }
freetype-rs = "0.9.0"
-libc = "0.2.11"
[target.'cfg(target_os = "macos")'.dependencies]
core-text = "1.1.1"
diff --git a/font/src/darwin/byte_order.rs b/font/src/darwin/byte_order.rs
new file mode 100644
index 00000000..5b696554
--- /dev/null
+++ b/font/src/darwin/byte_order.rs
@@ -0,0 +1,34 @@
+//! Constants for bitmap byte order
+#![allow(non_upper_case_globals)]
+pub const kCGBitmapByteOrder32Little: u32 = 2 << 12;
+pub const kCGBitmapByteOrder32Big: u32 = 4 << 12;
+
+#[cfg(target_endian = "little")]
+pub const kCGBitmapByteOrder32Host: u32 = kCGBitmapByteOrder32Little;
+
+#[cfg(target_endian = "big")]
+pub const kCGBitmapByteOrder32Host: u32 = kCGBitmapByteOrder32Big;
+
+#[cfg(target_endian = "little")]
+pub fn extract_rgb(bytes: Vec<u8>) -> Vec<u8> {
+ let pixels = bytes.len() / 4;
+ let mut rgb = Vec::with_capacity(pixels * 3);
+
+ for i in 0..pixels {
+ let offset = i * 4;
+ rgb.push(bytes[offset + 2]);
+ rgb.push(bytes[offset + 1]);
+ rgb.push(bytes[offset + 0]);
+ }
+
+ rgb
+}
+
+#[cfg(target_endian = "big")]
+pub fn extract_rgb(bytes: Vec<u8>) -> Vec<u8> {
+ bytes.into_iter()
+ .enumerate()
+ .filter(|&(index, _)| ((index) % 4) != 0)
+ .map(|(_, val)| val)
+ .collect::<Vec<_>>()
+}
diff --git a/font/src/darwin/cg_color.rs b/font/src/darwin/cg_color.rs
new file mode 100644
index 00000000..552137cc
--- /dev/null
+++ b/font/src/darwin/cg_color.rs
@@ -0,0 +1,79 @@
+use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
+use core_graphics::color_space::{CGColorSpace, CGColorSpaceRef};
+use core_graphics::base::CGFloat;
+use std::mem;
+
+#[repr(C)]
+pub struct __CGColor;
+
+pub type CGColorRef = *const __CGColor;
+
+pub struct CGColor {
+ obj: CGColorRef,
+}
+
+impl Drop for CGColor {
+ fn drop(&mut self) {
+ unsafe {
+ CFRelease(self.as_CFTypeRef())
+ }
+ }
+}
+
+impl Clone for CGColor {
+ fn clone(&self) -> CGColor {
+ unsafe {
+ TCFType::wrap_under_get_rule(self.as_concrete_TypeRef())
+ }
+ }
+}
+
+impl TCFType<CGColorRef> for CGColor {
+ #[inline]
+ fn as_concrete_TypeRef(&self) -> CGColorRef {
+ self.obj
+ }
+
+ #[inline]
+ unsafe fn wrap_under_get_rule(reference: CGColorRef) -> CGColor {
+ let reference: CGColorRef = mem::transmute(CFRetain(mem::transmute(reference)));
+ TCFType::wrap_under_create_rule(reference)
+ }
+
+ #[inline]
+ fn as_CFTypeRef(&self) -> CFTypeRef {
+ unsafe {
+ mem::transmute(self.as_concrete_TypeRef())
+ }
+ }
+
+ #[inline]
+ unsafe fn wrap_under_create_rule(obj: CGColorRef) -> CGColor {
+ CGColor {
+ obj: obj,
+ }
+ }
+
+ #[inline]
+ fn type_id() -> CFTypeID {
+ unsafe {
+ CGColorGetTypeID()
+ }
+ }
+}
+
+impl CGColor {
+ pub fn new(color_space: CGColorSpace, values: [CGFloat; 4]) -> CGColor {
+ unsafe {
+ let result = CGColorCreate(color_space.as_concrete_TypeRef(), values.as_ptr());
+ TCFType::wrap_under_create_rule(result)
+ }
+ }
+}
+
+#[link(name = "ApplicationServices", kind = "framework")]
+extern {
+ fn CGColorCreate(space: CGColorSpaceRef, vals: *const CGFloat) -> CGColorRef;
+ fn CGColorGetTypeID() -> CFTypeID;
+}
+
diff --git a/font/src/darwin/mod.rs b/font/src/darwin/mod.rs
index 844850e0..5e53abd5 100644
--- a/font/src/darwin/mod.rs
+++ b/font/src/darwin/mod.rs
@@ -1,20 +1,20 @@
//! Font rendering based on CoreText
//!
//! TODO error handling... just search for unwrap.
+#![allow(improper_ctypes)]
use std::collections::HashMap;
-use std::ops::Deref;
use std::ptr;
use core_foundation::base::TCFType;
use core_foundation::string::{CFString, CFStringRef};
use core_foundation::array::CFIndex;
use core_foundation_sys::string::UniChar;
-use core_graphics::base::kCGImageAlphaNoneSkipFirst;
-use core_graphics::base::kCGImageAlphaPremultipliedLast;
+use core_graphics::base::kCGImageAlphaPremultipliedFirst;
+use core_graphics::base::CGFloat;
use core_graphics::color_space::CGColorSpace;
use core_graphics::context::{CGContext, CGContextRef};
-use core_graphics::font::CGGlyph;
-use core_graphics::geometry::CGPoint;
+use core_graphics::font::{CGFont, CGFontRef, CGGlyph};
+use core_graphics::geometry::{CGPoint, CGRect, CGSize};
use core_text::font::{CTFont, new_from_descriptor as ct_new_from_descriptor};
use core_text::font_collection::create_for_family;
use core_text::font_collection::get_family_names as ct_get_family_names;
@@ -23,12 +23,21 @@ use core_text::font_descriptor::kCTFontHorizontalOrientation;
use core_text::font_descriptor::kCTFontVerticalOrientation;
use core_text::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef, CTFontOrientation};
+use libc::size_t;
+
use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::size::Size2D;
use super::{FontDesc, RasterizedGlyph, Metrics};
+pub mod cg_color;
+use self::cg_color::{CGColorRef, CGColor};
+
+pub mod byte_order;
+use self::byte_order::kCGBitmapByteOrder32Host;
+use self::byte_order::extract_rgb;
+
/// Font descriptor
///
/// The descriptor provides data about a font and supports creating a font.
@@ -52,7 +61,7 @@ pub struct Rasterizer {
}
impl Rasterizer {
- pub fn new(dpi_x: f32, dpi_y: f32, device_pixel_ratio: f32) -> Rasterizer {
+ pub fn new(_dpi_x: f32, _dpi_y: f32, device_pixel_ratio: f32) -> Rasterizer {
println!("device_pixel_ratio: {}", device_pixel_ratio);
Rasterizer {
fonts: HashMap::new(),
@@ -106,9 +115,10 @@ impl Default for FontOrientation {
}
/// A font
-#[derive(Debug, Clone)]
+#[derive(Clone)]
pub struct Font {
- ct_font: CTFont
+ ct_font: CTFont,
+ cg_font: CGFont,
}
unsafe impl Send for Font {}
@@ -159,21 +169,14 @@ impl Descriptor {
/// Create a Font from this descriptor
pub fn to_font(&self, pt_size: f64) -> Font {
let ct_font = ct_new_from_descriptor(&self.ct_descriptor, pt_size);
+ let cg_font = ct_font.copy_to_CGFont();
Font {
- ct_font: ct_font
+ ct_font: ct_font,
+ cg_font: cg_font,
}
}
}
-impl Deref for Font {
- type Target = CTFont;
-
- #[inline]
- fn deref(&self) -> &Self::Target {
- &self.ct_font
- }
-}
-
impl Font {
/// The the bounding rect of a glyph
pub fn bounding_rect_for_glyph(&self, orientation: FontOrientation, index: u32) -> Rect<f64> {
@@ -211,7 +214,7 @@ impl Font {
1)
}
- pub fn get_glyph(&self, character: char, size: f64) -> RasterizedGlyph {
+ pub fn get_glyph(&self, character: char, _size: f64) -> RasterizedGlyph {
let glyph_index = match self.glyph_index(character) {
Some(i) => i,
None => {
@@ -252,14 +255,27 @@ impl Font {
8, // bits per component
rasterized_width as usize * 4,
&CGColorSpace::create_device_rgb(),
- kCGImageAlphaNoneSkipFirst);
+ kCGImageAlphaPremultipliedFirst |
+ kCGBitmapByteOrder32Host);
+
+ // Give the context an opaque, black background
+ cg_context.set_rgb_fill_color(0.0, 0.0, 0.0, 1.0);
+ let context_rect = CGRect::new(&CGPoint::new(0.0, 0.0),
+ &CGSize::new(rasterized_width as f64,
+ rasterized_height as f64));
+ cg_context.fill_rect(context_rect);
cg_context.set_allows_font_smoothing(true);
cg_context.set_should_smooth_fonts(true);
cg_context.set_allows_font_subpixel_quantization(true);
cg_context.set_should_subpixel_quantize_fonts(true);
- cg_context.set_rgb_fill_color(1.0, 1.0, 1.0, 1.0);
+ cg_context.set_allows_font_subpixel_positioning(true);
+ cg_context.set_should_subpixel_position_fonts(true);
+ cg_context.set_allows_antialiasing(true);
+ cg_context.set_should_antialias(true);
+ // Set fill color to white for drawing the glyph
+ cg_context.set_rgb_fill_color(1.0, 1.0, 1.0, 1.0);
let rasterization_origin = CGPoint {
x: -rasterized_left as f64,
y: rasterized_descent as f64,
@@ -269,13 +285,10 @@ impl Font {
&[rasterization_origin],
cg_context.clone());
- let rasterized_area = (rasterized_width * rasterized_height) as usize;
let rasterized_pixels = cg_context.data().to_vec();
- let buf = rasterized_pixels.into_iter()
- .enumerate()
- .filter(|&(index, _)| (index % 4) != 0)
- .map(|(_, val)| val)
- .collect::<Vec<_>>();
+ println!("rasterized_pixels: {:?}", rasterized_pixels);
+
+ let buf = extract_rgb(rasterized_pixels);
RasterizedGlyph {
c: character,
@@ -304,9 +317,18 @@ impl Font {
/// Additional methods needed to render fonts for Alacritty
///
/// TODO upstream these into core_graphics crate
-trait CGContextExt {
+pub trait CGContextExt {
fn set_allows_font_subpixel_quantization(&self, bool);
fn set_should_subpixel_quantize_fonts(&self, bool);
+ fn set_allows_font_subpixel_positioning(&self, bool);
+ fn set_should_subpixel_position_fonts(&self, bool);
+ fn set_allows_antialiasing(&self, bool);
+ fn set_should_antialias(&self, bool);
+ fn fill_rect(&self, rect: CGRect);
+ fn set_font_smoothing_background_color(&self, color: CGColor);
+ fn show_glyphs_at_positions(&self, &[CGGlyph], &[CGPoint]);
+ fn set_font(&self, &CGFont);
+ fn set_font_size(&self, size: f64);
}
impl CGContextExt for CGContext {
@@ -321,12 +343,81 @@ impl CGContextExt for CGContext {
CGContextSetShouldSubpixelQuantizeFonts(self.as_concrete_TypeRef(), should);
}
}
+
+ fn set_should_subpixel_position_fonts(&self, should: bool) {
+ unsafe {
+ CGContextSetShouldSubpixelPositionFonts(self.as_concrete_TypeRef(), should);
+ }
+ }
+
+ fn set_allows_font_subpixel_positioning(&self, allows: bool) {
+ unsafe {
+ CGContextSetAllowsFontSubpixelPositioning(self.as_concrete_TypeRef(), allows);
+ }
+ }
+
+ fn set_should_antialias(&self, should: bool) {
+ unsafe {
+ CGContextSetShouldAntialias(self.as_concrete_TypeRef(), should);
+ }
+ }
+
+ fn set_allows_antialiasing(&self, allows: bool) {
+ unsafe {
+ CGContextSetAllowsAntialiasing(self.as_concrete_TypeRef(), allows);
+ }
+ }
+
+ fn fill_rect(&self, rect: CGRect) {
+ unsafe {
+ CGContextFillRect(self.as_concrete_TypeRef(), rect);
+ }
+ }
+
+ fn set_font_smoothing_background_color(&self, color: CGColor) {
+ unsafe {
+ CGContextSetFontSmoothingBackgroundColor(self.as_concrete_TypeRef(),
+ color.as_concrete_TypeRef());
+ }
+ }
+
+ fn show_glyphs_at_positions(&self, glyphs: &[CGGlyph], positions: &[CGPoint]) {
+ assert_eq!(glyphs.len(), positions.len());
+ unsafe {
+ CGContextShowGlyphsAtPositions(self.as_concrete_TypeRef(),
+ glyphs.as_ptr(),
+ positions.as_ptr(),
+ glyphs.len());
+ }
+ }
+
+ fn set_font(&self, font: &CGFont) {
+ unsafe {
+ CGContextSetFont(self.as_concrete_TypeRef(), font.as_concrete_TypeRef());
+ }
+ }
+
+ fn set_font_size(&self, size: f64) {
+ unsafe {
+ CGContextSetFontSize(self.as_concrete_TypeRef(), size as CGFloat);
+ }
+ }
}
#[link(name = "ApplicationServices", kind = "framework")]
extern {
fn CGContextSetAllowsFontSubpixelQuantization(c: CGContextRef, allows: bool);
fn CGContextSetShouldSubpixelQuantizeFonts(c: CGContextRef, should: bool);
+ fn CGContextSetAllowsFontSubpixelPositioning(c: CGContextRef, allows: bool);
+ fn CGContextSetShouldSubpixelPositionFonts(c: CGContextRef, should: bool);
+ fn CGContextSetAllowsAntialiasing(c: CGContextRef, allows: bool);
+ fn CGContextSetShouldAntialias(c: CGContextRef, should: bool);
+ fn CGContextFillRect(c: CGContextRef, r: CGRect);
+ fn CGContextSetFontSmoothingBackgroundColor(c: CGContextRef, color: CGColorRef);
+ fn CGContextShowGlyphsAtPositions(c: CGContextRef, glyphs: *const CGGlyph,
+ positions: *const CGPoint, count: size_t);
+ fn CGContextSetFont(c: CGContextRef, font: CGFontRef);
+ fn CGContextSetFontSize(c: CGContextRef, size: CGFloat);
}
#[cfg(test)]
diff --git a/font/src/lib.rs b/font/src/lib.rs
index ba632bee..bd485ff0 100644
--- a/font/src/lib.rs
+++ b/font/src/lib.rs
@@ -10,8 +10,6 @@
extern crate fontconfig;
#[cfg(not(target_os = "macos"))]
extern crate freetype;
-#[cfg(not(target_os = "macos"))]
-extern crate libc;
#[cfg(target_os = "macos")]
extern crate core_text;
@@ -23,6 +21,7 @@ extern crate core_foundation_sys;
extern crate core_graphics;
extern crate euclid;
+extern crate libc;
use std::fmt;