core_text/
frame.rs

1// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10use crate::line::CTLine;
11use core_foundation::array::{CFArray, CFArrayRef};
12use core_foundation::base::{CFRange, CFTypeID, TCFType};
13use core_foundation::{declare_TCFType, impl_CFTypeDescription, impl_TCFType};
14use core_graphics::context::{CGContext, CGContextRef};
15use core_graphics::geometry::CGPoint;
16use core_graphics::path::{CGPath, SysCGPathRef};
17use foreign_types::{ForeignType, ForeignTypeRef};
18
19#[repr(C)]
20pub struct __CTFrame(core::ffi::c_void);
21
22pub type CTFrameRef = *const __CTFrame;
23
24declare_TCFType! {
25    CTFrame, CTFrameRef
26}
27impl_TCFType!(CTFrame, CTFrameRef, CTFrameGetTypeID);
28impl_CFTypeDescription!(CTFrame);
29
30impl CTFrame {
31    /// The `CGPath` used to create this `CTFrame`.
32    pub fn get_path(&self) -> CGPath {
33        unsafe { CGPath::from_ptr(CTFrameGetPath(self.as_concrete_TypeRef())).clone() }
34    }
35
36    /// Returns an owned copy of the underlying lines.
37    ///
38    /// Each line is retained, and will remain valid past the life of this `CTFrame`.
39    pub fn get_lines(&self) -> Vec<CTLine> {
40        unsafe {
41            let array_ref = CTFrameGetLines(self.as_concrete_TypeRef());
42            let array: CFArray<CTLine> = CFArray::wrap_under_get_rule(array_ref);
43            array
44                .iter()
45                .map(|l| CTLine::wrap_under_get_rule(l.as_concrete_TypeRef()))
46                .collect()
47        }
48    }
49
50    /// Return the origin of each line in a given range.
51    ///
52    /// If no range is provided, returns the origin of each line in the frame.
53    ///
54    /// If the length of the range is 0, returns the origin of all lines from
55    /// the range's start to the end.
56    ///
57    /// The origin is the position relative to the path used to create this `CTFFrame`;
58    /// to get the path use [`get_path`].
59    ///
60    /// [`get_path`]: #method.get_path
61    pub fn get_line_origins(&self, range: impl Into<Option<CFRange>>) -> Vec<CGPoint> {
62        let range = range.into().unwrap_or_else(|| CFRange::init(0, 0));
63        let len = match range.length {
64            // range length of 0 means 'all remaining lines'
65            0 => unsafe {
66                let array_ref = CTFrameGetLines(self.as_concrete_TypeRef());
67                let array: CFArray<CTLine> = CFArray::wrap_under_get_rule(array_ref);
68                array.len() - range.location
69            },
70            n => n,
71        };
72        let len = len.max(0) as usize;
73        let mut out = vec![CGPoint::new(0., 0.); len];
74        unsafe {
75            CTFrameGetLineOrigins(self.as_concrete_TypeRef(), range, out.as_mut_ptr());
76        }
77        out
78    }
79
80    pub fn draw(&self, context: &CGContextRef) {
81        unsafe {
82            CTFrameDraw(self.as_concrete_TypeRef(), context.as_ptr());
83        }
84    }
85}
86
87#[cfg_attr(feature = "link", link(name = "CoreText", kind = "framework"))]
88extern "C" {
89    fn CTFrameGetTypeID() -> CFTypeID;
90    fn CTFrameGetLines(frame: CTFrameRef) -> CFArrayRef;
91    fn CTFrameDraw(frame: CTFrameRef, context: *mut <CGContext as ForeignType>::CType);
92    fn CTFrameGetLineOrigins(frame: CTFrameRef, range: CFRange, origins: *mut CGPoint);
93    fn CTFrameGetPath(frame: CTFrameRef) -> SysCGPathRef;
94}