#![deny(missing_debug_implementations)]
use harfbuzz_sys as hb;
#[macro_use]
extern crate bitflags;
mod blob;
mod buffer;
mod common;
mod face;
mod font;
pub mod font_funcs;
#[cfg(feature = "rusttype")]
pub mod rusttype;
pub use crate::blob::*;
pub use crate::buffer::*;
pub use crate::common::*;
pub use crate::face::*;
pub use crate::font::*;
use std::ops::{Bound, RangeBounds};
use std::os::raw::c_uint;
pub(crate) fn start_end_range(range: impl RangeBounds<usize>) -> (c_uint, c_uint) {
const MAX_UINT: usize = c_uint::max_value() as usize;
let start = match range.start_bound() {
Bound::Included(&included) => included.min(MAX_UINT) as c_uint,
Bound::Excluded(&excluded) => excluded.min(MAX_UINT - 1) as c_uint + 1,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(&included) => included.saturating_add(1).min(MAX_UINT) as c_uint,
Bound::Excluded(&excluded) => excluded.min(MAX_UINT) as c_uint,
Bound::Unbounded => c_uint::max_value(),
};
(start, end)
}
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Variation(hb::hb_variation_t);
impl Variation {
pub fn new(tag: impl Into<Tag>, value: f32) -> Variation {
Variation(hb::hb_variation_t {
tag: tag.into().0,
value,
})
}
pub fn tag(&self) -> Tag {
Tag(self.0.tag)
}
pub fn value(&self) -> f32 {
self.0.value
}
}
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Feature(hb::hb_feature_t);
impl Feature {
pub fn new(tag: impl Into<Tag>, value: u32, range: impl RangeBounds<usize>) -> Feature {
let (start, end) = start_end_range(range);
Feature(hb::hb_feature_t {
tag: tag.into().0,
value,
start,
end,
})
}
pub fn tag(&self) -> Tag {
Tag(self.0.tag)
}
pub fn value(&self) -> u32 {
self.0.value
}
pub fn start(&self) -> usize {
self.0.start as usize
}
pub fn end(&self) -> usize {
self.0.end as usize
}
}
pub fn shape(font: &Font<'_>, buffer: UnicodeBuffer, features: &[Feature]) -> GlyphBuffer {
let buffer = buffer.guess_segment_properties();
unsafe {
hb::hb_shape(
font.as_raw(),
buffer.0.as_raw(),
features.as_ptr() as *mut _,
features.len() as u32,
)
};
GlyphBuffer(buffer.0)
}
#[cfg(test)]
mod tests {
use std::mem::{align_of, size_of};
pub(crate) fn assert_memory_layout_equal<T, U>() {
assert_eq!(size_of::<T>(), size_of::<U>());
assert_eq!(align_of::<T>(), align_of::<U>());
}
#[test]
fn it_works() {}
fn assert_feature(feat: Feature, tag: Tag, value: u32, start: usize, end: usize) {
assert_eq!(feat.tag(), tag);
assert_eq!(feat.value(), value);
assert_eq!(feat.start(), start);
assert_eq!(feat.end(), end);
}
use super::{Feature, Tag};
#[test]
fn feature_new() {
let tag = b"abcd".into();
const UINT_MAX: usize = std::os::raw::c_uint::max_value() as usize;
let feature = Feature::new(tag, 100, 2..100);
assert_feature(feature, tag, 100, 2, 100);
let feature = Feature::new(tag, 100, 2..=100);
assert_feature(feature, tag, 100, 2, 101);
let feature = Feature::new(tag, 100, 2..);
assert_feature(feature, tag, 100, 2, UINT_MAX);
let feature = Feature::new(tag, 100, ..100);
assert_feature(feature, tag, 100, 0, 100);
let feature = Feature::new(tag, 100, ..=100);
assert_feature(feature, tag, 100, 0, 101);
let feature = Feature::new(tag, 100, ..);
assert_feature(feature, tag, 100, 0, UINT_MAX);
}
}