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};
18use std::os::raw::c_void;
19
20#[repr(C)]
21pub struct __CTFrame(c_void);
22
23pub type CTFrameRef = *const __CTFrame;
24
25declare_TCFType! {
26    CTFrame, CTFrameRef
27}
28impl_TCFType!(CTFrame, CTFrameRef, CTFrameGetTypeID);
29impl_CFTypeDescription!(CTFrame);
30
31impl CTFrame {
32    /// The `CGPath` used to create this `CTFrame`.
33    pub fn get_path(&self) -> CGPath {
34        unsafe { CGPath::from_ptr(CTFrameGetPath(self.as_concrete_TypeRef())).clone() }
35    }
36
37    /// Returns an owned copy of the underlying lines.
38    ///
39    /// Each line is retained, and will remain valid past the life of this `CTFrame`.
40    pub fn get_lines(&self) -> Vec<CTLine> {
41        unsafe {
42            let array_ref = CTFrameGetLines(self.as_concrete_TypeRef());
43            let array: CFArray<CTLine> = CFArray::wrap_under_get_rule(array_ref);
44            array
45                .iter()
46                .map(|l| CTLine::wrap_under_get_rule(l.as_concrete_TypeRef()))
47                .collect()
48        }
49    }
50
51    /// Return the origin of each line in a given range.
52    ///
53    /// If no range is provided, returns the origin of each line in the frame.
54    ///
55    /// If the length of the range is 0, returns the origin of all lines from
56    /// the range's start to the end.
57    ///
58    /// The origin is the position relative to the path used to create this `CTFFrame`;
59    /// to get the path use [`get_path`].
60    ///
61    /// [`get_path`]: #method.get_path
62    pub fn get_line_origins(&self, range: impl Into<Option<CFRange>>) -> Vec<CGPoint> {
63        let range = range.into().unwrap_or_else(|| CFRange::init(0, 0));
64        let len = match range.length {
65            // range length of 0 means 'all remaining lines'
66            0 => unsafe {
67                let array_ref = CTFrameGetLines(self.as_concrete_TypeRef());
68                let array: CFArray<CTLine> = CFArray::wrap_under_get_rule(array_ref);
69                array.len() - range.location
70            },
71            n => n,
72        };
73        let len = len.max(0) as usize;
74        let mut out = vec![CGPoint::new(0., 0.); len];
75        unsafe {
76            CTFrameGetLineOrigins(self.as_concrete_TypeRef(), range, out.as_mut_ptr());
77        }
78        out
79    }
80
81    pub fn draw(&self, context: &CGContextRef) {
82        unsafe {
83            CTFrameDraw(self.as_concrete_TypeRef(), context.as_ptr());
84        }
85    }
86}
87
88#[cfg_attr(feature = "link", link(name = "CoreText", kind = "framework"))]
89extern "C" {
90    fn CTFrameGetTypeID() -> CFTypeID;
91    fn CTFrameGetLines(frame: CTFrameRef) -> CFArrayRef;
92    fn CTFrameDraw(frame: CTFrameRef, context: *mut <CGContext as ForeignType>::CType);
93    fn CTFrameGetLineOrigins(frame: CTFrameRef, range: CFRange, origins: *mut CGPoint);
94    fn CTFrameGetPath(frame: CTFrameRef) -> SysCGPathRef;
95}