550 lines
20 KiB
Rust
550 lines
20 KiB
Rust
//! Bindings for [`AFont`], [`AFontMatcher`], and [`ASystemFontIterator`]
|
|
//!
|
|
//! [`AFont`]: https://developer.android.com/ndk/reference/group/font
|
|
//! [`AFontMatcher`]: https://developer.android.com/ndk/reference/group/font#afontmatcher_create
|
|
//! [`ASystemFontIterator`]: https://developer.android.com/ndk/reference/group/font#asystemfontiterator_open
|
|
|
|
#![cfg(feature = "api-level-29")]
|
|
|
|
use std::convert::TryFrom;
|
|
use std::ffi::{CStr, OsStr};
|
|
use std::fmt::{self, Write};
|
|
use std::os::unix::prelude::OsStrExt;
|
|
use std::path::Path;
|
|
use std::ptr::NonNull;
|
|
|
|
/// An integer holding a valid font weight value between 1 and 1000.
|
|
///
|
|
/// See the following definitions for more details:
|
|
/// * [`AFONT_WEIGHT_*`]
|
|
/// * [`Font::weight`]
|
|
///
|
|
/// [`AFONT_WEIGHT_*`]: https://developer.android.com/ndk/reference/group/font#anonymous-enum-33
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct FontWeight(u16);
|
|
|
|
impl FontWeight {
|
|
pub const fn new(value: u16) -> Result<Self, FontWeightValueError> {
|
|
if Self::MIN.0 <= value && value <= Self::MAX.0 {
|
|
Ok(Self(value))
|
|
} else {
|
|
Err(FontWeightValueError(()))
|
|
}
|
|
}
|
|
|
|
pub const fn to_u16(self) -> u16 {
|
|
self.0
|
|
}
|
|
|
|
/// The minimum value for the font weight value. Unlike [`ffi::AFONT_WEIGHT_MIN`] being `0`,
|
|
/// [`FontWeight::MIN`] is `1` to make the `MIN..MAX` range be inclusive, keeping consistency
|
|
/// between [`FontWeight`] and other types like `std::num::NonZeroU*`.
|
|
pub const MIN: FontWeight = FontWeight(ffi::AFONT_WEIGHT_MIN as u16 + 1);
|
|
|
|
/// A font weight value for the thin weight.
|
|
pub const THIN: FontWeight = FontWeight(ffi::AFONT_WEIGHT_THIN as u16);
|
|
|
|
/// A font weight value for the extra-light weight.
|
|
pub const EXTRA_LIGHT: FontWeight = FontWeight(ffi::AFONT_WEIGHT_EXTRA_LIGHT as u16);
|
|
|
|
/// A font weight value for the light weight.
|
|
pub const LIGHT: FontWeight = FontWeight(ffi::AFONT_WEIGHT_LIGHT as u16);
|
|
|
|
/// A font weight value for the normal weight.
|
|
pub const NORMAL: FontWeight = FontWeight(ffi::AFONT_WEIGHT_NORMAL as u16);
|
|
|
|
/// A font weight value for the medium weight.
|
|
pub const MEDIUM: FontWeight = FontWeight(ffi::AFONT_WEIGHT_MEDIUM as u16);
|
|
|
|
/// A font weight value for the semi-bold weight.
|
|
pub const SEMI_BOLD: FontWeight = FontWeight(ffi::AFONT_WEIGHT_SEMI_BOLD as u16);
|
|
|
|
/// A font weight value for the bold weight.
|
|
pub const BOLD: FontWeight = FontWeight(ffi::AFONT_WEIGHT_BOLD as u16);
|
|
|
|
/// A font weight value for the extra-bold weight.
|
|
pub const EXTRA_BOLD: FontWeight = FontWeight(ffi::AFONT_WEIGHT_EXTRA_BOLD as u16);
|
|
|
|
/// A font weight value for the black weight.
|
|
pub const BLACK: FontWeight = FontWeight(ffi::AFONT_WEIGHT_BLACK as u16);
|
|
|
|
/// The maximum value for the font weight value.
|
|
pub const MAX: FontWeight = FontWeight(ffi::AFONT_WEIGHT_MAX as u16);
|
|
}
|
|
|
|
impl fmt::Display for FontWeight {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match *self {
|
|
FontWeight::THIN => f.write_str("Thin"),
|
|
FontWeight::EXTRA_LIGHT => f.write_str("Extra Light (Ultra Light)"),
|
|
FontWeight::LIGHT => f.write_str("Light"),
|
|
FontWeight::NORMAL => f.write_str("Normal (Regular)"),
|
|
FontWeight::MEDIUM => f.write_str("Medium"),
|
|
FontWeight::SEMI_BOLD => f.write_str("Semi Bold (Demi Bold)"),
|
|
FontWeight::BOLD => f.write_str("Bold"),
|
|
FontWeight::EXTRA_BOLD => f.write_str("Extra Bold (Ultra Bold)"),
|
|
FontWeight::BLACK => f.write_str("Black (Heavy)"),
|
|
_ => writeln!(f, "{}", self.0),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The error type returned when an invalid font weight value is passed.
|
|
#[derive(Debug)]
|
|
pub struct FontWeightValueError(());
|
|
|
|
impl fmt::Display for FontWeightValueError {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
fmt.write_str("font weight must be positive and less than or equal to 1000")
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for FontWeightValueError {}
|
|
|
|
impl TryFrom<u16> for FontWeight {
|
|
type Error = FontWeightValueError;
|
|
|
|
fn try_from(value: u16) -> Result<Self, Self::Error> {
|
|
FontWeight::new(value)
|
|
}
|
|
}
|
|
|
|
/// A 4-byte integer representing an OpenType axis tag.
|
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
|
pub struct AxisTag(u32);
|
|
|
|
impl AxisTag {
|
|
/// Checks whether the given 4-byte array can construct a valid axis tag and returns
|
|
/// [`Ok(AxisTag)`] if the array is valid.
|
|
///
|
|
/// Each byte in a tag must be in the range 0x20 to 0x7E. A space character cannot be followed
|
|
/// by a non-space character. A tag must have one to four non-space characters. See the
|
|
/// [OpenType spec] for more details.
|
|
///
|
|
/// [OpenType spec]: https://learn.microsoft.com/en-us/typography/opentype/spec/otff#data-types
|
|
pub const fn from_be_bytes_checked(value: [u8; 4]) -> Result<Self, AxisTagValueError> {
|
|
// Each byte in a tag must be in the range 0x20 to 0x7E.
|
|
macro_rules! check_byte_range {
|
|
($($e:expr)+) => {
|
|
$(
|
|
if !(value[$e] as char).is_ascii_graphic() && value[$e] != b' ' {
|
|
return Err(AxisTagValueError::InvalidCharacter);
|
|
}
|
|
)+
|
|
};
|
|
}
|
|
check_byte_range!(0 1 2 3);
|
|
|
|
if value[0] == b' ' {
|
|
return Err(
|
|
if value[1] == b' ' && value[2] == b' ' && value[3] == b' ' {
|
|
// A tag must have one to four non-space characters.
|
|
AxisTagValueError::EmptyTag
|
|
} else {
|
|
// A space character cannot be followed by a non-space character.
|
|
AxisTagValueError::InvalidSpacePadding
|
|
},
|
|
);
|
|
}
|
|
|
|
macro_rules! check_if_valid {
|
|
($e:expr ; $($f:expr)+) => {
|
|
if value[$e] == b' ' {
|
|
return if true $(&& value[$f] == b' ')+ {
|
|
Ok(Self(u32::from_be_bytes(value)))
|
|
} else {
|
|
// A space character cannot be followed by a non-space character.
|
|
Err(AxisTagValueError::InvalidSpacePadding)
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
check_if_valid!(1; 2 3);
|
|
check_if_valid!(2; 3);
|
|
|
|
// Whether or not value[3] is b' ', value is a valid axis tag.
|
|
Ok(Self(u32::from_be_bytes(value)))
|
|
}
|
|
|
|
/// Checks whether the given 4-byte array can construct a valid axis tag and returns
|
|
/// [`Ok(AxisTag)`] if the array is valid.
|
|
///
|
|
/// See [`AxisTag::from_be()`] for more details.
|
|
pub const fn from_be_checked(value: u32) -> Result<Self, AxisTagValueError> {
|
|
Self::from_be_bytes_checked(value.to_be_bytes())
|
|
}
|
|
|
|
/// Construct an axis tag from the given 4-byte array. If the resulting axis tag is invalid,
|
|
/// this function panics.
|
|
///
|
|
/// See [`AxisTag::from_be()`] for more details.
|
|
pub const fn from_be_bytes(value: [u8; 4]) -> Self {
|
|
Self::unwrap_result(Self::from_be_bytes_checked(value))
|
|
}
|
|
|
|
/// Construct an axis tag from the given 4-byte integer. If the resulting axis tag is invalid,
|
|
/// this function panics.
|
|
///
|
|
/// See [`AxisTag::from_be()`] for more details.
|
|
pub const fn from_be(value: u32) -> Self {
|
|
Self::unwrap_result(Self::from_be_checked(value))
|
|
}
|
|
|
|
/// const-version of [`Result::unwrap`]. Should be removed when [`Option::unwrap`] or
|
|
/// [`Result::unwrap`] become `const`-stable.
|
|
const fn unwrap_result(result: Result<Self, AxisTagValueError>) -> Self {
|
|
match result {
|
|
Ok(t) => t,
|
|
Err(e) => panic!("{}", e.as_str()),
|
|
}
|
|
}
|
|
|
|
pub const fn to_u32(self) -> u32 {
|
|
self.0
|
|
}
|
|
|
|
pub const fn to_be_bytes(self) -> [u8; 4] {
|
|
self.0.to_be_bytes()
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for AxisTag {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let bytes = self.to_be_bytes();
|
|
f.write_char(bytes[0] as char)?;
|
|
f.write_char(bytes[1] as char)?;
|
|
f.write_char(bytes[2] as char)?;
|
|
f.write_char(bytes[3] as char)
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for AxisTag {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "AxisTag({} {:#x})", self, self.0)
|
|
}
|
|
}
|
|
|
|
/// The error type returned when an invalid axis tag value is passed.
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub enum AxisTagValueError {
|
|
/// There is a byte not in the range 0x20 to 0x7E.
|
|
InvalidCharacter,
|
|
/// There is a space character followed by a non-space character.
|
|
InvalidSpacePadding,
|
|
/// The tag only consists of space characters.
|
|
EmptyTag,
|
|
}
|
|
|
|
impl AxisTagValueError {
|
|
pub const fn as_str(&self) -> &'static str {
|
|
match self {
|
|
Self::InvalidCharacter => "each byte in an axis tag must be in the range 0x20 to 0x7E",
|
|
Self::InvalidSpacePadding => {
|
|
"a space character cannot be followed by a non-space character"
|
|
}
|
|
Self::EmptyTag => "a tag must have one to four non-space characters",
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for AxisTagValueError {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
fmt.write_str(self.as_str())
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for AxisTagValueError {}
|
|
|
|
/// A native [`AFont *`]
|
|
///
|
|
/// [`AFont *`]: https://developer.android.com/ndk/reference/group/font
|
|
#[derive(Debug)]
|
|
pub struct Font {
|
|
ptr: NonNull<ffi::AFont>,
|
|
}
|
|
|
|
impl Font {
|
|
/// Assumes ownership of `ptr`.
|
|
///
|
|
/// # Safety
|
|
/// `ptr` must be a valid owning pointer to an Android [`ffi::AFont`].
|
|
pub unsafe fn from_ptr(ptr: NonNull<ffi::AFont>) -> Self {
|
|
Self { ptr }
|
|
}
|
|
|
|
/// Returns s the pointer to the native [`ffi::AFont`].
|
|
pub fn ptr(&self) -> NonNull<ffi::AFont> {
|
|
self.ptr
|
|
}
|
|
|
|
/// Returns a count of font variation settings associated with the current font.
|
|
///
|
|
/// The font variation settings are provided as multiple tag-value pairs.
|
|
///
|
|
/// For example, bold italic font may have following font variation settings: `'wght' 700`,
|
|
/// `'slnt' -12`. In this case, [`Font::axis_count()`] returns `2` and [`Font::axis_tag_at()`] and
|
|
/// [`Font::axis_value_at()`] return those variation names and the corresponding values.
|
|
///
|
|
/// ```no_run
|
|
/// use ndk::font::Font;
|
|
///
|
|
/// let font: Font = todo!();
|
|
/// for idx in 0..font.axis_count() {
|
|
/// log::debug!("{}: {}", font.axis_tag_at(idx), font.axis_value_at(idx));
|
|
/// }
|
|
/// // Output:
|
|
/// // wght: 700
|
|
/// // slnt: -12
|
|
/// ```
|
|
pub fn axis_count(&self) -> usize {
|
|
unsafe { ffi::AFont_getAxisCount(self.ptr.as_ptr()) }
|
|
}
|
|
|
|
/// Returns an OpenType axis tag associated with the current font.
|
|
///
|
|
/// See [`Font::axis_count()`] for more details.
|
|
pub fn axis_tag_at(&self, idx: usize) -> AxisTag {
|
|
// Android returns Axis Tag in big-endian.
|
|
// See https://cs.android.com/android/platform/superproject/+/refs/heads/master:frameworks/base/native/android/system_fonts.cpp;l=197 for details
|
|
AxisTag(unsafe { ffi::AFont_getAxisTag(self.ptr.as_ptr(), idx as u32) })
|
|
}
|
|
|
|
/// Returns an OpenType axis value associated with the current font.
|
|
///
|
|
/// See [`Font::axis_count()`] for more details.
|
|
pub fn axis_value_at(&self, idx: usize) -> f32 {
|
|
unsafe { ffi::AFont_getAxisValue(self.ptr.as_ptr(), idx as u32) }
|
|
}
|
|
|
|
/// Returns a font collection index value associated with the current font.
|
|
///
|
|
/// In case the target font file is a font collection (e.g. `.ttc` or `.otc`), this returns a
|
|
/// non-negative value as a font offset in the collection. This always returns 0 if the target
|
|
/// font file is a regular font.
|
|
pub fn collection_index(&self) -> usize {
|
|
unsafe { ffi::AFont_getCollectionIndex(self.ptr.as_ptr()) }
|
|
}
|
|
|
|
/// Returns an absolute path to the current font file.
|
|
///
|
|
/// Here is a list of font formats returned by this method:
|
|
///
|
|
/// * OpenType
|
|
/// * OpenType Font Collection
|
|
/// * TrueType
|
|
/// * TrueType Collection
|
|
///
|
|
/// The file extension could be one of `*.otf`, `*.ttf`, `*.otc` or `*.ttc`.
|
|
/// The font file specified by the returned path is guaranteed to be openable with `O_RDONLY`.
|
|
pub fn path(&self) -> &Path {
|
|
let path = unsafe { CStr::from_ptr(ffi::AFont_getFontFilePath(self.ptr.as_ptr())) };
|
|
OsStr::from_bytes(path.to_bytes()).as_ref()
|
|
}
|
|
|
|
/// Returns an IETF BCP47 compliant language tag associated with the current font.
|
|
///
|
|
/// For information about IETF BCP47, read [`Locale.forLanguageTag(java.lang.String)`].
|
|
///
|
|
/// [`Locale.forLanguageTag(java.lang.String)`]: https://developer.android.com/reference/java/util/Locale.html#forLanguageTag(java.lang.String)
|
|
pub fn locale(&self) -> Option<&CStr> {
|
|
let ptr = unsafe { ffi::AFont_getLocale(self.ptr.as_ptr()) };
|
|
if ptr.is_null() {
|
|
None
|
|
} else {
|
|
Some(unsafe { CStr::from_ptr(ptr) })
|
|
}
|
|
}
|
|
|
|
/// Returns a weight value associated with the current font.
|
|
///
|
|
/// The weight values are positive and less than or equal to 1000. Here are pairs of the common
|
|
/// names and their values.
|
|
///
|
|
/// | Value | Name | NDK Definition |
|
|
/// | ----- | ------------------------- | --------------------------- |
|
|
/// | 100 | Thin | [`FontWeight::THIN`] |
|
|
/// | 200 | Extra Light (Ultra Light) | [`FontWeight::EXTRA_LIGHT`] |
|
|
/// | 300 | Light | [`FontWeight::LIGHT`] |
|
|
/// | 400 | Normal (Regular) | [`FontWeight::NORMAL`] |
|
|
/// | 500 | Medium | [`FontWeight::MEDIUM`] |
|
|
/// | 600 | Semi Bold (Demi Bold) | [`FontWeight::SEMI_BOLD`] |
|
|
/// | 700 | Bold | [`FontWeight::BOLD`] |
|
|
/// | 800 | Extra Bold (Ultra Bold) | [`FontWeight::EXTRA_BOLD`] |
|
|
/// | 900 | Black (Heavy) | [`FontWeight::BLACK`] |
|
|
pub fn weight(&self) -> FontWeight {
|
|
FontWeight(unsafe { ffi::AFont_getWeight(self.ptr.as_ptr()) })
|
|
}
|
|
|
|
/// Returns [`true`] if the current font is italic, otherwise returns [`false`].
|
|
pub fn is_italic(&self) -> bool {
|
|
unsafe { ffi::AFont_isItalic(self.ptr.as_ptr()) }
|
|
}
|
|
}
|
|
|
|
impl Drop for Font {
|
|
fn drop(&mut self) {
|
|
unsafe { ffi::AFont_close(self.ptr.as_ptr()) }
|
|
}
|
|
}
|
|
|
|
/// Corresponds to [`AFAMILY_VARIANT_*`].
|
|
///
|
|
/// [`AFAMILY_VARIANT_*`]: https://developer.android.com/ndk/reference/group/font#group___font_1gga96a58e29e8dbf2b5bdeb775cba46556ea662aafc7016e35d6758da93416fc0833
|
|
#[repr(u32)]
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub enum FamilyVariant {
|
|
/// A family variant value for the compact font family variant.
|
|
/// The compact font family has Latin-based vertical metrics.
|
|
Compact = ffi::AFAMILY_VARIANT_COMPACT as _,
|
|
/// A family variant value for the system default variant.
|
|
Default = ffi::AFAMILY_VARIANT_DEFAULT as _,
|
|
/// A family variant value for the elegant font family variant.
|
|
/// The elegant font family may have larger vertical metrics than Latin font.
|
|
Elegant = ffi::AFAMILY_VARIANT_ELEGANT as _,
|
|
}
|
|
|
|
/// A native [`AFontMatcher *`]
|
|
///
|
|
/// [`AFontMatcher *`]: https://developer.android.com/ndk/reference/group/font#afontmatcher_create
|
|
#[derive(Debug)]
|
|
pub struct FontMatcher {
|
|
ptr: NonNull<ffi::AFontMatcher>,
|
|
}
|
|
|
|
impl FontMatcher {
|
|
/// Assumes ownership of `ptr`.
|
|
///
|
|
/// # Safety
|
|
/// `ptr` must be a valid owning pointer to an Android [`ffi::AFontMatcher`].
|
|
pub unsafe fn from_ptr(ptr: NonNull<ffi::AFontMatcher>) -> Self {
|
|
Self { ptr }
|
|
}
|
|
|
|
/// Returns s the pointer to the native [`ffi::AFontMatcher`].
|
|
pub fn ptr(&self) -> NonNull<ffi::AFontMatcher> {
|
|
self.ptr
|
|
}
|
|
|
|
/// Creates a new [`FontMatcher`] object. [`FontMatcher`] selects the best font from the
|
|
/// parameters set by the user.
|
|
pub fn new() -> Self {
|
|
let ptr = NonNull::new(unsafe { ffi::AFontMatcher_create() })
|
|
.expect("AFontMatcher_create returned NULL");
|
|
unsafe { FontMatcher::from_ptr(ptr) }
|
|
}
|
|
|
|
/// Performs the matching from the generic font family for the text and select one font.
|
|
///
|
|
/// For more information about generic font families, please read the
|
|
/// [W3C spec](https://www.w3.org/TR/css-fonts-4/#generic-font-families).
|
|
///
|
|
/// Even if no font can render the given text, this function will return a non-null result for
|
|
/// drawing Tofu character.
|
|
///
|
|
/// # Parameters
|
|
///
|
|
/// - `family_name`: A font family name.
|
|
/// - `text`: A UTF-16 encoded text buffer to be rendered. If an empty string is given, this
|
|
/// function will panic.
|
|
/// - `run_length_out`: Set this to [`Some`] if you want to get the length of the text run with
|
|
/// the font returned.
|
|
pub fn match_font(
|
|
&mut self,
|
|
family_name: &CStr,
|
|
text: &[u16],
|
|
run_length_out: Option<&mut u32>,
|
|
) -> Font {
|
|
if text.is_empty() {
|
|
panic!("text is empty");
|
|
}
|
|
unsafe {
|
|
Font::from_ptr(
|
|
NonNull::new(ffi::AFontMatcher_match(
|
|
self.ptr.as_ptr(),
|
|
family_name.as_ptr(),
|
|
text.as_ptr(),
|
|
text.len() as _,
|
|
run_length_out.map_or(std::ptr::null_mut(), |u| u),
|
|
))
|
|
.expect("AFontMatcher_match returned NULL"),
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Sets the family variant of the font to be matched.
|
|
///
|
|
/// If this function is not called, the match is performed with [`FamilyVariant::Default`].
|
|
pub fn set_family_variant(&mut self, family_variant: FamilyVariant) {
|
|
unsafe { ffi::AFontMatcher_setFamilyVariant(self.ptr.as_ptr(), family_variant as u32) }
|
|
}
|
|
|
|
/// Sets the locale of the font to be matched.
|
|
///
|
|
/// If this function is not called, the match is performed with an empty locale list.
|
|
///
|
|
/// # Parameters
|
|
///
|
|
/// - `language_tags`: comma separated IETF BCP47 compliant language tags.
|
|
pub fn set_locales(&mut self, language_tags: &CStr) {
|
|
unsafe { ffi::AFontMatcher_setLocales(self.ptr.as_ptr(), language_tags.as_ptr()) }
|
|
}
|
|
|
|
/// Sets the style of the font to be matched.
|
|
///
|
|
/// If this function is not called, the match is performed with [`FontWeight::NORMAL`] with non-italic style.
|
|
pub fn set_style(&mut self, weight: FontWeight, italic: bool) {
|
|
unsafe { ffi::AFontMatcher_setStyle(self.ptr.as_ptr(), weight.to_u16(), italic) }
|
|
}
|
|
}
|
|
|
|
impl Drop for FontMatcher {
|
|
fn drop(&mut self) {
|
|
unsafe { ffi::AFontMatcher_destroy(self.ptr.as_ptr()) }
|
|
}
|
|
}
|
|
|
|
/// A native [`ASystemFontIterator *`]
|
|
///
|
|
/// [`ASystemFontIterator *`]: https://developer.android.com/ndk/reference/group/font#asystemfontiterator_open
|
|
#[derive(Debug)]
|
|
pub struct SystemFontIterator {
|
|
ptr: NonNull<ffi::ASystemFontIterator>,
|
|
}
|
|
|
|
impl SystemFontIterator {
|
|
/// Assumes ownership of `ptr`.
|
|
///
|
|
/// # Safety
|
|
/// `ptr` must be a valid owning pointer to an Android [`ffi::ASystemFontIterator`].
|
|
pub unsafe fn from_ptr(ptr: NonNull<ffi::ASystemFontIterator>) -> Self {
|
|
Self { ptr }
|
|
}
|
|
|
|
/// Returns the pointer to the native [`ffi::ASystemFontIterator`].
|
|
pub fn ptr(&self) -> NonNull<ffi::ASystemFontIterator> {
|
|
self.ptr
|
|
}
|
|
|
|
/// Creates a system font iterator.
|
|
pub fn new() -> Option<Self> {
|
|
NonNull::new(unsafe { ffi::ASystemFontIterator_open() })
|
|
.map(|p| unsafe { SystemFontIterator::from_ptr(p) })
|
|
}
|
|
}
|
|
|
|
impl Iterator for SystemFontIterator {
|
|
type Item = Font;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
NonNull::new(unsafe { ffi::ASystemFontIterator_next(self.ptr.as_ptr()) })
|
|
.map(|p| unsafe { Font::from_ptr(p) })
|
|
}
|
|
}
|
|
|
|
impl Drop for SystemFontIterator {
|
|
fn drop(&mut self) {
|
|
unsafe { ffi::ASystemFontIterator_close(self.ptr.as_ptr()) }
|
|
}
|
|
}
|