use std::mem;
use bitflags::bitflags;
use core_foundation::{
base::{CFRange, CFTypeID, TCFType},
declare_TCFType,
dictionary::CFDictionaryRef,
impl_CFTypeDescription, impl_TCFType,
};
use core_graphics::{context::CGContextRef, path::CGPathRef};
use core_text::{frame::CTFrameRef, framesetter::CTFramesetterRef, line::CTLineRef};
use libc::{c_void, size_t};
use crate::text::TextAlignment;
#[link(name = "CoreText", kind = "framework")]
extern "C" {
pub fn CTLineDraw(line: CTLineRef, context: CGContextRef);
}
#[link(name = "CoreText", kind = "framework")]
extern "C" {
pub fn CTFrameDraw(frame: CTFrameRef, context: CGContextRef);
}
#[link(name = "CoreText", kind = "framework")]
extern "C" {
pub fn CTFramesetterCreateFrame(framesetter: CTFramesetterRef, string_range: CFRange, path: CGPathRef, attributes: CFDictionaryRef)
-> CTFrameRef;
}
#[repr(C)]
pub struct __CTParagraphStyle(c_void);
pub type CTParagraphStyleRef = *const __CTParagraphStyle;
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CTTextAlignment {
#[doc(alias = "kCTTextAlignmentLeft")]
Left = 0,
#[doc(alias = "kCTTextAlignmentRight")]
Right = 1,
#[doc(alias = "kCTTextAlignmentCenter")]
Center = 2,
#[doc(alias = "kCTTextAlignmentJustified")]
Justified = 3,
#[doc(alias = "kCTTextAlignmentNatural")]
Natural = 4,
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CTLineBreakMode {
#[doc(alias = "kCTLineBreakByWordWrapping")]
WordWrapping = 0,
#[doc(alias = "kCTLineBreakByCharWrapping")]
CharWrapping = 1,
#[doc(alias = "kCTLineBreakByClipping")]
Clipping = 2,
#[doc(alias = "kCTLineBreakByTruncatingHead")]
TruncatingHead = 3,
#[doc(alias = "kCTLineBreakByTruncatingTail")]
TruncatingTail = 4,
#[doc(alias = "kCTLineBreakByTruncatingMiddle")]
TruncatingMiddle = 5,
}
#[repr(i8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CTWritingDirection {
#[doc(alias = "kCTWritingDirectionNatural")]
Natural = -1,
#[doc(alias = "kCTWritingDirectionLeftToRight")]
LeftToRight = 0,
#[doc(alias = "kCTWritingDirectionRightToLeft")]
RightToLeft = 1,
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CTParagraphStyleSpecifier {
#[doc(alias = "kCTParagraphStyleSpecifierAlignment")]
Alignment = 0,
#[doc(alias = "kCTParagraphStyleSpecifierFirstLineHeadIndent")]
FirstLineHeadIndent = 1,
#[doc(alias = "kCTParagraphStyleSpecifierHeadIndent")]
HeadIndent = 2,
#[doc(alias = "kCTParagraphStyleSpecifierTailIndent")]
TailIndent = 3,
#[doc(alias = "kCTParagraphStyleSpecifierTabStops")]
TabStops = 4,
#[doc(alias = "kCTParagraphStyleSpecifierDefaultTabInterval")]
DefaultTabInterval = 5,
#[doc(alias = "kCTParagraphStyleSpecifierLineBreakMode")]
LineBreakMode = 6,
#[doc(alias = "kCTParagraphStyleSpecifierLineHeightMultiple")]
LineHeightMultiple = 7,
#[doc(alias = "kCTParagraphStyleSpecifierMaximumLineHeight")]
MaximumLineHeight = 8,
#[doc(alias = "kCTParagraphStyleSpecifierMinimumLineHeight")]
MinimumLineHeight = 9,
#[doc(alias = "kCTParagraphStyleSpecifierLineSpacing")]
LineSpacing = 10,
#[doc(alias = "kCTParagraphStyleSpecifierParagraphSpacing")]
ParagraphSpacing = 11,
#[doc(alias = "kCTParagraphStyleSpecifierParagraphSpacingBefore")]
ParagraphSpacingBefore = 12,
#[doc(alias = "kCTParagraphStyleSpecifierBaseWritingDirection")]
BaseWritingDirection = 13,
#[doc(alias = "kCTParagraphStyleSpecifierMaximumLineSpacing")]
MaximumLineSpacing = 14,
#[doc(alias = "kCTParagraphStyleSpecifierMinimumLineSpacing")]
MinimumLineSpacing = 15,
#[doc(alias = "kCTParagraphStyleSpecifierLineSpacingAdjustment")]
LineSpacingAdjustment = 16,
#[doc(alias = "kCTParagraphStyleSpecifierLineBoundsOptions")]
LineBoundsOptions = 17,
Count,
}
#[repr(C)]
pub struct CTParagraphStyleSetting {
spec: CTParagraphStyleSpecifier,
value_size: usize,
value: *const c_void,
}
#[link(name = "CoreText", kind = "framework")]
extern "C" {
pub fn CTParagraphStyleCreate(settings: *const CTParagraphStyleSetting, settingCount: size_t) -> CTParagraphStyleRef;
pub fn CTParagraphStyleCreateCopy(paragraphStyle: CTParagraphStyleRef) -> CTParagraphStyleRef;
pub fn CTParagraphStyleGetTypeID() -> CFTypeID;
}
impl CTParagraphStyleSetting {
pub fn from_alignment(alignment: CTTextAlignment) -> Self {
let alignment = match alignment {
CTTextAlignment::Left => &CTTextAlignment::Left,
CTTextAlignment::Right => &CTTextAlignment::Right,
CTTextAlignment::Center => &CTTextAlignment::Center,
CTTextAlignment::Justified => &CTTextAlignment::Justified,
CTTextAlignment::Natural => &CTTextAlignment::Natural,
} as *const _ as *const c_void;
Self {
spec: CTParagraphStyleSpecifier::Alignment,
value_size: mem::size_of::<CTTextAlignment>(),
value: alignment,
}
}
}
declare_TCFType!(CTParagraphStyle, CTParagraphStyleRef);
impl_TCFType!(CTParagraphStyle, CTParagraphStyleRef, CTParagraphStyleGetTypeID);
impl_CFTypeDescription!(CTParagraphStyle);
impl CTParagraphStyle {
pub fn new(settings: &[CTParagraphStyleSetting]) -> Self {
unsafe {
let paragraph_style = CTParagraphStyleCreate(settings.as_ptr(), settings.len() as size_t);
CTParagraphStyle::wrap_under_create_rule(paragraph_style)
}
}
pub fn copy(&self) -> Self {
unsafe {
let paragraph_style = CTParagraphStyleCreateCopy(self.as_concrete_TypeRef());
CTParagraphStyle::wrap_under_create_rule(paragraph_style)
}
}
}
bitflags! {
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct CTUnderlineStyle: i32 {
#[doc(alias = "kCTUnderlineStyleNone")]
const None = 0x00;
#[doc(alias = "kCTUnderlineStyleSingle")]
const Single = 0x01;
#[doc(alias = "kCTUnderlineStyleThick")]
const Thick = 0x02;
#[doc(alias = "kCTUnderlineStyleDouble")]
const Double = 0x09;
}
}
impl From<TextAlignment> for CTTextAlignment {
fn from(alignment: TextAlignment) -> Self {
match alignment {
TextAlignment::Left => CTTextAlignment::Left,
TextAlignment::Right => CTTextAlignment::Right,
TextAlignment::Center => CTTextAlignment::Center,
}
}
}