diff --git a/core-graphics/.gitignore b/core-graphics/.gitignore new file mode 100644 index 0000000..c34fbd0 --- /dev/null +++ b/core-graphics/.gitignore @@ -0,0 +1,14 @@ +*~ +*# +*.o +*.a +*.so +*.dylib +*.dSYM +*.dll +*.dummy +cocoa-test +build +/target +/doc +/Cargo.lock diff --git a/core-graphics/.travis.yml b/core-graphics/.travis.yml new file mode 100644 index 0000000..f741543 --- /dev/null +++ b/core-graphics/.travis.yml @@ -0,0 +1,13 @@ +language: rust +os: osx +rust: + - nightly + - beta + - stable + +script: + - cargo test + - cargo test --features="elcapitan" + +notifications: + webhooks: http://build.servo.org:54856/travis diff --git a/core-graphics/COPYRIGHT b/core-graphics/COPYRIGHT new file mode 100644 index 0000000..8b7291a --- /dev/null +++ b/core-graphics/COPYRIGHT @@ -0,0 +1,5 @@ +Licensed under the Apache License, Version 2.0 or the MIT license +, at your +option. All files in the project carrying such notice may not be +copied, modified, or distributed except according to those terms. diff --git a/core-graphics/Cargo.toml b/core-graphics/Cargo.toml new file mode 100644 index 0000000..3c18a56 --- /dev/null +++ b/core-graphics/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "core-graphics" +description = "Bindings to Core Graphics for OS X" +homepage = "https://github.com/servo/core-graphics-rs" +repository = "https://github.com/servo/core-graphics-rs" +version = "0.13.0" +authors = ["The Servo Project Developers"] +license = "MIT / Apache-2.0" + +[features] +default = [] +elcapitan = [] + +[dependencies] +bitflags = "1.0" +core-foundation = "0.5" +foreign-types = "0.3.0" +libc = "0.2" diff --git a/core-graphics/LICENSE-APACHE b/core-graphics/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/core-graphics/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/core-graphics/LICENSE-MIT b/core-graphics/LICENSE-MIT new file mode 100644 index 0000000..807526f --- /dev/null +++ b/core-graphics/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2012-2013 Mozilla Foundation + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/core-graphics/README.md b/core-graphics/README.md new file mode 100644 index 0000000..a23522d --- /dev/null +++ b/core-graphics/README.md @@ -0,0 +1,3 @@ +# core-graphics-rs + +[![Build Status](https://travis-ci.org/servo/core-graphics-rs.svg?branch=master)](https://travis-ci.org/servo/core-graphics-rs) diff --git a/core-graphics/src/base.rs b/core-graphics/src/base.rs new file mode 100644 index 0000000..f5c954d --- /dev/null +++ b/core-graphics/src/base.rs @@ -0,0 +1,53 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// this file defines CGFloat, as well as stubbed data types. + +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] + +use libc; + +#[cfg(any(target_arch = "x86", + target_arch = "arm", + target_arch = "aarch64"))] +pub type boolean_t = libc::c_int; +#[cfg(target_arch = "x86_64")] +pub type boolean_t = libc::c_uint; + +#[cfg(target_pointer_width = "64")] +pub type CGFloat = libc::c_double; +#[cfg(not(target_pointer_width = "64"))] +pub type CGFloat = libc::c_float; + +pub type CGError = libc::int32_t; + +pub const kCGImageAlphaNone: u32 = 0; +pub const kCGImageAlphaPremultipliedLast: u32 = 1; +pub const kCGImageAlphaPremultipliedFirst: u32 = 2; +pub const kCGImageAlphaLast: u32 = 3; +pub const kCGImageAlphaFirst: u32 = 4; +pub const kCGImageAlphaNoneSkipLast: u32 = 5; +pub const kCGImageAlphaNoneSkipFirst: u32 = 6; + +pub const kCGBitmapByteOrderDefault: u32 = (0 << 12); +pub const kCGBitmapByteOrder16Little: u32 = (1 << 12); +pub const kCGBitmapByteOrder32Little: u32 = (2 << 12); +pub const kCGBitmapByteOrder16Big: u32 = (3 << 12); +pub const kCGBitmapByteOrder32Big: u32 = (4 << 12); + +#[cfg(target_endian = "big")] +pub const kCGBitmapByteOrder16Host: u32 = kCGBitmapByteOrder16Big; +#[cfg(target_endian = "big")] +pub const kCGBitmapByteOrder32Host: u32 = kCGBitmapByteOrder32Big; + +#[cfg(target_endian = "little")] +pub const kCGBitmapByteOrder16Host: u32 = kCGBitmapByteOrder16Little; +#[cfg(target_endian = "little")] +pub const kCGBitmapByteOrder32Host: u32 = kCGBitmapByteOrder32Little; diff --git a/core-graphics/src/color_space.rs b/core-graphics/src/color_space.rs new file mode 100644 index 0000000..67f2504 --- /dev/null +++ b/core-graphics/src/color_space.rs @@ -0,0 +1,59 @@ +// Copyright 2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core_foundation::base::{CFRelease, CFRetain, CFTypeID}; +use core_foundation::string::CFStringRef; +use foreign_types::ForeignType; + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGColorSpace; + fn drop = |p| CFRelease(p as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGColorSpace; + pub struct CGColorSpaceRef; +} + +impl CGColorSpace { + pub fn type_id() -> CFTypeID { + unsafe { + CGColorSpaceGetTypeID() + } + } + + pub fn create_with_name(name: CFStringRef) -> Option { + unsafe { + let p = CGColorSpaceCreateWithName(name); + if !p.is_null() {Some(CGColorSpace::from_ptr(p))} else {None} + } + } + + pub fn create_device_rgb() -> CGColorSpace { + unsafe { + let result = CGColorSpaceCreateDeviceRGB(); + CGColorSpace::from_ptr(result) + } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + pub static kCGColorSpaceSRGB: CFStringRef; + pub static kCGColorSpaceAdobeRGB1998: CFStringRef; + pub static kCGColorSpaceGenericGray: CFStringRef; + pub static kCGColorSpaceGenericRGB: CFStringRef; + pub static kCGColorSpaceGenericCMYK: CFStringRef; + pub static kCGColorSpaceGenericRGBLinear: CFStringRef; + pub static kCGColorSpaceGenericGrayGamma2_2: CFStringRef; + + fn CGColorSpaceCreateDeviceRGB() -> ::sys::CGColorSpaceRef; + fn CGColorSpaceCreateWithName(name: CFStringRef) -> ::sys::CGColorSpaceRef; + fn CGColorSpaceGetTypeID() -> CFTypeID; +} + diff --git a/core-graphics/src/context.rs b/core-graphics/src/context.rs new file mode 100644 index 0000000..2030b0f --- /dev/null +++ b/core-graphics/src/context.rs @@ -0,0 +1,284 @@ +// Copyright 2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base::CGFloat; +use color_space::CGColorSpace; +use core_foundation::base::{CFRelease, CFRetain, CFTypeID}; +use font::{CGFont, CGGlyph}; +use geometry::CGPoint; +use libc::{c_void, c_int, size_t}; + +use std::cmp; +use std::ptr; +use std::slice; +use geometry::{CGAffineTransform, CGRect}; +use image::CGImage; +use foreign_types::ForeignType; + +#[repr(C)] +pub enum CGTextDrawingMode { + CGTextFill, + CGTextStroke, + CGTextFillStroke, + CGTextInvisible, + CGTextFillClip, + CGTextStrokeClip, + CGTextClip +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGContext; + fn drop = |cs| CFRelease(cs as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGContext; + pub struct CGContextRef; +} + +impl CGContext { + pub fn type_id() -> CFTypeID { + unsafe { + CGContextGetTypeID() + } + } + + pub fn create_bitmap_context(data: Option<*mut c_void>, + width: size_t, + height: size_t, + bits_per_component: size_t, + bytes_per_row: size_t, + space: &CGColorSpace, + bitmap_info: u32) + -> CGContext { + unsafe { + let result = CGBitmapContextCreate(data.unwrap_or(ptr::null_mut()), + width, + height, + bits_per_component, + bytes_per_row, + space.as_ptr(), + bitmap_info); + assert!(!result.is_null()); + Self::from_ptr(result) + } + } + + pub fn data(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut( + CGBitmapContextGetData(self.as_ptr()) as *mut u8, + (self.height() * self.bytes_per_row()) as usize) + } + } + + pub fn width(&self) -> size_t { + unsafe { + CGBitmapContextGetWidth(self.as_ptr()) + } + } + + pub fn height(&self) -> size_t { + unsafe { + CGBitmapContextGetHeight(self.as_ptr()) + } + } + + pub fn bytes_per_row(&self) -> size_t { + unsafe { + CGBitmapContextGetBytesPerRow(self.as_ptr()) + } + } + + pub fn set_rgb_fill_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { + unsafe { + CGContextSetRGBFillColor(self.as_ptr(), red, green, blue, alpha) + } + } + + pub fn set_allows_font_smoothing(&self, allows_font_smoothing: bool) { + unsafe { + CGContextSetAllowsFontSmoothing(self.as_ptr(), allows_font_smoothing) + } + } + + pub fn set_font_smoothing_style(&self, style: i32) { + unsafe { + CGContextSetFontSmoothingStyle(self.as_ptr(), style as _); + } + } + + pub fn set_should_smooth_fonts(&self, should_smooth_fonts: bool) { + unsafe { + CGContextSetShouldSmoothFonts(self.as_ptr(), should_smooth_fonts) + } + } + + pub fn set_allows_antialiasing(&self, allows_antialiasing: bool) { + unsafe { + CGContextSetAllowsAntialiasing(self.as_ptr(), allows_antialiasing) + } + } + + pub fn set_should_antialias(&self, should_antialias: bool) { + unsafe { + CGContextSetShouldAntialias(self.as_ptr(), should_antialias) + } + } + + pub fn set_allows_font_subpixel_quantization(&self, allows_font_subpixel_quantization: bool) { + unsafe { + CGContextSetAllowsFontSubpixelQuantization(self.as_ptr(), allows_font_subpixel_quantization) + } + } + + pub fn set_should_subpixel_quantize_fonts(&self, should_subpixel_quantize_fonts: bool) { + unsafe { + CGContextSetShouldSubpixelQuantizeFonts(self.as_ptr(), should_subpixel_quantize_fonts) + } + } + + pub fn set_allows_font_subpixel_positioning(&self, allows_font_subpixel_positioning: bool) { + unsafe { + CGContextSetAllowsFontSubpixelPositioning(self.as_ptr(), allows_font_subpixel_positioning) + } + } + + pub fn set_should_subpixel_position_fonts(&self, should_subpixel_position_fonts: bool) { + unsafe { + CGContextSetShouldSubpixelPositionFonts(self.as_ptr(), should_subpixel_position_fonts) + } + } + + pub fn set_text_drawing_mode(&self, mode: CGTextDrawingMode) { + unsafe { + CGContextSetTextDrawingMode(self.as_ptr(), mode) + } + } + + pub fn fill_rect(&self, rect: CGRect) { + unsafe { + CGContextFillRect(self.as_ptr(), rect) + } + } + + pub fn draw_image(&self, rect: CGRect, image: &CGImage) { + unsafe { + CGContextDrawImage(self.as_ptr(), rect, image.as_ptr()); + } + } + + pub fn create_image(&self) -> Option { + let image = unsafe { CGBitmapContextCreateImage(self.as_ptr()) }; + if !image.is_null() { + Some(unsafe { CGImage::from_ptr(image) }) + } else { + None + } + } + + pub fn set_font(&self, font: &CGFont) { + unsafe { + CGContextSetFont(self.as_ptr(), font.as_ptr()) + } + } + + pub fn set_font_size(&self, size: CGFloat) { + unsafe { + CGContextSetFontSize(self.as_ptr(), size) + } + } + + pub fn set_text_matrix(&self, t: &CGAffineTransform) { + unsafe { + CGContextSetTextMatrix(self.as_ptr(), *t) + } + } + + pub fn show_glyphs_at_positions(&self, glyphs: &[CGGlyph], positions: &[CGPoint]) { + unsafe { + let count = cmp::min(glyphs.len(), positions.len()); + CGContextShowGlyphsAtPositions(self.as_ptr(), + glyphs.as_ptr(), + positions.as_ptr(), + count) + } + } +} + +#[test] +fn create_bitmap_context_test() { + use geometry::*; + + let cs = CGColorSpace::create_device_rgb(); + let ctx = CGContext::create_bitmap_context(None, + 16, 8, + 8, 0, + &cs, + ::base::kCGImageAlphaPremultipliedLast); + ctx.set_rgb_fill_color(1.,0.,1.,1.); + ctx.fill_rect(CGRect::new(&CGPoint::new(0.,0.), &CGSize::new(8.,8.))); + let img = ctx.create_image().unwrap(); + assert_eq!(16, img.width()); + assert_eq!(8, img.height()); + assert_eq!(8, img.bits_per_component()); + assert_eq!(32, img.bits_per_pixel()); + let data = img.data(); + assert_eq!(255, data.bytes()[0]); + assert_eq!(0, data.bytes()[1]); + assert_eq!(255, data.bytes()[2]); + assert_eq!(255, data.bytes()[3]); +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + fn CGBitmapContextCreate(data: *mut c_void, + width: size_t, + height: size_t, + bitsPerComponent: size_t, + bytesPerRow: size_t, + space: ::sys::CGColorSpaceRef, + bitmapInfo: u32) + -> ::sys::CGContextRef; + fn CGBitmapContextGetData(context: ::sys::CGContextRef) -> *mut c_void; + fn CGBitmapContextGetWidth(context: ::sys::CGContextRef) -> size_t; + fn CGBitmapContextGetHeight(context: ::sys::CGContextRef) -> size_t; + fn CGBitmapContextGetBytesPerRow(context: ::sys::CGContextRef) -> size_t; + fn CGBitmapContextCreateImage(context: ::sys::CGContextRef) -> ::sys::CGImageRef; + fn CGContextGetTypeID() -> CFTypeID; + fn CGContextSetAllowsFontSmoothing(c: ::sys::CGContextRef, allowsFontSmoothing: bool); + fn CGContextSetShouldSmoothFonts(c: ::sys::CGContextRef, shouldSmoothFonts: bool); + fn CGContextSetFontSmoothingStyle(c: ::sys::CGContextRef, style: c_int); + fn CGContextSetAllowsAntialiasing(c: ::sys::CGContextRef, allowsAntialiasing: bool); + fn CGContextSetShouldAntialias(c: ::sys::CGContextRef, shouldAntialias: bool); + fn CGContextSetAllowsFontSubpixelQuantization(c: ::sys::CGContextRef, + allowsFontSubpixelQuantization: bool); + fn CGContextSetShouldSubpixelQuantizeFonts(c: ::sys::CGContextRef, + shouldSubpixelQuantizeFonts: bool); + fn CGContextSetAllowsFontSubpixelPositioning(c: ::sys::CGContextRef, + allowsFontSubpixelPositioning: bool); + fn CGContextSetShouldSubpixelPositionFonts(c: ::sys::CGContextRef, + shouldSubpixelPositionFonts: bool); + fn CGContextSetTextDrawingMode(c: ::sys::CGContextRef, mode: CGTextDrawingMode); + fn CGContextSetRGBFillColor(context: ::sys::CGContextRef, + red: CGFloat, + green: CGFloat, + blue: CGFloat, + alpha: CGFloat); + fn CGContextFillRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextDrawImage(c: ::sys::CGContextRef, rect: CGRect, image: ::sys::CGImageRef); + fn CGContextSetFont(c: ::sys::CGContextRef, font: ::sys::CGFontRef); + fn CGContextSetFontSize(c: ::sys::CGContextRef, size: CGFloat); + fn CGContextSetTextMatrix(c: ::sys::CGContextRef, t: CGAffineTransform); + fn CGContextShowGlyphsAtPositions(c: ::sys::CGContextRef, + glyphs: *const CGGlyph, + positions: *const CGPoint, + count: size_t); +} + diff --git a/core-graphics/src/data_provider.rs b/core-graphics/src/data_provider.rs new file mode 100644 index 0000000..9a10496 --- /dev/null +++ b/core-graphics/src/data_provider.rs @@ -0,0 +1,89 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core_foundation::base::{CFRelease, CFRetain, CFTypeID, TCFType}; +use core_foundation::data::{CFData, CFDataRef}; + +use libc::{c_void, size_t, off_t}; +use std::mem; +use std::sync::Arc; + +use foreign_types::{ForeignType, ForeignTypeRef}; + +pub type CGDataProviderGetBytesCallback = Option size_t>; +pub type CGDataProviderReleaseInfoCallback = Option; +pub type CGDataProviderRewindCallback = Option; +pub type CGDataProviderSkipBytesCallback = Option; +pub type CGDataProviderSkipForwardCallback = Option off_t>; + +pub type CGDataProviderGetBytePointerCallback = Option *mut c_void>; +pub type CGDataProviderGetBytesAtOffsetCallback = Option; +pub type CGDataProviderReleaseBytePointerCallback = Option; +pub type CGDataProviderReleaseDataCallback = Option; +pub type CGDataProviderGetBytesAtPositionCallback = Option; + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGDataProvider; + fn drop = |cs| CFRelease(cs as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGDataProvider; + pub struct CGDataProviderRef; +} + +impl CGDataProvider { + pub fn type_id() -> CFTypeID { + unsafe { + CGDataProviderGetTypeID() + } + } + + /// Creates a data provider from the given reference-counted buffer. + /// + /// The `CGDataProvider` object takes ownership of the reference. Once the data provider + /// is destroyed, the reference count of the buffer is automatically decremented. + pub fn from_buffer(buffer: Arc>) -> Self { + unsafe { + let ptr = (*buffer).as_ptr() as *const c_void; + let len = buffer.len() as size_t; + let info = mem::transmute::>, *mut c_void>(buffer); + let result = CGDataProviderCreateWithData(info, ptr, len, Some(release)); + return CGDataProvider::from_ptr(result); + } + + unsafe extern "C" fn release(info: *mut c_void, _: *const c_void, _: size_t) { + drop(mem::transmute::<*mut c_void, Arc>>(info)) + } + } +} + +impl CGDataProviderRef { + /// Creates a copy of the data from the underlying `CFDataProviderRef`. + pub fn copy_data(&self) -> CFData { + unsafe { CFData::wrap_under_create_rule(CGDataProviderCopyData(self.as_ptr())) } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + fn CGDataProviderCopyData(provider: ::sys::CGDataProviderRef) -> CFDataRef; + //fn CGDataProviderCreateDirect + //fn CGDataProviderCreateSequential + //fn CGDataProviderCreateWithCFData + fn CGDataProviderCreateWithData(info: *mut c_void, + data: *const c_void, + size: size_t, + releaseData: CGDataProviderReleaseDataCallback + ) -> ::sys::CGDataProviderRef; + //fn CGDataProviderCreateWithFilename(filename: *c_char) -> CGDataProviderRef; + //fn CGDataProviderCreateWithURL + fn CGDataProviderGetTypeID() -> CFTypeID; + //fn CGDataProviderRelease(provider: CGDataProviderRef); + //fn CGDataProviderRetain(provider: CGDataProviderRef) -> CGDataProviderRef; +} diff --git a/core-graphics/src/display.rs b/core-graphics/src/display.rs new file mode 100644 index 0000000..0b1c8b2 --- /dev/null +++ b/core-graphics/src/display.rs @@ -0,0 +1,468 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_upper_case_globals)] + +use libc; +use std::ptr; +pub use base::{CGError, boolean_t}; +pub use geometry::{CGRect, CGPoint, CGSize}; + +use core_foundation::base::{CFRetain, TCFType}; +use image::CGImage; +use foreign_types::ForeignType; + +pub type CGDirectDisplayID = libc::uint32_t; +pub type CGWindowID = libc::uint32_t; + +pub const kCGNullWindowID: CGWindowID = 0 as CGWindowID; + + +pub type CGWindowListOption = libc::uint32_t; + +pub const kCGWindowListOptionAll: CGWindowListOption = 0; +pub const kCGWindowListOptionOnScreenOnly: CGWindowListOption = 1 << 0; +pub const kCGWindowListOptionOnScreenAboveWindow: CGWindowListOption = 1 << 1; +pub const kCGWindowListOptionOnScreenBelowWindow: CGWindowListOption = 1 << 2; +pub const kCGWindowListOptionIncludingWindow: CGWindowListOption = 1 << 3; +pub const kCGWindowListExcludeDesktopElements: CGWindowListOption = 1 << 4; + +pub type CGWindowImageOption = libc::uint32_t; + +pub const kCGWindowImageDefault: CGWindowImageOption = 0; +pub const kCGWindowImageBoundsIgnoreFraming: CGWindowImageOption = 1 << 0; +pub const kCGWindowImageShouldBeOpaque: CGWindowImageOption = 1 << 1; +pub const kCGWindowImageOnlyShadows: CGWindowImageOption = 1 << 2; +pub const kCGWindowImageBestResolution: CGWindowImageOption = 1 << 3; +pub const kCGWindowImageNominalResolution: CGWindowImageOption = 1 << 4; + +pub use core_foundation::dictionary::{ CFDictionary, CFDictionaryRef, CFDictionaryGetValueIfPresent }; +pub use core_foundation::array::{ CFArray, CFArrayRef }; +pub use core_foundation::array::{ CFArrayGetCount, CFArrayGetValueAtIndex }; +pub use core_foundation::base::{ CFIndex, CFRelease, CFTypeRef }; + +#[derive(Copy, Clone, Debug)] +pub struct CGDisplay { + pub id: CGDirectDisplayID, +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGDisplayMode; + fn drop = CGDisplayModeRelease; + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGDisplayMode; + pub struct CGDisplayModeRef; +} + +impl CGDisplay { + #[inline] + pub fn new(id: CGDirectDisplayID) -> CGDisplay { + CGDisplay { id: id } + } + + /// Returns the the main display. + #[inline] + pub fn main() -> CGDisplay { + CGDisplay::new(unsafe { CGMainDisplayID() }) + } + + /// Returns the bounds of a display in the global display coordinate space. + #[inline] + pub fn bounds(&self) -> CGRect { + unsafe { CGDisplayBounds(self.id) } + } + + /// Returns information about a display's current configuration. + #[inline] + pub fn display_mode(&self) -> Option { + unsafe { + let mode_ref = CGDisplayCopyDisplayMode(self.id); + if !mode_ref.is_null() { + Some(CGDisplayMode::from_ptr(mode_ref)) + } else { + None + } + } + } + + /// Returns an image containing the contents of the specified display. + #[inline] + pub fn image(&self) -> Option { + unsafe { + let image_ref = CGDisplayCreateImage(self.id); + if !image_ref.is_null() { + Some(CGImage::from_ptr(image_ref)) + } else { + None + } + } + } + + /// Returns a composite image based on a dynamically generated list of + /// windows. + #[inline] + pub fn screenshot( + bounds: CGRect, + list_option: CGWindowListOption, + window_id: CGWindowID, + image_option: CGWindowImageOption, + ) -> Option { + unsafe { + let image_ref = CGWindowListCreateImage(bounds, list_option, window_id, image_option); + if !image_ref.is_null() { + Some(CGImage::from_ptr(image_ref)) + } else { + None + } + } + } + + /// Returns a composite image of the specified windows. + #[inline] + pub fn screenshot_from_windows( + bounds: CGRect, + windows: CFArray, + image_option: CGWindowImageOption, + ) -> Option { + unsafe { + let image_ref = CGWindowListCreateImageFromArray( + bounds, + windows.as_concrete_TypeRef(), + image_option, + ); + if !image_ref.is_null() { + Some(CGImage::from_ptr(image_ref)) + } else { + None + } + } + } + + /// Generates and returns information about the selected windows in the + /// current user session. + pub fn window_list_info( + option: CGWindowListOption, + relative_to_window: Option, + ) -> Option { + let relative_to_window = relative_to_window.unwrap_or(kCGNullWindowID); + let array_ref = unsafe { CGWindowListCopyWindowInfo(option, relative_to_window) }; + if array_ref != ptr::null() { + Some(unsafe { TCFType::wrap_under_create_rule(array_ref) }) + } else { + None + } + } + + /// Returns a Boolean value indicating whether a display is active. + #[inline] + pub fn is_active(&self) -> bool { + unsafe { CGDisplayIsActive(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is always in a + /// mirroring set. + #[inline] + pub fn is_always_in_mirror_set(&self) -> bool { + unsafe { CGDisplayIsAlwaysInMirrorSet(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is sleeping (and is + /// therefore not drawable.) + #[inline] + pub fn is_asleep(&self) -> bool { + unsafe { CGDisplayIsAsleep(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is built-in, such as + /// the internal display in portable systems. + #[inline] + pub fn is_builtin(&self) -> bool { + unsafe { CGDisplayIsBuiltin(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is in a hardware + /// mirroring set. + #[inline] + pub fn is_in_hw_mirror_set(&self) -> bool { + unsafe { CGDisplayIsInHWMirrorSet(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is in a mirroring set. + #[inline] + pub fn is_in_mirror_set(&self) -> bool { + unsafe { CGDisplayIsInMirrorSet(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is the main display. + #[inline] + pub fn is_main(&self) -> bool { + unsafe { CGDisplayIsMain(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is connected or online. + #[inline] + pub fn is_online(&self) -> bool { + unsafe { CGDisplayIsOnline(self.id) != 0 } + } + + /// Returns a boolean indicating whether Quartz is using OpenGL-based + /// window acceleration (Quartz Extreme) to render in a display. + #[inline] + pub fn uses_open_gl_acceleration(&self) -> bool { + unsafe { CGDisplayUsesOpenGLAcceleration(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is running in a stereo + /// graphics mode. + #[inline] + pub fn is_stereo(&self) -> bool { + unsafe { CGDisplayIsStereo(self.id) != 0 } + } + + /// For a secondary display in a mirroring set, returns the primary + /// display. + #[inline] + pub fn mirrors_display(&self) -> CGDirectDisplayID { + unsafe { CGDisplayMirrorsDisplay(self.id) } + } + + /// Returns the primary display in a hardware mirroring set. + #[inline] + pub fn primary_display(&self) -> CGDirectDisplayID { + unsafe { CGDisplayPrimaryDisplay(self.id) } + } + + /// Returns the rotation angle of a display in degrees. + #[inline] + pub fn rotation(&self) -> f64 { + unsafe { CGDisplayRotation(self.id) } + } + + /// Returns the width and height of a display in millimeters. + #[inline] + pub fn screen_size(&self) -> CGSize { + unsafe { CGDisplayScreenSize(self.id) } + } + + /// Returns the serial number of a display monitor. + #[inline] + pub fn serial_number(&self) -> u32 { + unsafe { CGDisplaySerialNumber(self.id) } + } + + /// Returns the logical unit number of a display. + #[inline] + pub fn unit_number(&self) -> u32 { + unsafe { CGDisplayUnitNumber(self.id) } + } + + /// Returns the vendor number of the specified display's monitor. + #[inline] + pub fn vendor_number(&self) -> u32 { + unsafe { CGDisplayVendorNumber(self.id) } + } + + /// Returns the model number of a display monitor. + #[inline] + pub fn model_number(&self) -> u32 { + unsafe { CGDisplayModelNumber(self.id) } + } + + /// Returns the display height in pixel units. + #[inline] + pub fn pixels_high(&self) -> u64 { + unsafe { CGDisplayPixelsHigh(self.id) as u64 } + } + + /// Returns the display width in pixel units. + #[inline] + pub fn pixels_wide(&self) -> u64 { + unsafe { CGDisplayPixelsWide(self.id) as u64 } + } + + /// Provides a list of displays that are active (or drawable). + #[inline] + pub fn active_displays() -> Result, CGError> { + let count = try!(CGDisplay::active_display_count()); + let mut buf: Vec = vec![0; count as usize]; + let result = + unsafe { CGGetActiveDisplayList(count as u32, buf.as_mut_ptr(), ptr::null_mut()) }; + if result == 0 { + Ok(buf) + } else { + Err(result) + } + } + + /// Provides count of displays that are active (or drawable). + #[inline] + pub fn active_display_count() -> Result { + let mut count: libc::uint32_t = 0; + let result = unsafe { CGGetActiveDisplayList(0, ptr::null_mut(), &mut count) }; + if result == 0 { + Ok(count as u32) + } else { + Err(result) + } + } + + /// Hides the mouse cursor, and increments the hide cursor count. + #[inline] + pub fn hide_cursor(&self) -> Result<(), CGError> { + let result = unsafe { CGDisplayHideCursor(self.id) }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Decrements the hide cursor count, and shows the mouse cursor if the + /// count is 0. + #[inline] + pub fn show_cursor(&self) -> Result<(), CGError> { + let result = unsafe { CGDisplayShowCursor(self.id) }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Moves the mouse cursor to a specified point relative to the display + /// origin (the upper-left corner of the display). + #[inline] + pub fn move_cursor_to_point(&self, point: CGPoint) -> Result<(), CGError> { + let result = unsafe { CGDisplayMoveCursorToPoint(self.id, point) }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Moves the mouse cursor without generating events. + #[inline] + pub fn warp_mouse_cursor_position(point: CGPoint) -> Result<(), CGError> { + let result = unsafe { CGWarpMouseCursorPosition(point) }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Connects or disconnects the mouse and cursor while an application is + /// in the foreground. + #[inline] + pub fn associate_mouse_and_mouse_cursor_position(connected: bool) -> Result<(), CGError> { + let result = unsafe { CGAssociateMouseAndMouseCursorPosition(connected as boolean_t) }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } +} + +impl CGDisplayMode { + #[inline] + pub fn height(&self) -> u64 { + unsafe { CGDisplayModeGetHeight(self.as_ptr()) as u64 } + } + + #[inline] + pub fn width(&self) -> u64 { + unsafe { CGDisplayModeGetWidth(self.as_ptr()) as u64 } + } + + #[inline] + pub fn pixel_height(&self) -> u64 { + unsafe { CGDisplayModeGetPixelHeight(self.as_ptr()) as u64 } + } + + #[inline] + pub fn pixel_width(&self) -> u64 { + unsafe { CGDisplayModeGetPixelWidth(self.as_ptr()) as u64 } + } + + #[inline] + pub fn refresh_rate(&self) -> f64 { + unsafe { CGDisplayModeGetRefreshRate(self.as_ptr()) } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern "C" { + pub static CGRectNull: CGRect; + pub static CGRectInfinite: CGRect; + + pub fn CGDisplayModeRelease(mode: ::sys::CGDisplayModeRef); + + pub fn CGMainDisplayID() -> CGDirectDisplayID; + pub fn CGDisplayIsActive(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsAlwaysInMirrorSet(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsAsleep(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsBuiltin(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsInHWMirrorSet(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsInMirrorSet(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsMain(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsOnline(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsStereo(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayMirrorsDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID; + pub fn CGDisplayPrimaryDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID; + pub fn CGDisplayRotation(display: CGDirectDisplayID) -> libc::c_double; + pub fn CGDisplayScreenSize(display: CGDirectDisplayID) -> CGSize; + pub fn CGDisplaySerialNumber(display: CGDirectDisplayID) -> libc::uint32_t; + pub fn CGDisplayUnitNumber(display: CGDirectDisplayID) -> libc::uint32_t; + pub fn CGDisplayUsesOpenGLAcceleration(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayVendorNumber(display: CGDirectDisplayID) -> libc::uint32_t; + pub fn CGGetActiveDisplayList( + max_displays: libc::uint32_t, + active_displays: *mut CGDirectDisplayID, + display_count: *mut libc::uint32_t, + ) -> CGError; + pub fn CGDisplayModelNumber(display: CGDirectDisplayID) -> libc::uint32_t; + pub fn CGDisplayPixelsHigh(display: CGDirectDisplayID) -> libc::size_t; + pub fn CGDisplayPixelsWide(display: CGDirectDisplayID) -> libc::size_t; + pub fn CGDisplayBounds(display: CGDirectDisplayID) -> CGRect; + pub fn CGDisplayCreateImage(display: CGDirectDisplayID) -> ::sys::CGImageRef; + + pub fn CGDisplayCopyDisplayMode(display: CGDirectDisplayID) -> ::sys::CGDisplayModeRef; + pub fn CGDisplayModeGetHeight(mode: ::sys::CGDisplayModeRef) -> libc::size_t; + pub fn CGDisplayModeGetWidth(mode: ::sys::CGDisplayModeRef) -> libc::size_t; + pub fn CGDisplayModeGetPixelHeight(mode: ::sys::CGDisplayModeRef) -> libc::size_t; + pub fn CGDisplayModeGetPixelWidth(mode: ::sys::CGDisplayModeRef) -> libc::size_t; + pub fn CGDisplayModeGetRefreshRate(mode: ::sys::CGDisplayModeRef) -> libc::c_double; + + // mouse stuff + pub fn CGDisplayHideCursor(display: CGDirectDisplayID) -> CGError; + pub fn CGDisplayShowCursor(display: CGDirectDisplayID) -> CGError; + pub fn CGDisplayMoveCursorToPoint(display: CGDirectDisplayID, point: CGPoint) -> CGError; + pub fn CGWarpMouseCursorPosition(point: CGPoint) -> CGError; + pub fn CGAssociateMouseAndMouseCursorPosition(connected: boolean_t) -> CGError; + + // Window Services Reference + pub fn CGWindowListCopyWindowInfo( + option: CGWindowListOption, + relativeToWindow: CGWindowID, + ) -> CFArrayRef; + pub fn CGWindowListCreateImage( + screenBounds: CGRect, + listOptions: CGWindowListOption, + windowId: CGWindowID, + imageOptions: CGWindowImageOption, + ) -> ::sys::CGImageRef; + pub fn CGWindowListCreateImageFromArray( + screenBounds: CGRect, + windowArray: CFArrayRef, + imageOptions: CGWindowImageOption, + ) -> ::sys::CGImageRef; +} diff --git a/core-graphics/src/event.rs b/core-graphics/src/event.rs new file mode 100644 index 0000000..b49fc12 --- /dev/null +++ b/core-graphics/src/event.rs @@ -0,0 +1,619 @@ +#![allow(non_upper_case_globals)] + +use core_foundation::base::{CFRelease, CFRetain, CFTypeID}; +use geometry::CGPoint; +use event_source::CGEventSource; + +use libc; + +use foreign_types::ForeignType; + +pub type CGEventField = libc::uint32_t; +pub type CGKeyCode = libc::uint16_t; + +/// Flags for events +/// +/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h) +bitflags! { + #[repr(C)] + pub struct CGEventFlags: u64 { + const CGEventFlagNull = 0; + + // Device-independent modifier key bits. + const CGEventFlagAlphaShift = 0x00010000; + const CGEventFlagShift = 0x00020000; + const CGEventFlagControl = 0x00040000; + const CGEventFlagAlternate = 0x00080000; + const CGEventFlagCommand = 0x00100000; + + // Special key identifiers. + const CGEventFlagHelp = 0x00400000; + const CGEventFlagSecondaryFn = 0x00800000; + + // Identifies key events from numeric keypad area on extended keyboards. + const CGEventFlagNumericPad = 0x00200000; + + // Indicates if mouse/pen movement events are not being coalesced + const CGEventFlagNonCoalesced = 0x00000100; + } +} + +/// Key codes for keys that are independent of keyboard layout. +/// +/// [Ref](https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.13.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h) +#[repr(C)] +pub struct KeyCode; +impl KeyCode { + pub const RETURN: CGKeyCode = 0x24; + pub const TAB: CGKeyCode = 0x30; + pub const SPACE: CGKeyCode = 0x31; + pub const DELETE: CGKeyCode = 0x33; + pub const ESCAPE: CGKeyCode = 0x35; + pub const COMMAND: CGKeyCode = 0x37; + pub const SHIFT: CGKeyCode = 0x38; + pub const CAPS_LOCK: CGKeyCode = 0x39; + pub const OPTION: CGKeyCode = 0x3A; + pub const CONTROL: CGKeyCode = 0x3B; + pub const RIGHT_COMMAND: CGKeyCode = 0x36; + pub const RIGHT_SHIFT: CGKeyCode = 0x3C; + pub const RIGHT_OPTION: CGKeyCode = 0x3D; + pub const RIGHT_CONTROL: CGKeyCode = 0x3E; + pub const FUNCTION: CGKeyCode = 0x3F; + pub const VOLUME_UP: CGKeyCode = 0x48; + pub const VOLUME_DOWN: CGKeyCode = 0x49; + pub const MUTE: CGKeyCode = 0x4A; + pub const F1: CGKeyCode = 0x7A; + pub const F2: CGKeyCode = 0x78; + pub const F3: CGKeyCode = 0x63; + pub const F4: CGKeyCode = 0x76; + pub const F5: CGKeyCode = 0x60; + pub const F6: CGKeyCode = 0x61; + pub const F7: CGKeyCode = 0x62; + pub const F8: CGKeyCode = 0x64; + pub const F9: CGKeyCode = 0x65; + pub const F10: CGKeyCode = 0x6D; + pub const F11: CGKeyCode = 0x67; + pub const F12: CGKeyCode = 0x6F; + pub const F13: CGKeyCode = 0x69; + pub const F14: CGKeyCode = 0x6B; + pub const F15: CGKeyCode = 0x71; + pub const F16: CGKeyCode = 0x6A; + pub const F17: CGKeyCode = 0x40; + pub const F18: CGKeyCode = 0x4F; + pub const F19: CGKeyCode = 0x50; + pub const F20: CGKeyCode = 0x5A; + pub const HELP: CGKeyCode = 0x72; + pub const HOME: CGKeyCode = 0x73; + pub const PAGE_UP: CGKeyCode = 0x74; + pub const FORWARD_DELETE: CGKeyCode = 0x75; + pub const END: CGKeyCode = 0x77; + pub const PAGE_DOWN: CGKeyCode = 0x79; + pub const LEFT_ARROW: CGKeyCode = 0x7B; + pub const RIGHT_ARROW: CGKeyCode = 0x7C; + pub const DOWN_ARROW: CGKeyCode = 0x7D; + pub const UP_ARROW: CGKeyCode = 0x7E; +} + +/// Constants that specify the different types of input events. +/// +/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h) +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGEventType { + Null = 0, + + // Mouse events. + LeftMouseDown = 1, + LeftMouseUp = 2, + RightMouseDown = 3, + RightMouseUp = 4, + MouseMoved = 5, + LeftMouseDragged = 6, + RightMouseDragged = 7, + + // Keyboard events. + KeyDown = 10, + KeyUp = 11, + FlagsChanged = 12, + + // Specialized control devices. + ScrollWheel = 22, + TabletPointer = 23, + TabletProximity = 24, + OtherMouseDown = 25, + OtherMouseUp = 26, + OtherMouseDragged = 27, + + // Out of band event types. These are delivered to the event tap callback + // to notify it of unusual conditions that disable the event tap. + TapDisabledByTimeout = 0xFFFFFFFE, + TapDisabledByUserInput = 0xFFFFFFFF, +} + +/// Constants used as keys to access specialized fields in low-level events. +/// +/// [Ref](https://developer.apple.com/documentation/coregraphics/cgeventfield) +pub struct EventField; +impl EventField { + /// Key to access an integer field that contains the mouse button event + /// number. Matching mouse-down and mouse-up events will have the same + /// event number. + pub const MOUSE_EVENT_NUMBER: CGEventField = 0; + + /// Key to access an integer field that contains the mouse button click + /// state. A click state of 1 represents a single click. A click state of + /// 2 represents a double-click. A click state of 3 represents a + /// triple-click. + pub const MOUSE_EVENT_CLICK_STATE: CGEventField = 1; + + /// Key to access a double field that contains the mouse button pressure. + /// The pressure value may range from 0 to 1, with 0 representing the + /// mouse being up. This value is commonly set by tablet pens mimicking a + /// mouse. + pub const MOUSE_EVENT_PRESSURE: CGEventField = 2; + + /// Key to access an integer field that contains the mouse button number. + pub const MOUSE_EVENT_BUTTON_NUMBER: CGEventField = 3; + + /// Key to access an integer field that contains the horizontal mouse + /// delta since the last mouse movement event. + pub const MOUSE_EVENT_DELTA_X: CGEventField = 4; + + /// Key to access an integer field that contains the vertical mouse delta + /// since the last mouse movement event. + pub const MOUSE_EVENT_DELTA_Y: CGEventField = 5; + + /// Key to access an integer field. The value is non-zero if the event + /// should be ignored by the Inkwell subsystem. + pub const MOUSE_EVENT_INSTANT_MOUSER: CGEventField = 6; + + /// Key to access an integer field that encodes the mouse event subtype as + /// a `kCFNumberIntType'. + pub const MOUSE_EVENT_SUB_TYPE: CGEventField = 7; + + /// Key to access an integer field, non-zero when this is an autorepeat of + /// a key-down, and zero otherwise. + pub const KEYBOARD_EVENT_AUTOREPEAT: CGEventField = 8; + + /// Key to access an integer field that contains the virtual keycode of the + /// key-down or key-up event. + pub const KEYBOARD_EVENT_KEYCODE: CGEventField = 9; + + /// Key to access an integer field that contains the keyboard type + /// identifier. + pub const KEYBOARD_EVENT_KEYBOARD_TYPE: CGEventField = 10; + + /// Key to access an integer field that contains scrolling data. This field + /// typically contains the change in vertical position since the last + /// scrolling event from a Mighty Mouse scroller or a single-wheel mouse + /// scroller. + pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_1: CGEventField = 11; + + /// Key to access an integer field that contains scrolling data. This field + /// typically contains the change in horizontal position since the last + /// scrolling event from a Mighty Mouse scroller. + pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_2: CGEventField = 12; + + /// Key to access a field that contains scrolling data. The scrolling data + /// represents a line-based or pixel-based change in vertical position + /// since the last scrolling event from a Mighty Mouse scroller or a + /// single-wheel mouse scroller. The scrolling data uses a fixed-point + /// 16.16 signed integer format. If this key is passed to + /// `CGEventGetDoubleValueField', the fixed-point value is converted to a + /// double value. + pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_1: CGEventField = 93; + + /// Key to access a field that contains scrolling data. The scrolling data + /// represents a line-based or pixel-based change in horizontal position + /// since the last scrolling event from a Mighty Mouse scroller. The + /// scrolling data uses a fixed-point 16.16 signed integer format. If this + /// key is passed to `CGEventGetDoubleValueField', the fixed-point value is + /// converted to a double value. + pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_2: CGEventField = 94; + + /// Key to access an integer field that contains pixel-based scrolling + /// data. The scrolling data represents the change in vertical position + /// since the last scrolling event from a Mighty Mouse scroller or a + /// single-wheel mouse scroller. + pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_1: CGEventField = 96; + + /// Key to access an integer field that contains pixel-based scrolling + /// data. The scrolling data represents the change in horizontal position + /// since the last scrolling event from a Mighty Mouse scroller. + pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_2: CGEventField = 97; + + /// Key to access an integer field that indicates whether the event should + /// be ignored by the Inkwell subsystem. If the value is non-zero, the + /// event should be ignored. + pub const SCROLL_WHEEL_EVENT_INSTANT_MOUSER: CGEventField = 14; + + /// Key to access an integer field that contains the absolute X coordinate + /// in tablet space at full tablet resolution. + pub const TABLET_EVENT_POINT_X: CGEventField = 15; + + /// Key to access an integer field that contains the absolute Y coordinate + /// in tablet space at full tablet resolution. + pub const TABLET_EVENT_POINT_Y: CGEventField = 16; + + /// Key to access an integer field that contains the absolute Z coordinate + /// in tablet space at full tablet resolution. + pub const TABLET_EVENT_POINT_Z: CGEventField = 17; + + /// Key to access an integer field that contains the tablet button state. + /// Bit 0 is the first button, and a set bit represents a closed or pressed + /// button. Up to 16 buttons are supported. + pub const TABLET_EVENT_POINT_BUTTONS: CGEventField = 18; + + /// Key to access a double field that contains the tablet pen pressure. A + /// value of 0.0 represents no pressure, and 1.0 represents maximum + /// pressure. + pub const TABLET_EVENT_POINT_PRESSURE: CGEventField = 19; + + /// Key to access a double field that contains the horizontal tablet pen + /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt. + pub const TABLET_EVENT_TILT_X: CGEventField = 20; + + /// Key to access a double field that contains the vertical tablet pen + /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt. + pub const TABLET_EVENT_TILT_Y: CGEventField = 21; + + /// Key to access a double field that contains the tablet pen rotation. + pub const TABLET_EVENT_ROTATION: CGEventField = 22; + + /// Key to access a double field that contains the tangential pressure on + /// the device. A value of 0.0 represents no pressure, and 1.0 represents + /// maximum pressure. + pub const TABLET_EVENT_TANGENTIAL_PRESSURE: CGEventField = 23; + + /// Key to access an integer field that contains the system-assigned unique + /// device ID. + pub const TABLET_EVENT_DEVICE_ID: CGEventField = 24; + + /// Key to access an integer field that contains a vendor-specified value. + pub const TABLET_EVENT_VENDOR_1: CGEventField = 25; + + /// Key to access an integer field that contains a vendor-specified value. + pub const TABLET_EVENT_VENDOR_2: CGEventField = 26; + + /// Key to access an integer field that contains a vendor-specified value. + pub const TABLET_EVENT_VENDOR_3: CGEventField = 27; + + /// Key to access an integer field that contains the vendor-defined ID, + /// typically the USB vendor ID. + pub const TABLET_PROXIMITY_EVENT_VENDOR_ID: CGEventField = 28; + + /// Key to access an integer field that contains the vendor-defined tablet + /// ID, typically the USB product ID. + pub const TABLET_PROXIMITY_EVENT_TABLET_ID: CGEventField = 29; + + /// Key to access an integer field that contains the vendor-defined ID of + /// the pointing device. + pub const TABLET_PROXIMITY_EVENT_POINTER_ID: CGEventField = 30; + + /// Key to access an integer field that contains the system-assigned + /// device ID. + pub const TABLET_PROXIMITY_EVENT_DEVICE_ID: CGEventField = 31; + + /// Key to access an integer field that contains the system-assigned + /// unique tablet ID. + pub const TABLET_PROXIMITY_EVENT_SYSTEM_TABLET_ID: CGEventField = 32; + + /// Key to access an integer field that contains the vendor-assigned + /// pointer type. + pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_TYPE: CGEventField = 33; + + /// Key to access an integer field that contains the vendor-defined + /// pointer serial number. + pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_SERIAL_NUMBER: CGEventField = 34; + + /// Key to access an integer field that contains the vendor-defined unique + /// ID. + pub const TABLET_PROXIMITY_EVENT_VENDOR_UNIQUE_ID: CGEventField = 35; + + /// Key to access an integer field that contains the device capabilities + /// mask. + pub const TABLET_PROXIMITY_EVENT_CAPABILITY_MASK: CGEventField = 36; + + /// Key to access an integer field that contains the pointer type. + pub const TABLET_PROXIMITY_EVENT_POINTER_TYPE: CGEventField = 37; + + /// Key to access an integer field that indicates whether the pen is in + /// proximity to the tablet. The value is non-zero if the pen is in + /// proximity to the tablet and zero when leaving the tablet. + pub const TABLET_PROXIMITY_EVENT_ENTER_PROXIMITY: CGEventField = 38; + + /// Key to access a field that contains the event target process serial + /// number. The value is a 64-bit value. + pub const EVENT_TARGET_PROCESS_SERIAL_NUMBER: CGEventField = 39; + + /// Key to access a field that contains the event target Unix process ID. + pub const EVENT_TARGET_UNIX_PROCESS_ID: CGEventField = 40; + + /// Key to access a field that contains the event source Unix process ID. + pub const EVENT_SOURCE_UNIX_PROCESS_ID: CGEventField = 41; + + /// Key to access a field that contains the event source user-supplied + /// data, up to 64 bits. + pub const EVENT_SOURCE_USER_DATA: CGEventField = 42; + + /// Key to access a field that contains the event source Unix effective UID. + pub const EVENT_SOURCE_USER_ID: CGEventField = 43; + + /// Key to access a field that contains the event source Unix effective + /// GID. + pub const EVENT_SOURCE_GROUP_ID: CGEventField = 44; + + /// Key to access a field that contains the event source state ID used to + /// create this event. + pub const EVENT_SOURCE_STATE_ID: CGEventField = 45; + + /// Key to access an integer field that indicates whether a scrolling event + /// contains continuous, pixel-based scrolling data. The value is non-zero + /// when the scrolling data is pixel-based and zero when the scrolling data + /// is line-based. + pub const SCROLL_WHEEL_EVENT_IS_CONTINUOUS: CGEventField = 88; + + /// Added in 10.5; made public in 10.7. + pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER: CGEventField = 91; + pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER_THAT_CAN_HANDLE_THIS_EVENT: CGEventField = 92; +} + +// Constants that specify buttons on a one, two, or three-button mouse. +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGMouseButton { + Left, + Right, + Center, +} + +/// Possible tapping points for events. +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGEventTapLocation { + HID, + Session, + AnnotatedSession, +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGEvent; + fn drop = |p| CFRelease(p as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGEvent; + pub struct CGEventRef; +} + +impl CGEvent { + pub fn type_id() -> CFTypeID { + unsafe { + CGEventGetTypeID() + } + } + + pub fn new(source: CGEventSource) -> Result { + unsafe { + let event_ref = CGEventCreate(source.as_ptr()); + if !event_ref.is_null() { + Ok(Self::from_ptr(event_ref)) + } else { + Err(()) + } + } + } + + pub fn new_keyboard_event( + source: CGEventSource, + keycode: CGKeyCode, + keydown: bool + ) -> Result { + unsafe { + let event_ref = CGEventCreateKeyboardEvent(source.as_ptr(), keycode, keydown); + if !event_ref.is_null() { + Ok(Self::from_ptr(event_ref)) + } else { + Err(()) + } + } + } + + pub fn new_mouse_event( + source: CGEventSource, + mouse_type: CGEventType, + mouse_cursor_position: CGPoint, + mouse_button: CGMouseButton + ) -> Result { + unsafe { + let event_ref = CGEventCreateMouseEvent(source.as_ptr(), mouse_type, + mouse_cursor_position, mouse_button); + if !event_ref.is_null() { + Ok(Self::from_ptr(event_ref)) + } else { + Err(()) + } + } + } + + pub fn post(&self, tap_location: CGEventTapLocation) { + unsafe { + CGEventPost(tap_location, self.as_ptr()); + } + } + + pub fn location(&self) -> CGPoint { + unsafe { + CGEventGetLocation(self.as_ptr()) + } + } + + #[cfg(feature = "elcapitan")] + pub fn post_to_pid(&self, pid: libc::pid_t) { + unsafe { + CGEventPostToPid(pid, self.as_ptr()); + } + } + + pub fn set_flags(&self, flags: CGEventFlags) { + unsafe { + CGEventSetFlags(self.as_ptr(), flags); + } + } + + pub fn get_flags(&self) -> CGEventFlags { + unsafe { + CGEventGetFlags(self.as_ptr()) + } + } + + pub fn set_type(&self, event_type: CGEventType) { + unsafe { + CGEventSetType(self.as_ptr(), event_type); + } + } + + pub fn get_type(&self) -> CGEventType { + unsafe { + CGEventGetType(self.as_ptr()) + } + } + + pub fn set_string_from_utf16_unchecked(&self, buf: &[u16]) { + let buflen = buf.len() as libc::c_ulong; + unsafe { + CGEventKeyboardSetUnicodeString(self.as_ptr(), buflen, buf.as_ptr()); + } + } + + pub fn set_string(&self, string: &str) { + let buf: Vec = string.encode_utf16().collect(); + self.set_string_from_utf16_unchecked(&buf); + } + + pub fn get_integer_value_field(&self, field: CGEventField) -> i64 { + unsafe { CGEventGetIntegerValueField(self.as_ptr(), field) } + } + + pub fn set_integer_value_field(&self, field: CGEventField, value: i64) { + unsafe { CGEventSetIntegerValueField(self.as_ptr(), field, value) } + } + + pub fn get_double_value_field(&self, field: CGEventField) -> f64 { + unsafe { CGEventGetDoubleValueField(self.as_ptr(), field) } + } + + pub fn set_double_value_field(&self, field: CGEventField, value: f64) { + unsafe { CGEventSetDoubleValueField(self.as_ptr(), field, value) } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + /// Return the type identifier for the opaque type `CGEventRef'. + fn CGEventGetTypeID() -> CFTypeID; + + /// Return a new event using the event source `source'. If `source' is NULL, + /// the default source is used. + fn CGEventCreate(source: ::sys::CGEventSourceRef) -> ::sys::CGEventRef; + + /// Return a new keyboard event. + /// + /// The event source may be taken from another event, or may be NULL. Based + /// on the virtual key code values entered, the appropriate key down, key up, + /// or flags changed events are generated. + /// + /// All keystrokes needed to generate a character must be entered, including + /// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z', + /// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT + /// and 'z' key must be released: + fn CGEventCreateKeyboardEvent(source: ::sys::CGEventSourceRef, keycode: CGKeyCode, + keydown: bool) -> ::sys::CGEventRef; + + /// Return a new mouse event. + /// + /// The event source may be taken from another event, or may be NULL. + /// `mouseType' should be one of the mouse event types. `mouseCursorPosition' + /// should be the position of the mouse cursor in global coordinates. + /// `mouseButton' should be the button that's changing state; `mouseButton' + /// is ignored unless `mouseType' is one of `kCGEventOtherMouseDown', + /// `kCGEventOtherMouseDragged', or `kCGEventOtherMouseUp'. + /// + /// The current implementation of the event system supports a maximum of + /// thirty-two buttons. Mouse button 0 is the primary button on the mouse. + /// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is + /// the center button, and the remaining buttons are in USB device order. + fn CGEventCreateMouseEvent(source: ::sys::CGEventSourceRef, mouseType: CGEventType, + mouseCursorPosition: CGPoint, mouseButton: CGMouseButton) -> ::sys::CGEventRef; + + /// Post an event into the event stream at a specified location. + /// + /// This function posts the specified event immediately before any event taps + /// instantiated for that location, and the event passes through any such + /// taps. + fn CGEventPost(tapLocation: CGEventTapLocation, event: ::sys::CGEventRef); + + #[cfg(feature = "elcapitan")] + /// Post an event to a specified process ID + fn CGEventPostToPid(pid: libc::pid_t, event: ::sys::CGEventRef); + + /// Set the event flags of an event. + fn CGEventSetFlags(event: ::sys::CGEventRef, flags: CGEventFlags); + + /// Return the event flags of an event. + fn CGEventGetFlags(event: ::sys::CGEventRef) -> CGEventFlags; + + /// Return the location of an event in global display coordinates. + /// CGPointZero is returned if event is not a valid ::sys::CGEventRef. + fn CGEventGetLocation(event: ::sys::CGEventRef) -> CGPoint; + + /// Set the event type of an event. + fn CGEventSetType(event: ::sys::CGEventRef, eventType: CGEventType); + + /// Return the event type of an event (left mouse down, for example). + fn CGEventGetType(event: ::sys::CGEventRef) -> CGEventType; + + /// Set the Unicode string associated with a keyboard event. + /// + /// By default, the system translates the virtual key code in a keyboard + /// event into a Unicode string based on the keyboard ID in the event + /// source. This function allows you to manually override this string. + /// Note that application frameworks may ignore the Unicode string in a + /// keyboard event and do their own translation based on the virtual + /// keycode and perceived event state. + fn CGEventKeyboardSetUnicodeString(event: ::sys::CGEventRef, + length: libc::c_ulong, + string: *const u16); + + /// Return the integer value of a field in an event. + fn CGEventGetIntegerValueField(event: ::sys::CGEventRef, field: CGEventField) -> i64; + + /// Set the integer value of a field in an event. + /// + /// Before calling this function, the event type must be set using a typed + /// event creation function such as `CGEventCreateMouseEvent', or by + /// calling `CGEventSetType'. + /// + /// If you are creating a mouse event generated by a tablet, call this + /// function and specify the field `kCGMouseEventSubtype' with a value of + /// `kCGEventMouseSubtypeTabletPoint' or + /// `kCGEventMouseSubtypeTabletProximity' before setting other parameters. + fn CGEventSetIntegerValueField(event: ::sys::CGEventRef, field: CGEventField, value: i64); + + /// Return the floating-point value of a field in an event. + /// + /// In cases where the field value is represented within the event by a fixed + /// point number or an integer, the result is scaled to the appropriate range + /// as part of creating the floating-point representation. + fn CGEventGetDoubleValueField(event: ::sys::CGEventRef, field: CGEventField) -> f64; + + /// Set the floating-point value of a field in an event. + /// + /// Before calling this function, the event type must be set using a typed + /// event creation function such as `CGEventCreateMouseEvent', or by calling + /// `CGEventSetType'. + /// + /// In cases where the field’s value is represented within the event by a + /// fixed point number or integer, the value parameter is scaled as needed + /// and converted to the appropriate type. + fn CGEventSetDoubleValueField(event: ::sys::CGEventRef, field: CGEventField, value: f64); +} diff --git a/core-graphics/src/event_source.rs b/core-graphics/src/event_source.rs new file mode 100644 index 0000000..ce13f5a --- /dev/null +++ b/core-graphics/src/event_source.rs @@ -0,0 +1,48 @@ +use core_foundation::base::{CFRelease, CFRetain, CFTypeID}; +use foreign_types::ForeignType; + +/// Possible source states of an event source. +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGEventSourceStateID { + Private = -1, + CombinedSessionState = 0, + HIDSystemState = 1, +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGEventSource; + fn drop = |p| CFRelease(p as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGEventSource; + pub struct CGEventSourceRef; +} + +impl CGEventSource { + pub fn type_id() -> CFTypeID { + unsafe { + CGEventSourceGetTypeID() + } + } + + pub fn new(state_id: CGEventSourceStateID) -> Result { + unsafe { + let event_source_ref = CGEventSourceCreate(state_id); + if !event_source_ref.is_null() { + Ok(Self::from_ptr(event_source_ref)) + } else { + Err(()) + } + } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + /// Return the type identifier for the opaque type `CGEventSourceRef'. + fn CGEventSourceGetTypeID() -> CFTypeID; + + /// Return a Quartz event source created with a specified source state. + fn CGEventSourceCreate(stateID: CGEventSourceStateID) -> ::sys::CGEventSourceRef; +} diff --git a/core-graphics/src/font.rs b/core-graphics/src/font.rs new file mode 100644 index 0000000..96e9f33 --- /dev/null +++ b/core-graphics/src/font.rs @@ -0,0 +1,156 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ptr; +use core_foundation::base::{CFRelease, CFRetain, CFTypeID, TCFType}; +use core_foundation::array::{CFArray, CFArrayRef}; +use core_foundation::data::{CFData, CFDataRef}; +use core_foundation::string::{CFString, CFStringRef}; +use core_foundation::dictionary::{CFDictionary, CFDictionaryRef}; +use data_provider::CGDataProvider; +use geometry::CGRect; + +use foreign_types::ForeignType; + +use libc::{self, c_int, size_t}; + +pub type CGGlyph = libc::c_ushort; + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGFont; + fn drop = |p| CFRelease(p as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGFont; + pub struct CGFontRef; +} + +unsafe impl Send for CGFont {} +unsafe impl Sync for CGFont {} + +impl CGFont { + pub fn type_id() -> CFTypeID { + unsafe { + CGFontGetTypeID() + } + } + + pub fn from_data_provider(provider: CGDataProvider) -> Result { + unsafe { + let font_ref = CGFontCreateWithDataProvider(provider.as_ptr()); + if !font_ref.is_null() { + Ok(CGFont::from_ptr(font_ref)) + } else { + Err(()) + } + } + } + + pub fn from_name(name: &CFString) -> Result { + unsafe { + let font_ref = CGFontCreateWithFontName(name.as_concrete_TypeRef()); + if !font_ref.is_null() { + Ok(CGFont::from_ptr(font_ref)) + } else { + Err(()) + } + } + } + + pub fn create_copy_from_variations(&self, vars: &CFDictionary) -> Result { + unsafe { + let font_ref = CGFontCreateCopyWithVariations(self.as_ptr(), + vars.as_concrete_TypeRef()); + if !font_ref.is_null() { + Ok(CGFont::from_ptr(font_ref)) + } else { + Err(()) + } + } + } + + pub fn postscript_name(&self) -> CFString { + unsafe { + let string_ref = CGFontCopyPostScriptName(self.as_ptr()); + TCFType::wrap_under_create_rule(string_ref) + } + } + + pub fn get_glyph_b_boxes(&self, glyphs: &[CGGlyph], bboxes: &mut [CGRect]) -> bool { + unsafe { + assert!(bboxes.len() >= glyphs.len()); + CGFontGetGlyphBBoxes(self.as_ptr(), + glyphs.as_ptr(), + glyphs.len(), + bboxes.as_mut_ptr()) + } + } + + pub fn get_glyph_advances(&self, glyphs: &[CGGlyph], advances: &mut [c_int]) -> bool { + unsafe { + assert!(advances.len() >= glyphs.len()); + CGFontGetGlyphAdvances(self.as_ptr(), + glyphs.as_ptr(), + glyphs.len(), + advances.as_mut_ptr()) + } + } + + pub fn get_units_per_em(&self) -> c_int { + unsafe { + CGFontGetUnitsPerEm(self.as_ptr()) + } + } + + pub fn copy_table_tags(&self) -> CFArray { + unsafe { + TCFType::wrap_under_create_rule(CGFontCopyTableTags(self.as_ptr())) + } + } + + pub fn copy_table_for_tag(&self, tag: u32) -> Option { + let data_ref = unsafe { CGFontCopyTableForTag(self.as_ptr(), tag) }; + if data_ref != ptr::null() { + Some(unsafe { TCFType::wrap_under_create_rule(data_ref) }) + } else { + None + } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + // TODO: basically nothing has bindings (even commented-out) besides what we use. + fn CGFontCreateWithDataProvider(provider: ::sys::CGDataProviderRef) -> ::sys::CGFontRef; + fn CGFontCreateWithFontName(name: CFStringRef) -> ::sys::CGFontRef; + fn CGFontCreateCopyWithVariations(font: ::sys::CGFontRef, vars: CFDictionaryRef) -> ::sys::CGFontRef; + fn CGFontGetTypeID() -> CFTypeID; + + fn CGFontCopyPostScriptName(font: ::sys::CGFontRef) -> CFStringRef; + + // These do the same thing as CFRetain/CFRelease, except + // gracefully handle a NULL argument. We don't use them. + //fn CGFontRetain(font: ::sys::CGFontRef); + //fn CGFontRelease(font: ::sys::CGFontRef); + + fn CGFontGetGlyphBBoxes(font: ::sys::CGFontRef, + glyphs: *const CGGlyph, + count: size_t, + bboxes: *mut CGRect) + -> bool; + fn CGFontGetGlyphAdvances(font: ::sys::CGFontRef, + glyphs: *const CGGlyph, + count: size_t, + advances: *mut c_int) + -> bool; + fn CGFontGetUnitsPerEm(font: ::sys::CGFontRef) -> c_int; + + fn CGFontCopyTableTags(font: ::sys::CGFontRef) -> CFArrayRef; + fn CGFontCopyTableForTag(font: ::sys::CGFontRef, tag: u32) -> CFDataRef; +} diff --git a/core-graphics/src/geometry.rs b/core-graphics/src/geometry.rs new file mode 100644 index 0000000..906c605 --- /dev/null +++ b/core-graphics/src/geometry.rs @@ -0,0 +1,195 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base::CGFloat; +use core_foundation::base::TCFType; +use core_foundation::dictionary::CFDictionary; + +pub const CG_ZERO_POINT: CGPoint = CGPoint { + x: 0.0, + y: 0.0, +}; + +pub const CG_ZERO_SIZE: CGSize = CGSize { + width: 0.0, + height: 0.0, +}; + +pub const CG_ZERO_RECT: CGRect = CGRect { + origin: CG_ZERO_POINT, + size: CG_ZERO_SIZE, +}; + +pub const CG_AFFINE_TRANSFORM_IDENTITY: CGAffineTransform = CGAffineTransform { + a: 1.0, b: 0.0, + c: 0.0, d: 1.0, + tx: 0.0, ty: 0.0, +}; + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct CGSize { + pub width: CGFloat, + pub height: CGFloat, +} + +impl CGSize { + #[inline] + pub fn new(width: CGFloat, height: CGFloat) -> CGSize { + CGSize { + width: width, + height: height, + } + } + + #[inline] + pub fn apply_transform(&self, t: &CGAffineTransform) -> CGSize { + unsafe { + ffi::CGSizeApplyAffineTransform(*self, *t) + } + } +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct CGPoint { + pub x: CGFloat, + pub y: CGFloat, +} + +impl CGPoint { + #[inline] + pub fn new(x: CGFloat, y: CGFloat) -> CGPoint { + CGPoint { + x: x, + y: y, + } + } + + #[inline] + pub fn apply_transform(&self, t: &CGAffineTransform) -> CGPoint { + unsafe { + ffi::CGPointApplyAffineTransform(*self, *t) + } + } +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct CGRect { + pub origin: CGPoint, + pub size: CGSize +} + +impl CGRect { + #[inline] + pub fn new(origin: &CGPoint, size: &CGSize) -> CGRect { + CGRect { + origin: *origin, + size: *size, + } + } + + #[inline] + pub fn inset(&self, size: &CGSize) -> CGRect { + unsafe { + ffi::CGRectInset(*self, size.width, size.height) + } + } + + #[inline] + pub fn from_dict_representation(dict: &CFDictionary) -> Option { + let mut rect = CGRect::new(&CGPoint::new(0., 0.), &CGSize::new(0., 0.)); + let result = unsafe { + ffi::CGRectMakeWithDictionaryRepresentation(dict.as_concrete_TypeRef(), &mut rect) + }; + if result == 0 { + None + } else { + Some(rect) + } + } + + #[inline] + pub fn is_empty(&self) -> bool { + unsafe { + // I use one, as it seems that `YES` is not available from this crate. + ffi::CGRectIsEmpty(*self) == 1 + } + } + + #[inline] + pub fn is_intersects(&self, other: &CGRect) -> bool { + unsafe { + // I use one, as it seems that `YES` is not available from this crate. + ffi::CGRectIntersectsRect(*self, *other) == 1 + } + } + + #[inline] + pub fn apply_transform(&self, t: &CGAffineTransform) -> CGRect { + unsafe { + ffi::CGRectApplyAffineTransform(*self, *t) + } + } +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct CGAffineTransform { + pub a: CGFloat, + pub b: CGFloat, + pub c: CGFloat, + pub d: CGFloat, + pub tx: CGFloat, + pub ty: CGFloat, +} + +impl CGAffineTransform { + #[inline] + pub fn new( + a: CGFloat, + b: CGFloat, + c: CGFloat, + d: CGFloat, + tx: CGFloat, + ty: CGFloat, + ) -> CGAffineTransform { + CGAffineTransform { a, b, c, d, tx, ty } + } + + #[inline] + pub fn invert(&self) -> CGAffineTransform { + unsafe { + ffi::CGAffineTransformInvert(*self) + } + } +} + +mod ffi { + use base::{CGFloat, boolean_t}; + use geometry::{CGAffineTransform, CGPoint, CGRect, CGSize}; + use core_foundation::dictionary::CFDictionaryRef; + + #[link(name = "CoreGraphics", kind = "framework")] + extern { + pub fn CGRectInset(rect: CGRect, dx: CGFloat, dy: CGFloat) -> CGRect; + pub fn CGRectMakeWithDictionaryRepresentation(dict: CFDictionaryRef, + rect: *mut CGRect) -> boolean_t; + pub fn CGRectIsEmpty(rect: CGRect) -> boolean_t; + pub fn CGRectIntersectsRect(rect1: CGRect, rect2: CGRect) -> boolean_t; + + pub fn CGAffineTransformInvert(t: CGAffineTransform) -> CGAffineTransform; + + pub fn CGPointApplyAffineTransform(point: CGPoint, t: CGAffineTransform) -> CGPoint; + pub fn CGRectApplyAffineTransform(rect: CGRect, t: CGAffineTransform) -> CGRect; + pub fn CGSizeApplyAffineTransform(size: CGSize, t: CGAffineTransform) -> CGSize; + } +} + diff --git a/core-graphics/src/image.rs b/core-graphics/src/image.rs new file mode 100644 index 0000000..93eb807 --- /dev/null +++ b/core-graphics/src/image.rs @@ -0,0 +1,109 @@ +use core_foundation::base::{CFRetain, CFTypeID}; +use core_foundation::data::CFData; +use color_space::CGColorSpace; +use data_provider::CGDataProviderRef; +use libc::size_t; +use foreign_types::{ForeignType, ForeignTypeRef}; + +#[repr(C)] +pub enum CGImageAlphaInfo { + CGImageAlphaNone, /* For example, RGB. */ + CGImageAlphaPremultipliedLast, /* For example, premultiplied RGBA */ + CGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */ + CGImageAlphaLast, /* For example, non-premultiplied RGBA */ + CGImageAlphaFirst, /* For example, non-premultiplied ARGB */ + CGImageAlphaNoneSkipLast, /* For example, RBGX. */ + CGImageAlphaNoneSkipFirst, /* For example, XRBG. */ + CGImageAlphaOnly /* No color data, alpha data only */ +} + +#[repr(C)] +pub enum CGImageByteOrderInfo { + CGImageByteOrderMask = 0x7000, + CGImageByteOrder16Little = (1 << 12), + CGImageByteOrder32Little = (2 << 12), + CGImageByteOrder16Big = (3 << 12), + CGImageByteOrder32Big = (4 << 12) +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGImage; + fn drop = CGImageRelease; + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGImage; + pub struct CGImageRef; +} + +impl CGImage { + pub fn type_id() -> CFTypeID { + unsafe { + CGImageGetTypeID() + } + } +} + +impl CGImageRef { + pub fn width(&self) -> size_t { + unsafe { + CGImageGetWidth(self.as_ptr()) + } + } + + pub fn height(&self) -> size_t { + unsafe { + CGImageGetHeight(self.as_ptr()) + } + } + + pub fn bits_per_component(&self) -> size_t { + unsafe { + CGImageGetBitsPerComponent(self.as_ptr()) + } + } + + pub fn bits_per_pixel(&self) -> size_t { + unsafe { + CGImageGetBitsPerPixel(self.as_ptr()) + } + } + + pub fn bytes_per_row(&self) -> size_t { + unsafe { + CGImageGetBytesPerRow(self.as_ptr()) + } + } + + pub fn color_space(&self) -> CGColorSpace { + unsafe { + let cs = CGImageGetColorSpace(self.as_ptr()); + CFRetain(cs as *mut _); + CGColorSpace::from_ptr(cs) + } + } + + /// Returns the raw image bytes wrapped in `CFData`. Note, the returned `CFData` owns the + /// underlying buffer. + pub fn data(&self) -> CFData { + let data_provider = unsafe { + CGDataProviderRef::from_ptr(CGImageGetDataProvider(self.as_ptr())) + }; + data_provider.copy_data() + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + fn CGImageGetTypeID() -> CFTypeID; + fn CGImageGetWidth(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetHeight(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetBitsPerComponent(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetBitsPerPixel(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetBytesPerRow(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetColorSpace(image: ::sys::CGImageRef) -> ::sys::CGColorSpaceRef; + fn CGImageGetDataProvider(image: ::sys::CGImageRef) -> ::sys::CGDataProviderRef; + fn CGImageRelease(image: ::sys::CGImageRef); + + //fn CGImageGetAlphaInfo(image: ::sys::CGImageRef) -> CGImageAlphaInfo; + //fn CGImageCreateCopyWithColorSpace(image: ::sys::CGImageRef, space: ::sys::CGColorSpaceRef) -> ::sys::CGImageRef +} diff --git a/core-graphics/src/lib.rs b/core-graphics/src/lib.rs new file mode 100644 index 0000000..01854e1 --- /dev/null +++ b/core-graphics/src/lib.rs @@ -0,0 +1,36 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate libc; +extern crate core_foundation; + +#[macro_use] +#[cfg(target_os = "macos")] +extern crate bitflags; + +#[macro_use] +extern crate foreign_types; + +pub mod base; +pub mod color_space; +pub mod context; +pub mod data_provider; +#[cfg(target_os = "macos")] +pub mod display; +#[cfg(target_os = "macos")] +pub mod event; +#[cfg(target_os = "macos")] +pub mod event_source; +pub mod font; +pub mod geometry; +#[cfg(target_os = "macos")] +pub mod private; +pub mod image; +pub mod path; +mod sys; diff --git a/core-graphics/src/path.rs b/core-graphics/src/path.rs new file mode 100644 index 0000000..4e60c59 --- /dev/null +++ b/core-graphics/src/path.rs @@ -0,0 +1,115 @@ +// Copyright 2017 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core_foundation::base::{CFRelease, CFRetain, CFTypeID}; +use foreign_types::ForeignType; +use geometry::CGPoint; +use libc::c_void; +use std::fmt::{self, Debug, Formatter}; +use std::marker::PhantomData; +use std::ops::Deref; +use std::slice; + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGPath; + fn drop = |p| CFRelease(p as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGPath; + pub struct CGPathRef; +} + +impl CGPath { + pub fn type_id() -> CFTypeID { + unsafe { + CGPathGetTypeID() + } + } + + pub fn apply<'a, F>(&'a self, mut closure: &'a F) where F: FnMut(CGPathElementRef<'a>) { + unsafe { + CGPathApply(self.as_ptr(), &mut closure as *mut _ as *mut c_void, do_apply::); + } + + unsafe extern "C" fn do_apply<'a, F>(info: *mut c_void, element: *const CGPathElement) + where F: FnMut(CGPathElementRef<'a>) { + let closure = info as *mut *mut F; + (**closure)(CGPathElementRef::new(element)) + } + } +} + +#[repr(i32)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum CGPathElementType { + MoveToPoint = 0, + AddLineToPoint = 1, + AddQuadCurveToPoint = 2, + AddCurveToPoint = 3, + CloseSubpath = 4, +} + +pub struct CGPathElementRef<'a> { + element: *const CGPathElement, + phantom: PhantomData<&'a CGPathElement>, +} + +impl<'a> CGPathElementRef<'a> { + fn new<'b>(element: *const CGPathElement) -> CGPathElementRef<'b> { + CGPathElementRef { + element: element, + phantom: PhantomData, + } + } +} + +impl<'a> Deref for CGPathElementRef<'a> { + type Target = CGPathElement; + fn deref(&self) -> &CGPathElement { + unsafe { + &*self.element + } + } +} + +#[repr(C)] +pub struct CGPathElement { + pub element_type: CGPathElementType, + points: *mut CGPoint, +} + +impl Debug for CGPathElement { + fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> { + write!(formatter, "{:?}: {:?}", self.element_type, self.points()) + } +} + +impl CGPathElement { + pub fn points(&self) -> &[CGPoint] { + unsafe { + match self.element_type { + CGPathElementType::CloseSubpath => &[], + CGPathElementType::MoveToPoint | CGPathElementType::AddLineToPoint => { + slice::from_raw_parts(self.points, 1) + } + CGPathElementType::AddQuadCurveToPoint => slice::from_raw_parts(self.points, 2), + CGPathElementType::AddCurveToPoint => slice::from_raw_parts(self.points, 3), + } + } + } +} + +type CGPathApplierFunction = unsafe extern "C" fn(info: *mut c_void, + element: *const CGPathElement); + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + fn CGPathApply(path: ::sys::CGPathRef, info: *mut c_void, function: CGPathApplierFunction); + fn CGPathGetTypeID() -> CFTypeID; +} diff --git a/core-graphics/src/private.rs b/core-graphics/src/private.rs new file mode 100644 index 0000000..0bc193b --- /dev/null +++ b/core-graphics/src/private.rs @@ -0,0 +1,116 @@ +// Copyright 2016 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Evil private APIs. +//! +//! These are liable to change at any time. Use with caution! + +use geometry::CGRect; +use libc::{c_int, c_uint}; +use std::ptr; + +pub struct CGSRegion { + region: ffi::CGSRegionRef, +} + +impl Drop for CGSRegion { + fn drop(&mut self) { + unsafe { + ffi::CGSRegionRelease(self.region) + } + } +} + +impl CGSRegion { + #[inline] + pub fn from_rect(rect: &CGRect) -> CGSRegion { + unsafe { + let mut region = ptr::null_mut(); + assert!(ffi::CGSNewRegionWithRect(rect, &mut region) == 0); + CGSRegion { + region: region, + } + } + } + + #[inline] + pub fn from_rects(rects: &[CGRect]) -> CGSRegion { + unsafe { + let mut region = ptr::null_mut(); + assert!(ffi::CGSNewRegionWithRectList(rects.as_ptr(), + rects.len() as c_uint, + &mut region) == 0); + CGSRegion { + region: region, + } + } + } +} + +/// This should always be memory-safe; the window server rejects any invalid surface IDs. +pub struct CGSSurface { + context_id: c_uint, + window_number: c_int, + surface_id: c_uint, +} + +impl CGSSurface { + #[inline] + pub fn from_ids(context_id: c_uint, window_number: c_int, surface_id: c_uint) -> CGSSurface { + CGSSurface { + context_id: context_id, + window_number: window_number, + surface_id: surface_id, + } + } + + #[inline] + pub fn id(&self) -> c_uint { + self.surface_id + } + + #[inline] + pub fn set_shape(&self, region: &CGSRegion) { + unsafe { + assert!(ffi::CGSSetSurfaceShape(self.context_id, + self.window_number, + self.surface_id, + region.region) == 0) + } + } +} + +mod ffi { + use geometry::CGRect; + use libc::{c_int, c_uint}; + + // This is an enum so that we can't easily make instances of this opaque type. + pub enum CGSRegionObject {} + + pub type CGError = OSStatus; + pub type CGSRegionRef = *mut CGSRegionObject; + pub type OSStatus = i32; + + #[link(name = "CoreGraphics", kind = "framework")] + extern { + pub fn CGSRegionRelease(region: CGSRegionRef); + pub fn CGSNewRegionWithRect(rect: *const CGRect, outRegion: *mut CGSRegionRef) -> CGError; + pub fn CGSNewRegionWithRectList(rects: *const CGRect, + rectCount: c_uint, + outRegion: *mut CGSRegionRef) + -> CGError; + + pub fn CGSSetSurfaceShape(contextID: c_uint, + windowNumber: c_int, + surfaceID: c_uint, + region: CGSRegionRef) + -> CGError; + } +} + diff --git a/core-graphics/src/sys.rs b/core-graphics/src/sys.rs new file mode 100644 index 0000000..1048e04 --- /dev/null +++ b/core-graphics/src/sys.rs @@ -0,0 +1,32 @@ +pub enum CGImage {} +pub type CGImageRef = *mut CGImage; + +pub enum CGColorSpace {} +pub type CGColorSpaceRef = *mut CGColorSpace; + +pub enum CGPath {} +pub type CGPathRef = *mut CGPath; + +pub enum CGDataProvider {} +pub type CGDataProviderRef = *mut CGDataProvider; + +pub enum CGFont {} +pub type CGFontRef = *mut CGFont; + +pub enum CGContext {} +pub type CGContextRef = *mut CGContext; + +#[cfg(target_os = "macos")] +mod macos { + pub enum CGEvent {} + pub type CGEventRef = *mut CGEvent; + + pub enum CGEventSource {} + pub type CGEventSourceRef = *mut CGEventSource; + + pub enum CGDisplayMode {} + pub type CGDisplayModeRef = *mut CGDisplayMode; +} + +#[cfg(target_os = "macos")] +pub use self::macos::*;