mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
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.
This commit is contained in:
parent
078dd41e37
commit
23dbf72154
5 changed files with 234 additions and 31 deletions
|
@ -7,11 +7,11 @@ license = "Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
euclid = "0.6.8"
|
euclid = "0.6.8"
|
||||||
|
libc = "0.2.11"
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
||||||
servo-fontconfig = { git = "https://github.com/jwilm/rust-fontconfig" }
|
servo-fontconfig = { git = "https://github.com/jwilm/rust-fontconfig" }
|
||||||
freetype-rs = "0.9.0"
|
freetype-rs = "0.9.0"
|
||||||
libc = "0.2.11"
|
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
core-text = "1.1.1"
|
core-text = "1.1.1"
|
||||||
|
|
34
font/src/darwin/byte_order.rs
Normal file
34
font/src/darwin/byte_order.rs
Normal file
|
@ -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<_>>()
|
||||||
|
}
|
79
font/src/darwin/cg_color.rs
Normal file
79
font/src/darwin/cg_color.rs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
//! Font rendering based on CoreText
|
//! Font rendering based on CoreText
|
||||||
//!
|
//!
|
||||||
//! TODO error handling... just search for unwrap.
|
//! TODO error handling... just search for unwrap.
|
||||||
|
#![allow(improper_ctypes)]
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::Deref;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use core_foundation::base::TCFType;
|
use core_foundation::base::TCFType;
|
||||||
use core_foundation::string::{CFString, CFStringRef};
|
use core_foundation::string::{CFString, CFStringRef};
|
||||||
use core_foundation::array::CFIndex;
|
use core_foundation::array::CFIndex;
|
||||||
use core_foundation_sys::string::UniChar;
|
use core_foundation_sys::string::UniChar;
|
||||||
use core_graphics::base::kCGImageAlphaNoneSkipFirst;
|
use core_graphics::base::kCGImageAlphaPremultipliedFirst;
|
||||||
use core_graphics::base::kCGImageAlphaPremultipliedLast;
|
use core_graphics::base::CGFloat;
|
||||||
use core_graphics::color_space::CGColorSpace;
|
use core_graphics::color_space::CGColorSpace;
|
||||||
use core_graphics::context::{CGContext, CGContextRef};
|
use core_graphics::context::{CGContext, CGContextRef};
|
||||||
use core_graphics::font::CGGlyph;
|
use core_graphics::font::{CGFont, CGFontRef, CGGlyph};
|
||||||
use core_graphics::geometry::CGPoint;
|
use core_graphics::geometry::{CGPoint, CGRect, CGSize};
|
||||||
use core_text::font::{CTFont, new_from_descriptor as ct_new_from_descriptor};
|
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::create_for_family;
|
||||||
use core_text::font_collection::get_family_names as ct_get_family_names;
|
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::kCTFontVerticalOrientation;
|
||||||
use core_text::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef, CTFontOrientation};
|
use core_text::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef, CTFontOrientation};
|
||||||
|
|
||||||
|
use libc::size_t;
|
||||||
|
|
||||||
use euclid::point::Point2D;
|
use euclid::point::Point2D;
|
||||||
use euclid::rect::Rect;
|
use euclid::rect::Rect;
|
||||||
use euclid::size::Size2D;
|
use euclid::size::Size2D;
|
||||||
|
|
||||||
use super::{FontDesc, RasterizedGlyph, Metrics};
|
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
|
/// Font descriptor
|
||||||
///
|
///
|
||||||
/// The descriptor provides data about a font and supports creating a font.
|
/// The descriptor provides data about a font and supports creating a font.
|
||||||
|
@ -52,7 +61,7 @@ pub struct Rasterizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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);
|
println!("device_pixel_ratio: {}", device_pixel_ratio);
|
||||||
Rasterizer {
|
Rasterizer {
|
||||||
fonts: HashMap::new(),
|
fonts: HashMap::new(),
|
||||||
|
@ -106,9 +115,10 @@ impl Default for FontOrientation {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A font
|
/// A font
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Font {
|
pub struct Font {
|
||||||
ct_font: CTFont
|
ct_font: CTFont,
|
||||||
|
cg_font: CGFont,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for Font {}
|
unsafe impl Send for Font {}
|
||||||
|
@ -159,21 +169,14 @@ impl Descriptor {
|
||||||
/// Create a Font from this descriptor
|
/// Create a Font from this descriptor
|
||||||
pub fn to_font(&self, pt_size: f64) -> Font {
|
pub fn to_font(&self, pt_size: f64) -> Font {
|
||||||
let ct_font = ct_new_from_descriptor(&self.ct_descriptor, pt_size);
|
let ct_font = ct_new_from_descriptor(&self.ct_descriptor, pt_size);
|
||||||
|
let cg_font = ct_font.copy_to_CGFont();
|
||||||
Font {
|
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 {
|
impl Font {
|
||||||
/// The the bounding rect of a glyph
|
/// The the bounding rect of a glyph
|
||||||
pub fn bounding_rect_for_glyph(&self, orientation: FontOrientation, index: u32) -> Rect<f64> {
|
pub fn bounding_rect_for_glyph(&self, orientation: FontOrientation, index: u32) -> Rect<f64> {
|
||||||
|
@ -211,7 +214,7 @@ impl Font {
|
||||||
1)
|
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) {
|
let glyph_index = match self.glyph_index(character) {
|
||||||
Some(i) => i,
|
Some(i) => i,
|
||||||
None => {
|
None => {
|
||||||
|
@ -252,14 +255,27 @@ impl Font {
|
||||||
8, // bits per component
|
8, // bits per component
|
||||||
rasterized_width as usize * 4,
|
rasterized_width as usize * 4,
|
||||||
&CGColorSpace::create_device_rgb(),
|
&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_allows_font_smoothing(true);
|
||||||
cg_context.set_should_smooth_fonts(true);
|
cg_context.set_should_smooth_fonts(true);
|
||||||
cg_context.set_allows_font_subpixel_quantization(true);
|
cg_context.set_allows_font_subpixel_quantization(true);
|
||||||
cg_context.set_should_subpixel_quantize_fonts(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 {
|
let rasterization_origin = CGPoint {
|
||||||
x: -rasterized_left as f64,
|
x: -rasterized_left as f64,
|
||||||
y: rasterized_descent as f64,
|
y: rasterized_descent as f64,
|
||||||
|
@ -269,13 +285,10 @@ impl Font {
|
||||||
&[rasterization_origin],
|
&[rasterization_origin],
|
||||||
cg_context.clone());
|
cg_context.clone());
|
||||||
|
|
||||||
let rasterized_area = (rasterized_width * rasterized_height) as usize;
|
|
||||||
let rasterized_pixels = cg_context.data().to_vec();
|
let rasterized_pixels = cg_context.data().to_vec();
|
||||||
let buf = rasterized_pixels.into_iter()
|
println!("rasterized_pixels: {:?}", rasterized_pixels);
|
||||||
.enumerate()
|
|
||||||
.filter(|&(index, _)| (index % 4) != 0)
|
let buf = extract_rgb(rasterized_pixels);
|
||||||
.map(|(_, val)| val)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
RasterizedGlyph {
|
RasterizedGlyph {
|
||||||
c: character,
|
c: character,
|
||||||
|
@ -304,9 +317,18 @@ impl Font {
|
||||||
/// Additional methods needed to render fonts for Alacritty
|
/// Additional methods needed to render fonts for Alacritty
|
||||||
///
|
///
|
||||||
/// TODO upstream these into core_graphics crate
|
/// TODO upstream these into core_graphics crate
|
||||||
trait CGContextExt {
|
pub trait CGContextExt {
|
||||||
fn set_allows_font_subpixel_quantization(&self, bool);
|
fn set_allows_font_subpixel_quantization(&self, bool);
|
||||||
fn set_should_subpixel_quantize_fonts(&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 {
|
impl CGContextExt for CGContext {
|
||||||
|
@ -321,12 +343,81 @@ impl CGContextExt for CGContext {
|
||||||
CGContextSetShouldSubpixelQuantizeFonts(self.as_concrete_TypeRef(), should);
|
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")]
|
#[link(name = "ApplicationServices", kind = "framework")]
|
||||||
extern {
|
extern {
|
||||||
fn CGContextSetAllowsFontSubpixelQuantization(c: CGContextRef, allows: bool);
|
fn CGContextSetAllowsFontSubpixelQuantization(c: CGContextRef, allows: bool);
|
||||||
fn CGContextSetShouldSubpixelQuantizeFonts(c: CGContextRef, should: 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)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
extern crate fontconfig;
|
extern crate fontconfig;
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
extern crate freetype;
|
extern crate freetype;
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
extern crate libc;
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
extern crate core_text;
|
extern crate core_text;
|
||||||
|
@ -23,6 +21,7 @@ extern crate core_foundation_sys;
|
||||||
extern crate core_graphics;
|
extern crate core_graphics;
|
||||||
|
|
||||||
extern crate euclid;
|
extern crate euclid;
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue