diff --git a/Cargo.lock b/Cargo.lock index fb28958..79bd580 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,12 +4,12 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "freetype-rs 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "errno 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "font 0.1.0", "gl_generator 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "glutin 0.4.9 (git+https://github.com/jwilm/glutin?rev=c95e6973ace3cbf321123a64588b27f032675be9)", + "glutin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "notify 2.5.5 (git+https://github.com/jwilm/rsnotify?branch=add-ignore-op)", - "servo-fontconfig 0.2.0 (git+https://github.com/jwilm/rust-fontconfig)", + "notify 2.6.1 (git+https://github.com/passcod/rsnotify)", ] [[package]] @@ -73,13 +73,13 @@ dependencies = [ [[package]] name = "cocoa" -version = "0.2.5" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "objc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -109,6 +109,16 @@ dependencies = [ "serde 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "core-text" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam" version = "0.2.9" @@ -132,11 +142,25 @@ dependencies = [ ] [[package]] -name = "dylib" -version = "0.0.1" +name = "errno" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "euclid" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -156,6 +180,20 @@ dependencies = [ "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "font" +version = "0.1.0" +dependencies = [ + "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "freetype-rs 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "servo-fontconfig 0.2.0 (git+https://github.com/jwilm/rust-fontconfig)", +] + [[package]] name = "freetype-rs" version = "0.9.0" @@ -217,16 +255,6 @@ dependencies = [ "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "gl_generator" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "xml-rs 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "gl_generator" version = "0.5.1" @@ -247,23 +275,22 @@ dependencies = [ [[package]] name = "glutin" -version = "0.4.9" -source = "git+https://github.com/jwilm/glutin?rev=c95e6973ace3cbf321123a64588b27f032675be9#c95e6973ace3cbf321123a64588b27f032675be9" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "android_glue 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "cgl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "cocoa 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cocoa 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "dwmapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gl_generator 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "gl_generator 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "objc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "osmesa-sys 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "objc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "osmesa-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "shared_library 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "user32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -271,7 +298,15 @@ dependencies = [ "wayland-kbd 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "wayland-window 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "x11-dl 2.4.0 (git+https://github.com/jwilm/x11-rs?rev=40f08df7b4408980b922b3c6e258c9c6765c2c24)", + "x11-dl 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "heapsize" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -410,8 +445,8 @@ dependencies = [ [[package]] name = "notify" -version = "2.5.5" -source = "git+https://github.com/jwilm/rsnotify?branch=add-ignore-op#0ca41a4807c427e6cf47d7e75735df62d2e86708" +version = "2.6.1" +source = "git+https://github.com/passcod/rsnotify#7fbba3514fb7045549045e8da315007cebbcc953" dependencies = [ "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -495,19 +530,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "objc" -version = "0.1.8" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "osmesa-sys" -version = "0.0.5" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "shared_library 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -702,19 +735,11 @@ dependencies = [ [[package]] name = "x11-dl" -version = "2.4.0" -source = "git+https://github.com/jwilm/x11-rs?rev=40f08df7b4408980b922b3c6e258c9c6765c2c24#40f08df7b4408980b922b3c6e258c9c6765c2c24" -dependencies = [ - "dylib 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "xml-rs" -version = "0.2.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b95fdf6..6a8430a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,18 +7,19 @@ exclude = ["res/*"] build = "build.rs" [dependencies] -servo-fontconfig = { git = "https://github.com/jwilm/rust-fontconfig" } -freetype-rs = "0.9.0" libc = "*" cgmath = "0.7" -notify = { git = "https://github.com/jwilm/rsnotify", branch = "add-ignore-op" } +notify = { git = "https://github.com/passcod/rsnotify" } bitflags = "*" +font = { path = "./font" } +errno = "0.1.6" [build-dependencies] gl_generator = "0.5" [dependencies.glutin] -git = "https://github.com/jwilm/glutin" -rev = "c95e6973ace3cbf321123a64588b27f032675be9" +version = "*" +# git = "https://github.com/jwilm/glutin" +# rev = "c95e6973ace3cbf321123a64588b27f032675be9" # version = "*" # path = "../glutin" diff --git a/font/Cargo.lock b/font/Cargo.lock new file mode 100644 index 0000000..5862234 --- /dev/null +++ b/font/Cargo.lock @@ -0,0 +1,193 @@ +[root] +name = "font" +version = "0.1.0" +dependencies = [ + "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "freetype-rs 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "servo-fontconfig 0.2.0 (git+https://github.com/jwilm/rust-fontconfig)", +] + +[[package]] +name = "bitflags" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "core-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-foundation-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-text" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "euclid" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "expat-sys" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "make-cmd 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "freetype-rs" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "freetype-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "freetype-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gcc" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "heapsize" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libz-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "make-cmd" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num-traits" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pkg-config" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc-serialize" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "servo-fontconfig" +version = "0.2.0" +source = "git+https://github.com/jwilm/rust-fontconfig#419135e5e1106ec0973dd4923bd9c70d8e438cc8" +dependencies = [ + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "servo-fontconfig-sys 2.11.3 (git+https://github.com/jwilm/libfontconfig)", +] + +[[package]] +name = "servo-fontconfig-sys" +version = "2.11.3" +source = "git+https://github.com/jwilm/libfontconfig#618a52973d46e5cce4f054f6ee3bd2682167eee4" +dependencies = [ + "expat-sys 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "freetype-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + diff --git a/font/Cargo.toml b/font/Cargo.toml new file mode 100644 index 0000000..8345af7 --- /dev/null +++ b/font/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "font" +version = "0.1.0" +authors = ["Joe Wilm "] +description = "Font rendering using the best available solution per platform" +license = "Apache-2.0" + +[dependencies] +euclid = "0.6.8" + +[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" +core-foundation = "0.2.2" +core-graphics = "0.3.2" +core-foundation-sys = "0.2.2" diff --git a/font/src/darwin/mod.rs b/font/src/darwin/mod.rs new file mode 100644 index 0000000..844850e --- /dev/null +++ b/font/src/darwin/mod.rs @@ -0,0 +1,380 @@ +//! Font rendering based on CoreText +//! +//! TODO error handling... just search for unwrap. +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::color_space::CGColorSpace; +use core_graphics::context::{CGContext, CGContextRef}; +use core_graphics::font::CGGlyph; +use core_graphics::geometry::CGPoint; +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; +use core_text::font_descriptor::kCTFontDefaultOrientation; +use core_text::font_descriptor::kCTFontHorizontalOrientation; +use core_text::font_descriptor::kCTFontVerticalOrientation; +use core_text::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef, CTFontOrientation}; + +use euclid::point::Point2D; +use euclid::rect::Rect; +use euclid::size::Size2D; + +use super::{FontDesc, RasterizedGlyph, Metrics}; + +/// Font descriptor +/// +/// The descriptor provides data about a font and supports creating a font. +#[derive(Debug)] +pub struct Descriptor { + family_name: String, + font_name: String, + style_name: String, + display_name: String, + font_path: String, + + ct_descriptor: CTFontDescriptor +} + +/// Rasterizer, the main type exported by this package +/// +/// Given a fontdesc, can rasterize fonts. +pub struct Rasterizer { + fonts: HashMap, + device_pixel_ratio: f32, +} + +impl 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(), + device_pixel_ratio: device_pixel_ratio, + } + } + + pub fn metrics(&mut self, desc: &FontDesc, size: f32) -> Metrics { + let scaled_size = self.device_pixel_ratio * size; + self.get_font(desc, scaled_size).unwrap().metrics() + } + + fn get_font(&mut self, desc: &FontDesc, size: f32) -> Option { + if let Some(font) = self.fonts.get(desc) { + return Some(font.clone()); + } + + let descriptors = descriptors_for_family(&desc.name[..]); + for descriptor in descriptors { + if descriptor.style_name == desc.style { + // Found the font we want + let font = descriptor.to_font(size as _); + self.fonts.insert(desc.to_owned(), font.clone()); + return Some(font); + } + } + + None + } + + pub fn get_glyph(&mut self, desc: &FontDesc, size: f32, c: char) -> RasterizedGlyph { + let scaled_size = self.device_pixel_ratio * size; + let glyph = self.get_font(desc, scaled_size).unwrap().get_glyph(c, scaled_size as _); + + glyph + } +} + +/// Specifies the intended rendering orientation of the font for obtaining glyph metrics +#[derive(Debug)] +pub enum FontOrientation { + Default = kCTFontDefaultOrientation as isize, + Horizontal = kCTFontHorizontalOrientation as isize, + Vertical = kCTFontVerticalOrientation as isize, +} + +impl Default for FontOrientation { + fn default() -> FontOrientation { + FontOrientation::Default + } +} + +/// A font +#[derive(Debug, Clone)] +pub struct Font { + ct_font: CTFont +} + +unsafe impl Send for Font {} + +/// List all family names +pub fn get_family_names() -> Vec { + // CFArray of CFStringRef + let names = ct_get_family_names(); + let mut owned_names = Vec::new(); + + for name in names.iter() { + let family: CFString = unsafe { TCFType::wrap_under_get_rule(name as CFStringRef) }; + owned_names.push(format!("{}", family)); + } + + owned_names +} + +/// Get descriptors for family name +pub fn descriptors_for_family(family: &str) -> Vec { + let mut out = Vec::new(); + + let ct_collection = match create_for_family(family) { + Some(c) => c, + None => return out, + }; + + // CFArray of CTFontDescriptorRef (i think) + let descriptors = ct_collection.get_descriptors(); + for descriptor in descriptors.iter() { + let desc: CTFontDescriptor = unsafe { + TCFType::wrap_under_get_rule(descriptor as CTFontDescriptorRef) + }; + out.push(Descriptor { + family_name: desc.family_name(), + font_name: desc.font_name(), + style_name: desc.style_name(), + display_name: desc.display_name(), + font_path: desc.font_path(), + ct_descriptor: desc, + }); + } + + out +} + +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); + Font { + ct_font: ct_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 { + let cg_rect = self.ct_font.get_bounding_rects_for_glyphs(orientation as CTFontOrientation, + &[index as CGGlyph]); + + Rect::new( + Point2D::new(cg_rect.origin.x, cg_rect.origin.y), + Size2D::new(cg_rect.size.width, cg_rect.size.height), + ) + } + + pub fn metrics(&self) -> Metrics { + let average_advance = self.glyph_advance('0'); + + let ascent = self.ct_font.ascent() as f64; + let descent = self.ct_font.descent() as f64; + let leading = self.ct_font.leading() as f64; + let line_height = (ascent + descent + leading + 0.5).floor(); + + Metrics { + average_advance: average_advance, + line_height: line_height, + } + } + + fn glyph_advance(&self, character: char) -> f64 { + let index = self.glyph_index(character).unwrap(); + + let indices = [index as CGGlyph]; + + self.ct_font.get_advances_for_glyphs(FontOrientation::Default as _, + &indices[0], + ptr::null_mut(), + 1) + } + + pub fn get_glyph(&self, character: char, size: f64) -> RasterizedGlyph { + let glyph_index = match self.glyph_index(character) { + Some(i) => i, + None => { + // TODO refactor this + return RasterizedGlyph { + c: ' ', + width: 0, + height: 0, + top: 0, + left: 0, + buf: Vec::new() + }; + } + }; + + let bounds = self.bounding_rect_for_glyph(Default::default(), glyph_index); + + let rasterized_left = bounds.origin.x.floor() as i32; + let rasterized_width = + (bounds.origin.x - (rasterized_left as f64) + bounds.size.width).ceil() as u32; + let rasterized_descent = (-bounds.origin.y).ceil() as i32; + let rasterized_ascent = (bounds.size.height + bounds.origin.y).ceil() as i32; + let rasterized_height = (rasterized_descent + rasterized_ascent) as u32; + + if rasterized_width == 0 || rasterized_height == 0 { + return RasterizedGlyph { + c: ' ', + width: 0, + height: 0, + top: 0, + left: 0, + buf: Vec::new() + }; + } + + let mut cg_context = CGContext::create_bitmap_context(rasterized_width as usize, + rasterized_height as usize, + 8, // bits per component + rasterized_width as usize * 4, + &CGColorSpace::create_device_rgb(), + kCGImageAlphaNoneSkipFirst); + + 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); + + let rasterization_origin = CGPoint { + x: -rasterized_left as f64, + y: rasterized_descent as f64, + }; + + self.ct_font.draw_glyphs(&[glyph_index as CGGlyph], + &[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::>(); + + RasterizedGlyph { + c: character, + left: rasterized_left, + top: (bounds.size.height + bounds.origin.y).ceil() as i32, + width: rasterized_width as i32, + height: rasterized_height as i32, + buf: buf, + } + } + + fn glyph_index(&self, character: char) -> Option { + let chars = [character as UniChar]; + let mut glyphs = [0 as CGGlyph]; + + let res = self.ct_font.get_glyphs_for_characters(&chars[0], &mut glyphs[0], 1 as CFIndex); + + if res { + Some(glyphs[0] as u32) + } else { + None + } + } +} + +/// Additional methods needed to render fonts for Alacritty +/// +/// TODO upstream these into core_graphics crate +trait CGContextExt { + fn set_allows_font_subpixel_quantization(&self, bool); + fn set_should_subpixel_quantize_fonts(&self, bool); +} + +impl CGContextExt for CGContext { + fn set_allows_font_subpixel_quantization(&self, allows: bool) { + unsafe { + CGContextSetAllowsFontSubpixelQuantization(self.as_concrete_TypeRef(), allows); + } + } + + fn set_should_subpixel_quantize_fonts(&self, should: bool) { + unsafe { + CGContextSetShouldSubpixelQuantizeFonts(self.as_concrete_TypeRef(), should); + } + } +} + +#[link(name = "ApplicationServices", kind = "framework")] +extern { + fn CGContextSetAllowsFontSubpixelQuantization(c: CGContextRef, allows: bool); + fn CGContextSetShouldSubpixelQuantizeFonts(c: CGContextRef, should: bool); +} + +#[cfg(test)] +mod tests { + #[test] + fn get_family_names() { + let names = super::get_family_names(); + assert!(names.contains(&String::from("Menlo"))); + assert!(names.contains(&String::from("Monaco"))); + } + + #[test] + fn get_descriptors_and_build_font() { + let list = super::descriptors_for_family("Menlo"); + assert!(!list.is_empty()); + println!("{:?}", list); + + // Check to_font + let fonts = list.iter() + .map(|desc| desc.to_font(72.)) + .collect::>(); + + for font in fonts { + // Check deref + println!("family: {}", font.family_name()); + + // Get a glyph + for c in &['a', 'b', 'c', 'd'] { + let glyph = font.get_glyph(*c, 72.); + + // Debug the glyph.. sigh + for row in 0..glyph.height { + for col in 0..glyph.width { + let index = ((glyph.width * 3 * row) + (col * 3)) as usize; + let value = glyph.buf[index]; + let c = match value { + 0...50 => ' ', + 51...100 => '.', + 101...150 => '~', + 151...200 => '*', + 201...255 => '#', + _ => unreachable!() + }; + print!("{}", c); + } + print!("\n"); + } + } + } + } +} diff --git a/src/list_fonts.rs b/font/src/ft/list_fonts.rs similarity index 100% rename from src/list_fonts.rs rename to font/src/ft/list_fonts.rs diff --git a/src/text.rs b/font/src/ft/mod.rs similarity index 72% rename from src/text.rs rename to font/src/ft/mod.rs index 5086a3a..f288cda 100644 --- a/src/text.rs +++ b/font/src/ft/mod.rs @@ -1,15 +1,20 @@ +//! Rasterization powered by FreeType and FontConfig use std::collections::HashMap; -use list_fonts::get_font_families; use freetype::Library; use freetype::Face; use freetype; +mod list_fonts; + +use self::list_fonts::{Family, get_font_families}; +use super::{FontDesc, RasterizedGlyph, Metrics}; + /// Rasterizes glyphs for a single font face. pub struct Rasterizer { faces: HashMap>, library: Library, - system_fonts: HashMap, + system_fonts: HashMap, dpi_x: u32, dpi_y: u32, dpr: f32, @@ -20,22 +25,10 @@ fn to_freetype_26_6(f: f32) -> isize { ((1i32 << 6) as f32 * f) as isize } -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct FontDesc { - name: String, - style: String, -} - -impl FontDesc { - pub fn new(name: S, style: S) -> FontDesc - where S: Into - { - FontDesc { - name: name.into(), - style: style.into() - } - } -} +// #[inline] +// fn freetype_26_6_to_float(val: i64) -> f64 { +// val as f64 / (1i64 << 6) as f64 +// } impl Rasterizer { pub fn new(dpi_x: f32, dpi_y: f32, device_pixel_ratio: f32) -> Rasterizer { @@ -51,22 +44,25 @@ impl Rasterizer { } } - pub fn box_size_for_font(&mut self, desc: &FontDesc, size: f32) -> (u32, u32) { + pub fn metrics(&mut self, desc: &FontDesc, size: f32) -> Metrics { let face = self.get_face(&desc).unwrap(); - let scale_size = self.dpr * size; + let scale_size = self.dpr as f64 * size as f64; - let em_size = face.em_size() as f32; - let w = face.max_advance_width() as f32; - let h = face.height() as f32; + let em_size = face.em_size() as f64; + let w = face.max_advance_width() as f64; + let h = (face.ascender() - face.descender() + face.height()) as f64; - let w_scale = w / em_size; - let h_scale = h / em_size; + let w_scale = w * scale_size / em_size; + let h_scale = h * scale_size / em_size; - ((w_scale * scale_size) as u32, (h_scale * scale_size) as u32) + Metrics { + average_advance: w_scale, + line_height: h_scale, + } } - pub fn get_face(&mut self, desc: &FontDesc) -> Option> { + fn get_face(&mut self, desc: &FontDesc) -> Option> { if let Some(face) = self.faces.get(desc) { return Some(face.clone()); } @@ -118,22 +114,12 @@ impl Rasterizer { } } -#[derive(Debug)] -pub struct RasterizedGlyph { - pub c: char, - pub width: i32, - pub height: i32, - pub top: i32, - pub left: i32, - pub buf: Vec, -} - +unsafe impl Send for Rasterizer {} #[cfg(test)] mod tests { - use super::{Rasterizer, FontDesc}; + use ::FontDesc; - #[cfg(target_os = "linux")] fn font_desc() -> FontDesc { FontDesc::new("Ubuntu Mono", "Regular") } diff --git a/font/src/lib.rs b/font/src/lib.rs new file mode 100644 index 0000000..ba632be --- /dev/null +++ b/font/src/lib.rs @@ -0,0 +1,94 @@ +//! Compatibility layer for different font engines +//! +//! This module is developed as part of Alacritty; Alacritty does not include Windows support +//! as a goal at this time, and neither does this module. +//! +//! CoreText is used on Mac OS. +//! FreeType is used on everything that's not Mac OS. + +#[cfg(not(target_os = "macos"))] +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; +#[cfg(target_os = "macos")] +extern crate core_foundation; +#[cfg(target_os = "macos")] +extern crate core_foundation_sys; +#[cfg(target_os = "macos")] +extern crate core_graphics; + +extern crate euclid; + +use std::fmt; + +// If target isn't macos, reexport everything from ft +#[cfg(not(target_os = "macos"))] +mod ft; +#[cfg(not(target_os = "macos"))] +pub use ft::*; + +// If target is macos, reexport everything from darwin +#[cfg(target_os = "macos")] +mod darwin; +#[cfg(target_os = "macos")] +pub use darwin::*; + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct FontDesc { + name: String, + style: String, +} + +impl FontDesc { + pub fn new(name: S, style: S) -> FontDesc + where S: Into + { + FontDesc { + name: name.into(), + style: style.into() + } + } +} + +pub struct RasterizedGlyph { + pub c: char, + pub width: i32, + pub height: i32, + pub top: i32, + pub left: i32, + pub buf: Vec, +} + +struct BufDebugger<'a>(&'a [u8]); + +impl<'a> fmt::Debug for BufDebugger<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("GlyphBuffer") + .field("len", &self.0.len()) + .field("bytes", &self.0) + .finish() + } +} + +impl fmt::Debug for RasterizedGlyph { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("RasterizedGlyph") + .field("c", &self.c) + .field("width", &self.width) + .field("height", &self.height) + .field("top", &self.top) + .field("left", &self.left) + .field("buf", &BufDebugger(&self.buf[..])) + .finish() + } +} + +pub struct Metrics { + pub average_advance: f64, + pub line_height: f64, +} diff --git a/res/text.v.glsl b/res/text.v.glsl index 0432bab..48d45ee 100644 --- a/res/text.v.glsl +++ b/res/text.v.glsl @@ -22,7 +22,6 @@ out vec3 bg; // Terminal properties uniform vec2 termDim; uniform vec2 cellDim; -uniform vec2 cellSep; uniform int backgroundPass; @@ -38,14 +37,14 @@ void main() vec2 uvSize = uv.zw; // Position of cell from top-left - vec2 cellPosition = (cellDim + cellSep) * gridCoords; + vec2 cellPosition = (cellDim) * gridCoords; // Invert Y since framebuffer origin is bottom-left cellPosition.y = termDim.y - cellPosition.y - cellDim.y; if (backgroundPass != 0) { cellPosition.y = cellPosition.y - 3; - vec2 finalPosition = (cellDim + cellSep) * position + cellPosition; + vec2 finalPosition = cellDim * position + cellPosition; gl_Position = projection * vec4(finalPosition.xy, 0.0, 1.0); TexCoords = vec2(0, 0); } else { diff --git a/src/grid.rs b/src/grid.rs index 7a1fedb..9ce16c8 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -9,10 +9,8 @@ use term::{Cursor, DEFAULT_FG, DEFAULT_BG}; use ::Rgb; /// Calculate the number of cells for an axis -pub fn num_cells_axis(cell_width: u32, cell_sep: i32, screen_width: u32) -> u32 { - println!("num_cells_axis(cell_width: {}, cell_sep: {}, screen_width: {}", - cell_width, cell_sep, screen_width); - ((screen_width as i32 - cell_sep) as f64 / (cell_width as i32 + cell_sep) as f64) as u32 +pub fn num_cells_axis(cell_width: u32, screen_width: u32) -> u32 { + (screen_width as f64 / cell_width as f64) as u32 } #[derive(Clone, Debug)] diff --git a/src/main.rs b/src/main.rs index f3808e0e..48f2df7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,12 +5,12 @@ #![feature(io)] #![feature(unicode)] -extern crate fontconfig; -extern crate freetype; +extern crate font; extern crate libc; extern crate glutin; extern crate cgmath; extern crate notify; +extern crate errno; #[macro_use] extern crate bitflags; @@ -18,8 +18,6 @@ extern crate bitflags; #[macro_use] mod macros; -mod list_fonts; -mod text; mod renderer; pub mod grid; mod meter; @@ -36,7 +34,7 @@ use grid::Grid; use meter::Meter; use renderer::{QuadRenderer, GlyphCache}; use term::Term; -use text::FontDesc; +use font::FontDesc; use tty::process_should_exit; use util::thread; @@ -115,41 +113,47 @@ pub struct TermProps { height: f32, cell_width: f32, cell_height: f32, - sep_x: f32, - sep_y: f32, } +#[cfg(target_os = "linux")] +static FONT: &'static str = "DejaVu Sans Mono"; +#[cfg(target_os = "linux")] +static FONT_STYLE: &'static str = "Book"; + +#[cfg(target_os = "macos")] +static FONT: &'static str = "Menlo"; +#[cfg(target_os = "macos")] +static FONT_STYLE: &'static str = "Regular"; + + fn main() { - let window = glutin::WindowBuilder::new() - .with_title("alacritty".into()) - .build() - .unwrap(); + let window = glutin::WindowBuilder::new().build().unwrap(); + window.set_title("Alacritty"); + // window.set_window_resize_callback(Some(resize_callback as fn(u32, u32))); + + gl::load_with(|symbol| window.get_proc_address(symbol) as *const _); let (width, height) = window.get_inner_size_pixels().unwrap(); - unsafe { - window.make_current().unwrap(); - } - - unsafe { - gl::load_with(|symbol| window.get_proc_address(symbol) as *const _); - gl::Viewport(0, 0, width as i32, height as i32); - } - - let (dpi_x, dpi_y) = window.get_dpi().unwrap(); let dpr = window.hidpi_factor(); + println!("device_pixel_ratio: {}", dpr); + let font_size = 11.; - let sep_x = 2; - let sep_y = 5; + let sep_x = 2.0; + let sep_y = -7.0; - let desc = FontDesc::new("DejaVu Sans Mono", "Book"); - let mut rasterizer = text::Rasterizer::new(dpi_x, dpi_y, dpr); + let desc = FontDesc::new(FONT, FONT_STYLE); + let mut rasterizer = font::Rasterizer::new(96., 96., dpr); - let (cell_width, cell_height) = rasterizer.box_size_for_font(&desc, font_size); + let metrics = rasterizer.metrics(&desc, font_size); + let cell_width = (metrics.average_advance + sep_x) as u32; + let cell_height = (metrics.line_height + sep_y) as u32; - let num_cols = grid::num_cells_axis(cell_width, sep_x, width); - let num_rows = grid::num_cells_axis(cell_height, sep_y, height); + println!("Cell Size: ({} x {})", cell_width, cell_height); + + let num_cols = grid::num_cells_axis(cell_width, width); + let num_rows = grid::num_cells_axis(cell_height, height); let tty = tty::new(num_rows as u8, num_cols as u8); tty.resize(num_rows as usize, num_cols as usize, width as usize, height as usize); @@ -162,25 +166,13 @@ fn main() { let props = TermProps { cell_width: cell_width as f32, - sep_x: sep_x as f32, cell_height: cell_height as f32, - sep_y: sep_y as f32, height: height as f32, width: width as f32, }; - let mut renderer = QuadRenderer::new(width, height); - let mut glyph_cache = GlyphCache::new(rasterizer, desc, font_size); - renderer.with_api(&props, |mut api| { - glyph_cache.init(&mut api); - }); - unsafe { - gl::Enable(gl::BLEND); - gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR); - gl::Enable(gl::MULTISAMPLE); - } let (tx, rx) = mpsc::channel(); let reader_tx = tx.clone(); @@ -198,83 +190,98 @@ fn main() { let window = Arc::new(window); let window_ref = window.clone(); - let input_thread = thread::spawn_named("Input Thread", move || { - for event in window_ref.wait_events() { - tx.send(Event::Glutin(event)).unwrap(); - if process_should_exit() { - break; - } + let render_thread = thread::spawn_named("Galaxy", move || { + let _ = unsafe { window.make_current() }; + unsafe { + gl::Viewport(0, 0, width as i32, height as i32); + gl::Enable(gl::BLEND); + gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR); + gl::Enable(gl::MULTISAMPLE); } - }); - 'main_loop: loop { - { - let mut writer = BufWriter::new(&writer); + let mut renderer = QuadRenderer::new(width, height); + renderer.with_api(&props, |mut api| { + glyph_cache.init(&mut api); + }); - // Block waiting for next event - match rx.recv() { - Ok(e) => { - let res = handle_event(e, &mut writer, &mut terminal, &mut pty_parser); - if res == ShouldExit::Yes { - break; - } - }, - Err(mpsc::RecvError) => break, - } + 'main_loop: loop { + { + let mut writer = BufWriter::new(&writer); - // Handle Any events that have been queued - loop { - match rx.try_recv() { + // Block waiting for next event + match rx.recv() { Ok(e) => { let res = handle_event(e, &mut writer, &mut terminal, &mut pty_parser); - if res == ShouldExit::Yes { break; } }, - Err(mpsc::TryRecvError::Disconnected) => break 'main_loop, - Err(mpsc::TryRecvError::Empty) => break, + Err(mpsc::RecvError) => break, } - // TODO make sure this doesn't block renders + // Handle Any events that have been queued + loop { + match rx.try_recv() { + Ok(e) => { + let res = handle_event(e, &mut writer, &mut terminal, &mut pty_parser); + + if res == ShouldExit::Yes { + break; + } + }, + Err(mpsc::TryRecvError::Disconnected) => break 'main_loop, + Err(mpsc::TryRecvError::Empty) => break, + } + + // TODO make sure this doesn't block renders + } + } + + unsafe { + gl::ClearColor(0.0, 0.0, 0.00, 1.0); + gl::Clear(gl::COLOR_BUFFER_BIT); + } + + { + let _sampler = meter.sampler(); + + renderer.with_api(&props, |mut api| { + // Draw the grid + api.render_grid(terminal.grid(), &mut glyph_cache); + + // Also draw the cursor + if !terminal.mode().contains(term::mode::TEXT_CURSOR) { + api.render_cursor(terminal.cursor(), &mut glyph_cache); + } + }) + } + + // Draw render timer + let timing = format!("{:.3} usec", meter.average()); + let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 }; + renderer.with_api(&props, |mut api| { + api.render_string(&timing[..], &mut glyph_cache, &color); + }); + + window.swap_buffers().unwrap(); + + if process_should_exit() { + break 'main_loop; } } + }); - unsafe { - gl::ClearColor(0.0, 0.0, 0.00, 1.0); - gl::Clear(gl::COLOR_BUFFER_BIT); - } - - { - let _sampler = meter.sampler(); - - renderer.with_api(&props, |mut api| { - // Draw the grid - api.render_grid(terminal.grid(), &mut glyph_cache); - - // Also draw the cursor - if !terminal.mode().contains(term::mode::TEXT_CURSOR) { - api.render_cursor(terminal.cursor(), &mut glyph_cache); - } - }) - } - - // Draw render timer - let timing = format!("{:.3} usec", meter.average()); - let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 }; - renderer.with_api(&props, |mut api| { - api.render_string(&timing[..], &mut glyph_cache, &color); - }); - - window.swap_buffers().unwrap(); - - if process_should_exit() { - break; + 'event_processing: loop { + for event in window_ref.wait_events() { + tx.send(Event::Glutin(event)).unwrap(); + if process_should_exit() { + break 'event_processing; + } } } reader_thread.join().ok(); - input_thread.join().ok(); + render_thread.join().ok(); println!("Goodbye"); } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index a0051aa..dff2007 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -13,7 +13,7 @@ use gl::types::*; use gl; use notify::{Watcher as WatcherApi, RecommendedWatcher as Watcher, op}; -use text::{Rasterizer, RasterizedGlyph, FontDesc}; +use font::{Rasterizer, RasterizedGlyph, FontDesc}; use grid::{self, Grid, Cell, CellFlags}; use term; @@ -45,9 +45,6 @@ pub struct ShaderProgram { /// Cell dimensions (pixels) u_cell_dim: GLint, - /// Cell separation (pixels) - u_cell_sep: GLint, - /// Background pass flag /// /// Rendering is split into two passes; 1 for backgrounds, and one for text @@ -649,24 +646,22 @@ impl ShaderProgram { } // get uniform locations - let (projection, term_dim, cell_dim, cell_sep, background) = unsafe { + let (projection, term_dim, cell_dim, background) = unsafe { ( gl::GetUniformLocation(program, cptr!(b"projection\0")), gl::GetUniformLocation(program, cptr!(b"termDim\0")), gl::GetUniformLocation(program, cptr!(b"cellDim\0")), - gl::GetUniformLocation(program, cptr!(b"cellSep\0")), gl::GetUniformLocation(program, cptr!(b"backgroundPass\0")), ) }; - assert_uniform_valid!(projection, term_dim, cell_dim, cell_sep); + assert_uniform_valid!(projection, term_dim, cell_dim); let shader = ShaderProgram { id: program, u_projection: projection, u_term_dim: term_dim, u_cell_dim: cell_dim, - u_cell_sep: cell_sep, u_background: background, }; @@ -690,7 +685,6 @@ impl ShaderProgram { unsafe { gl::Uniform2f(self.u_term_dim, props.width, props.height); gl::Uniform2f(self.u_cell_dim, props.cell_width, props.cell_height); - gl::Uniform2f(self.u_cell_sep, props.sep_x, props.sep_y); } } diff --git a/src/tty.rs b/src/tty.rs index 89975b4..a653d9a 100644 --- a/src/tty.rs +++ b/src/tty.rs @@ -47,9 +47,7 @@ pub fn process_should_exit() -> bool { /// Get the current value of errno fn errno() -> c_int { - unsafe { - ptr::read(libc::__errno_location() as *const _) - } + ::errno::errno().0 } enum Relation { @@ -74,6 +72,7 @@ fn fork() -> Relation { } /// Get raw fds for master/slave ends of a new pty +#[cfg(target_os = "linux")] fn openpty(rows: u8, cols: u8) -> (c_int, c_int) { let mut master: c_int = 0; let mut slave: c_int = 0; @@ -96,10 +95,33 @@ fn openpty(rows: u8, cols: u8) -> (c_int, c_int) { (master, slave) } +#[cfg(target_os = "macos")] +fn openpty(rows: u8, cols: u8) -> (c_int, c_int) { + let mut master: c_int = 0; + let mut slave: c_int = 0; + + let mut win = winsize { + ws_row: rows as libc::c_ushort, + ws_col: cols as libc::c_ushort, + ws_xpixel: 0, + ws_ypixel: 0, + }; + + let res = unsafe { + libc::openpty(&mut master, &mut slave, ptr::null_mut(), ptr::null_mut(), &mut win) + }; + + if res < 0 { + die!("openpty failed"); + } + + (master, slave) +} + /// Really only needed on BSD, but should be fine elsewhere fn set_controlling_terminal(fd: c_int) { let res = unsafe { - libc::ioctl(fd, libc::TIOCSCTTY, 0) + libc::ioctl(fd, libc::TIOCSCTTY as _, 0) }; if res < 0 { @@ -125,15 +147,7 @@ struct Passwd<'a> { /// If `buf` is changed while `Passwd` is alive, bad thing will almost certainly happen. fn get_pw_entry<'a>(buf: &'a mut [i8; 1024]) -> Passwd<'a> { // Create zeroed passwd struct - let mut entry = libc::passwd { - pw_name: ptr::null_mut(), - pw_passwd: ptr::null_mut(), - pw_uid: 0, - pw_gid: 0, - pw_gecos: ptr::null_mut(), - pw_dir: ptr::null_mut(), - pw_shell: ptr::null_mut(), - }; + let mut entry: libc::passwd = unsafe { ::std::mem::uninitialized() }; let mut res: *mut libc::passwd = ptr::null_mut();