use std::ptr::{null, null_mut};
use core_foundation::{
array::{CFArray, CFArrayRef},
base::{CFTypeID, TCFType},
};
use libc::{c_void, size_t};
use crate::{
base::CGFloat,
color::CGColor,
color_space::{CGColorSpace, CGColorSpaceRef},
};
#[repr(C)]
pub struct __CGGradient(c_void);
pub type CGGradientRef = *const __CGGradient;
bitflags! {
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct CGGradientDrawingOptions: u32 {
#[doc(alias = "kCGGradientDrawsBeforeStartLocation")]
const BeforeStartLocation = (1 << 0);
#[doc(alias = "kCGGradientDrawsAfterEndLocation")]
const AfterEndLocation = (1 << 1);
}
}
extern "C" {
pub fn CGGradientGetTypeID() -> CFTypeID;
pub fn CGGradientCreateWithColorComponents(
space: CGColorSpaceRef,
components: *const CGFloat,
locations: *const CGFloat,
count: size_t,
) -> CGGradientRef;
pub fn CGGradientCreateWithColors(space: CGColorSpaceRef, colors: CFArrayRef, locations: *const CGFloat) -> CGGradientRef;
pub fn CGGradientRetain(gradient: CGGradientRef) -> CGGradientRef;
pub fn CGGradientRelease(gradient: CGGradientRef);
}
pub struct CGGradient(CGGradientRef);
impl Drop for CGGradient {
fn drop(&mut self) {
unsafe { CGGradientRelease(self.0) }
}
}
impl_TCFType!(CGGradient, CGGradientRef, CGGradientGetTypeID);
impl_CFTypeDescription!(CGGradient);
impl CGGradient {
pub fn from_color_components(
color_space: Option<&CGColorSpace>,
components: Option<&[CGFloat]>,
locations: Option<&[CGFloat]>,
) -> Option<CGGradient> {
unsafe {
let gradient = CGGradientCreateWithColorComponents(
color_space.map_or(null_mut(), |cs| cs.as_concrete_TypeRef()),
components.map_or(null(), |c| c.as_ptr()),
locations.map_or(null(), |l| l.as_ptr()),
locations.map_or(0, |l| l.len() as size_t),
);
if gradient.is_null() {
None
} else {
Some(TCFType::wrap_under_create_rule(gradient))
}
}
}
pub fn from_colors(color_space: Option<&CGColorSpace>, colors: Option<&CFArray<CGColor>>, locations: Option<&[CGFloat]>) -> Option<CGGradient> {
unsafe {
let gradient = CGGradientCreateWithColors(
color_space.map_or(null_mut(), |cs| cs.as_concrete_TypeRef()),
colors.map_or(null(), |c| c.as_concrete_TypeRef()),
locations.map_or(null(), |l| l.as_ptr()),
);
if gradient.is_null() {
None
} else {
Some(TCFType::wrap_under_create_rule(gradient))
}
}
}
}