Something went wrong. Try again.
we (web engine): Experimental web browser project to understand the limits of Claude
Something went wrong. Try again.
Rust
at url-parser
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370//! CoreGraphics FFI bindings for bitmap rendering.//!//! Provides wrappers around `CGColorSpace`, `CGContext` (bitmap contexts),//! and `CGImage` for software rendering into a Rust-owned pixel buffer.//!//! # Safety//!//! This module contains `unsafe` code for FFI with CoreGraphics.//! The `platform` crate is one of the few crates where `unsafe` is permitted.
use std::os::raw::c_void;use std::ptr::NonNull;
// ---------------------------------------------------------------------------// CoreGraphics framework link// ---------------------------------------------------------------------------
#[link(name = "CoreGraphics", kind = "framework")]extern "C" { fn CGColorSpaceCreateDeviceRGB() -> *mut c_void; fn CGColorSpaceRelease(space: *mut c_void);
fn CGBitmapContextCreate( data: *mut c_void, width: usize, height: usize, bits_per_component: usize, bytes_per_row: usize, colorspace: *mut c_void, bitmap_info: u32, ) -> *mut c_void;
fn CGBitmapContextCreateImage(context: *mut c_void) -> *mut c_void;
fn CGContextRelease(context: *mut c_void); fn CGImageRelease(image: *mut c_void);
fn CGContextDrawImage(context: *mut c_void, rect: CGRect, image: *mut c_void); fn CGContextSetRGBFillColor(context: *mut c_void, red: f64, green: f64, blue: f64, alpha: f64); fn CGContextFillRect(context: *mut c_void, rect: CGRect);}
// ---------------------------------------------------------------------------// Geometry (re-export compatible with appkit types)// ---------------------------------------------------------------------------
/// `CGRect` — a rectangle defined by origin and size.////// This is layout-compatible with `NSRect` / the appkit `NSRect` type.#[repr(C)]#[derive(Debug, Clone, Copy)]pub struct CGRect { pub origin: CGPoint, pub size: CGSize,}
/// `CGPoint` — a point in 2D space.#[repr(C)]#[derive(Debug, Clone, Copy)]pub struct CGPoint { pub x: f64, pub y: f64,}
/// `CGSize` — a 2D size.#[repr(C)]#[derive(Debug, Clone, Copy)]pub struct CGSize { pub width: f64, pub height: f64,}
impl CGRect { /// Create a new rectangle. pub fn new(x: f64, y: f64, width: f64, height: f64) -> CGRect { CGRect { origin: CGPoint { x, y }, size: CGSize { width, height }, } }}
// ---------------------------------------------------------------------------// CGBitmapInfo constants// ---------------------------------------------------------------------------
/// Alpha info mask (lower 5 bits of CGBitmapInfo).pub const K_CG_IMAGE_ALPHA_PREMULTIPLIED_FIRST: u32 = 2;
/// Byte order mask: 32-bit host byte order.pub const K_CG_BITMAP_BYTE_ORDER_32_HOST: u32 = 0;
/// Standard BGRA premultiplied alpha format used by macOS windowing.////// Pixel layout in memory on little-endian (ARM64): B, G, R, A/// This matches what CoreGraphics and AppKit expect for display.pub const BITMAP_INFO_PREMULTIPLIED_FIRST: u32 = K_CG_IMAGE_ALPHA_PREMULTIPLIED_FIRST | K_CG_BITMAP_BYTE_ORDER_32_HOST;
// ---------------------------------------------------------------------------// ColorSpace// ---------------------------------------------------------------------------
/// An owned CoreGraphics device RGB color space.pub struct ColorSpace(NonNull<c_void>);
impl ColorSpace { /// Create a device RGB color space. pub fn device_rgb() -> Option<ColorSpace> { let ptr = unsafe { CGColorSpaceCreateDeviceRGB() }; NonNull::new(ptr).map(ColorSpace) }
/// Return the raw pointer. #[inline] pub fn as_ptr(&self) -> *mut c_void { self.0.as_ptr() }}
impl Drop for ColorSpace { fn drop(&mut self) { unsafe { CGColorSpaceRelease(self.as_ptr()) } }}
// ---------------------------------------------------------------------------// BitmapContext — a CGBitmapContext backed by a Rust-owned pixel buffer// ---------------------------------------------------------------------------
/// A CoreGraphics bitmap context backed by a Rust-owned pixel buffer.////// The pixel buffer is BGRA, 8 bits per component, premultiplied alpha./// The buffer is owned by this struct and the `CGBitmapContext` renders into it.pub struct BitmapContext { context: NonNull<c_void>, buffer: Vec<u8>, width: usize, height: usize,}
impl BitmapContext { /// Create a new bitmap context with the given dimensions. /// /// Allocates a Rust-owned pixel buffer and wraps it in a CGBitmapContext. /// Pixel format: 4 bytes per pixel (BGRA, premultiplied alpha). pub fn new(width: usize, height: usize) -> Option<BitmapContext> { if width == 0 || height == 0 { return None; }
let bytes_per_row = width * 4; let mut buffer = vec![0u8; bytes_per_row * height]; let color_space = ColorSpace::device_rgb()?;
let ctx = unsafe { CGBitmapContextCreate( buffer.as_mut_ptr() as *mut c_void, width, height, 8, // bits per component bytes_per_row, color_space.as_ptr(), BITMAP_INFO_PREMULTIPLIED_FIRST, ) };
let context = NonNull::new(ctx)?; Some(BitmapContext { context, buffer, width, height, }) }
/// Get the width in pixels. #[inline] pub fn width(&self) -> usize { self.width }
/// Get the height in pixels. #[inline] pub fn height(&self) -> usize { self.height }
/// Get the bytes per row (stride). #[inline] pub fn bytes_per_row(&self) -> usize { self.width * 4 }
/// Get a shared reference to the raw pixel buffer. /// /// Pixel format: BGRA, 8 bits per component, premultiplied alpha. /// Layout: row-major, bottom-to-top (CG default coordinate system). #[inline] pub fn pixels(&self) -> &[u8] { &self.buffer }
/// Get a mutable reference to the raw pixel buffer. /// /// After modifying pixels directly, changes are immediately visible to /// CoreGraphics since the bitmap context wraps this buffer. #[inline] pub fn pixels_mut(&mut self) -> &mut [u8] { &mut self.buffer }
/// Create a `CGImage` from the current bitmap context contents. /// /// Returns `None` if the image cannot be created. pub fn create_image(&self) -> Option<Image> { let img = unsafe { CGBitmapContextCreateImage(self.context.as_ptr()) }; NonNull::new(img).map(Image) }
/// Fill a rectangle with an RGBA color using CoreGraphics. /// /// Color components are in 0.0..=1.0 range. pub fn fill_rect(&self, rect: CGRect, r: f64, g: f64, b: f64, a: f64) { unsafe { CGContextSetRGBFillColor(self.context.as_ptr(), r, g, b, a); CGContextFillRect(self.context.as_ptr(), rect); } }
/// Clear the entire buffer to a given RGBA color. /// /// Color components are in 0.0..=1.0 range. This uses CoreGraphics /// `CGContextFillRect` to fill the entire bitmap. pub fn clear(&self, r: f64, g: f64, b: f64, a: f64) { let rect = CGRect::new(0.0, 0.0, self.width as f64, self.height as f64); self.fill_rect(rect, r, g, b, a); }
/// Return the raw CGContextRef pointer. /// /// Useful for passing to other CG drawing functions. #[inline] pub fn as_ptr(&self) -> *mut c_void { self.context.as_ptr() }}
impl Drop for BitmapContext { fn drop(&mut self) { unsafe { CGContextRelease(self.context.as_ptr()) } }}
// ---------------------------------------------------------------------------// Image — an owned CGImage// ---------------------------------------------------------------------------
/// An owned CoreGraphics image (CGImageRef).////// Created from a [`BitmapContext`] via [`BitmapContext::create_image`].pub struct Image(NonNull<c_void>);
impl Image { /// Return the raw CGImageRef pointer. #[inline] pub fn as_ptr(&self) -> *mut c_void { self.0.as_ptr() }}
impl Drop for Image { fn drop(&mut self) { unsafe { CGImageRelease(self.as_ptr()) } }}
// ---------------------------------------------------------------------------// Drawing a CGImage into a CGContext// ---------------------------------------------------------------------------
/// Draw a `CGImage` into a CoreGraphics context at the given rectangle.////// This is used in `drawRect:` to blit the bitmap into the view's context.////// # Safety////// `target_context` must be a valid CGContextRef (e.g., from/// `NSGraphicsContext.currentContext.CGContext`).pub unsafe fn draw_image_in_context(target_context: *mut c_void, rect: CGRect, image: &Image) { CGContextDrawImage(target_context, rect, image.as_ptr());}
// ---------------------------------------------------------------------------// Tests// ---------------------------------------------------------------------------
#[cfg(test)]mod tests { use super::*;
#[test] fn cgrect_new() { let rect = CGRect::new(10.0, 20.0, 300.0, 400.0); assert_eq!(rect.origin.x, 10.0); assert_eq!(rect.origin.y, 20.0); assert_eq!(rect.size.width, 300.0); assert_eq!(rect.size.height, 400.0); }
#[test] fn bitmap_info_constant() { assert_eq!(BITMAP_INFO_PREMULTIPLIED_FIRST, 2); }
#[test] fn create_color_space() { let cs = ColorSpace::device_rgb().expect("should create device RGB color space"); assert!(!cs.as_ptr().is_null()); }
#[test] fn create_bitmap_context() { let ctx = BitmapContext::new(100, 100).expect("should create bitmap context"); assert_eq!(ctx.width(), 100); assert_eq!(ctx.height(), 100); assert_eq!(ctx.bytes_per_row(), 400); assert_eq!(ctx.pixels().len(), 100 * 400); }
#[test] fn bitmap_context_zero_size_returns_none() { assert!(BitmapContext::new(0, 100).is_none()); assert!(BitmapContext::new(100, 0).is_none()); assert!(BitmapContext::new(0, 0).is_none()); }
#[test] fn bitmap_context_pixels_mut() { let mut ctx = BitmapContext::new(10, 10).expect("should create"); let pixels = ctx.pixels_mut(); // Write a red pixel at (0, 0): BGRA format pixels[0] = 0; // B pixels[1] = 0; // G pixels[2] = 255; // R pixels[3] = 255; // A assert_eq!(ctx.pixels()[0], 0); assert_eq!(ctx.pixels()[2], 255); }
#[test] fn bitmap_context_clear_and_create_image() { let ctx = BitmapContext::new(50, 50).expect("should create"); ctx.clear(0.0, 0.0, 1.0, 1.0); // blue let img = ctx.create_image().expect("should create image"); assert!(!img.as_ptr().is_null()); }
#[test] fn bitmap_context_fill_rect() { let ctx = BitmapContext::new(100, 100).expect("should create"); let rect = CGRect::new(10.0, 10.0, 50.0, 50.0); ctx.fill_rect(rect, 1.0, 0.0, 0.0, 1.0); // red rectangle let img = ctx .create_image() .expect("should create image from filled context"); assert!(!img.as_ptr().is_null()); }}