1use crate::run::CTRun;
11use core_foundation::array::{CFArray, CFArrayRef};
12use core_foundation::attributed_string::CFAttributedStringRef;
13use core_foundation::base::{CFIndex, CFRange, CFTypeID, TCFType};
14use core_foundation::{declare_TCFType, impl_CFTypeDescription, impl_TCFType};
15use core_graphics::base::CGFloat;
16use core_graphics::context::CGContext;
17use core_graphics::geometry::{CGPoint, CGRect};
18use foreign_types::ForeignType;
19
20#[repr(C)]
21pub struct __CTLine(core::ffi::c_void);
22
23pub type CTLineRef = *const __CTLine;
24
25declare_TCFType! {
26 CTLine, CTLineRef
27}
28impl_TCFType!(CTLine, CTLineRef, CTLineGetTypeID);
29impl_CFTypeDescription!(CTLine);
30
31pub struct TypographicBounds {
33 pub width: CGFloat,
34 pub ascent: CGFloat,
35 pub descent: CGFloat,
36 pub leading: CGFloat,
37}
38
39impl CTLine {
40 pub fn new_with_attributed_string(string: CFAttributedStringRef) -> Self {
41 unsafe {
42 let ptr = CTLineCreateWithAttributedString(string);
43 CTLine::wrap_under_create_rule(ptr)
44 }
45 }
46
47 pub fn glyph_runs(&self) -> CFArray<CTRun> {
48 unsafe { TCFType::wrap_under_get_rule(CTLineGetGlyphRuns(self.0)) }
49 }
50
51 pub fn get_string_range(&self) -> CFRange {
52 unsafe { CTLineGetStringRange(self.as_concrete_TypeRef()) }
53 }
54
55 pub fn draw(&self, context: &CGContext) {
56 unsafe { CTLineDraw(self.as_concrete_TypeRef(), context.as_ptr()) }
57 }
58
59 pub fn get_image_bounds(&self, context: &CGContext) -> CGRect {
60 unsafe { CTLineGetImageBounds(self.as_concrete_TypeRef(), context.as_ptr()) }
61 }
62
63 pub fn get_typographic_bounds(&self) -> TypographicBounds {
64 let mut ascent = 0.0;
65 let mut descent = 0.0;
66 let mut leading = 0.0;
67 unsafe {
68 let width = CTLineGetTypographicBounds(
69 self.as_concrete_TypeRef(),
70 &mut ascent,
71 &mut descent,
72 &mut leading,
73 );
74 TypographicBounds {
75 width,
76 ascent,
77 descent,
78 leading,
79 }
80 }
81 }
82
83 pub fn get_string_index_for_position(&self, position: CGPoint) -> CFIndex {
84 unsafe { CTLineGetStringIndexForPosition(self.as_concrete_TypeRef(), position) }
85 }
86
87 pub fn get_string_offset_for_string_index(&self, charIndex: CFIndex) -> CGFloat {
88 unsafe {
89 CTLineGetOffsetForStringIndex(self.as_concrete_TypeRef(), charIndex, std::ptr::null())
90 }
91 }
92}
93
94#[cfg_attr(feature = "link", link(name = "CoreText", kind = "framework"))]
95extern "C" {
96 fn CTLineGetTypeID() -> CFTypeID;
97 fn CTLineGetGlyphRuns(line: CTLineRef) -> CFArrayRef;
98 fn CTLineGetStringRange(line: CTLineRef) -> CFRange;
99
100 fn CTLineCreateWithAttributedString(string: CFAttributedStringRef) -> CTLineRef;
102
103 fn CTLineDraw(line: CTLineRef, context: *const core_graphics::sys::CGContext);
105
106 fn CTLineGetImageBounds(
108 line: CTLineRef,
109 context: *const core_graphics::sys::CGContext,
110 ) -> CGRect;
111 fn CTLineGetTypographicBounds(
112 line: CTLineRef,
113 ascent: *mut CGFloat,
114 descent: *mut CGFloat,
115 leading: *mut CGFloat,
116 ) -> CGFloat;
117
118 fn CTLineGetStringIndexForPosition(line: CTLineRef, position: CGPoint) -> CFIndex;
120 fn CTLineGetOffsetForStringIndex(
121 line: CTLineRef,
122 charIndex: CFIndex,
123 secondaryOffset: *const CGFloat,
124 ) -> CGFloat;
125}