use std::fmt;
use std::io::Read;
use std::ptr::NonNull;
use crate::common::{Direction, Language, Tag};
use crate::ffi;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct GlyphPosition {
pub x_advance: i32,
pub y_advance: i32,
pub x_offset: i32,
pub y_offset: i32,
var: ffi::hb_var_int_t,
}
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct GlyphInfo {
pub glyph: u32,
mask: ffi::hb_mask_t,
pub cluster: u32,
var1: ffi::hb_var_int_t,
var2: ffi::hb_var_int_t,
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum BufferClusterLevel {
MonotoneGraphemes,
MonotoneCharacters,
Characters,
}
impl BufferClusterLevel {
fn from_raw(raw: ffi::hb_buffer_cluster_level_t) -> Self {
match raw {
ffi::HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES => BufferClusterLevel::MonotoneGraphemes,
ffi::HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS => BufferClusterLevel::MonotoneCharacters,
ffi::HB_BUFFER_CLUSTER_LEVEL_CHARACTERS => BufferClusterLevel::Characters,
_ => panic!("received unrecognized HB_BUFFER_CLUSTER_LEVEL"),
}
}
fn into_raw(self) -> ffi::hb_buffer_cluster_level_t {
match self {
BufferClusterLevel::MonotoneGraphemes => ffi::HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES,
BufferClusterLevel::MonotoneCharacters => ffi::HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS,
BufferClusterLevel::Characters => ffi::HB_BUFFER_CLUSTER_LEVEL_CHARACTERS,
}
}
}
impl Default for BufferClusterLevel {
fn default() -> Self {
BufferClusterLevel::MonotoneGraphemes
}
}
pub(crate) struct Buffer {
ptr: NonNull<ffi::hb_buffer_t>,
}
impl Buffer {
fn new() -> Buffer {
let ptr = NonNull::new(unsafe { ffi::hb_buffer_create() }).unwrap();
Buffer { ptr }
}
pub fn as_ptr(&self) -> *mut ffi::hb_buffer_t {
self.ptr.as_ptr()
}
fn len(&self) -> usize {
unsafe { ffi::hb_buffer_get_length(self.as_ptr()) as usize }
}
fn is_empty(&self) -> bool {
self.len() == 0
}
fn clear(&mut self) {
unsafe { ffi::hb_buffer_clear_contents(self.as_ptr()) };
}
}
impl Drop for Buffer {
fn drop(&mut self) {
unsafe { ffi::hb_buffer_destroy(self.as_ptr()) }
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum SerializeFormat {
Text,
Json,
}
impl From<SerializeFormat> for ffi::hb_buffer_serialize_format_t {
fn from(fmt: SerializeFormat) -> Self {
match fmt {
SerializeFormat::Text => ffi::HB_BUFFER_SERIALIZE_FORMAT_TEXT,
SerializeFormat::Json => ffi::HB_BUFFER_SERIALIZE_FORMAT_JSON,
}
}
}
bitflags::bitflags! {
#[derive(Default)]
pub struct SerializeFlags: u32 {
const NO_CLUSTERS = ffi::HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS;
const NO_POSITIONS = ffi::HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
const NO_GLYPH_NAMES = ffi::HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES;
const GLYPH_EXTENTS = ffi::HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS;
const GLYPH_FLAGS = ffi::HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS;
const NO_ADVANCES = ffi::HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES;
}
}
pub struct BufferSerializer<'a> {
font: Option<&'a crate::Font<'a>>,
buffer: &'a Buffer,
start: usize,
end: usize,
format: SerializeFormat,
flags: SerializeFlags,
bytes: std::io::Cursor<Vec<u8>>,
}
impl<'a> Read for BufferSerializer<'a> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self.bytes.read(buf) {
Ok(0) => {
if self.start > self.end.saturating_sub(1) {
return Ok(0);
}
let mut bytes_written = 0;
let num_serialized_items = unsafe {
ffi::hb_buffer_serialize_glyphs(
self.buffer.as_ptr(),
self.start as u32,
self.end as u32,
self.bytes.get_mut().as_mut_ptr() as *mut _,
self.bytes.get_ref().capacity() as u32,
&mut bytes_written,
self.font
.map(|f| f.as_ptr())
.unwrap_or(std::ptr::null_mut()),
self.format.into(),
self.flags.bits(),
)
};
self.start += num_serialized_items as usize;
self.bytes.set_position(0);
unsafe { self.bytes.get_mut().set_len(bytes_written as usize) };
self.read(buf)
}
Ok(size) => Ok(size),
Err(err) => Err(err),
}
}
}
pub struct UnicodeBuffer(pub(crate) Buffer);
impl UnicodeBuffer {
#[inline]
pub fn new() -> UnicodeBuffer {
UnicodeBuffer(Buffer::new())
}
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn push_str(&mut self, str: &str) {
unsafe {
ffi::hb_buffer_add_utf8(
self.0.as_ptr(),
str.as_ptr() as *const _,
str.len() as i32,
0,
str.len() as i32,
);
}
}
pub fn set_direction(&mut self, direction: Direction) {
unsafe { ffi::hb_buffer_set_direction(self.0.as_ptr(), direction.to_raw()) };
}
pub fn direction(&self) -> Direction {
Direction::from_raw(unsafe { ffi::hb_buffer_get_direction(self.0.as_ptr()) })
}
pub fn set_script(&mut self, script: Tag) {
unsafe {
let script = ffi::hb_script_from_iso15924_tag(script.0);
ffi::hb_buffer_set_script(self.0.as_ptr(), script)
}
}
pub fn script(&self) -> Tag {
Tag(unsafe {
let script = ffi::hb_buffer_get_script(self.0.as_ptr());
ffi::hb_script_to_iso15924_tag(script)
})
}
pub fn set_language(&mut self, lang: Language) {
unsafe { ffi::hb_buffer_set_language(self.0.as_ptr(), lang.0) }
}
pub fn language(&self) -> Option<Language> {
let raw_lang = unsafe { ffi::hb_buffer_get_language(self.0.as_ptr()) };
if raw_lang.is_null() {
None
} else {
Some(Language(raw_lang))
}
}
pub fn guess_segment_properties(&mut self) {
unsafe { ffi::hb_buffer_guess_segment_properties(self.0.as_ptr()) };
}
pub fn set_cluster_level(&mut self, cluster_level: BufferClusterLevel) {
unsafe { ffi::hb_buffer_set_cluster_level(self.0.as_ptr(), cluster_level.into_raw()) }
}
pub fn cluster_level(&self) -> BufferClusterLevel {
BufferClusterLevel::from_raw(unsafe { ffi::hb_buffer_get_cluster_level(self.0.as_ptr()) })
}
pub fn reset_clusters(&mut self) {
unsafe { ffi::hb_buffer_reset_clusters(self.0.as_ptr()) }
}
pub fn clear(&mut self) {
self.0.clear()
}
}
impl std::fmt::Debug for UnicodeBuffer {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.debug_struct("UnicodeBuffer")
.field("direction", &self.direction())
.field("language", &self.language())
.field("script", &self.script())
.field("cluster_level", &self.cluster_level())
.finish()
}
}
impl Default for UnicodeBuffer {
fn default() -> UnicodeBuffer {
UnicodeBuffer::new()
}
}
pub struct GlyphBuffer(pub(crate) Buffer);
impl GlyphBuffer {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn glyph_positions(&self) -> &[GlyphPosition] {
unsafe {
let mut length: u32 = 0;
let glyph_pos =
ffi::hb_buffer_get_glyph_positions(self.0.as_ptr(), &mut length as *mut u32);
std::slice::from_raw_parts(glyph_pos as *const _, length as usize)
}
}
pub fn glyph_infos(&self) -> &[GlyphInfo] {
unsafe {
let mut length: u32 = 0;
let glyph_infos = ffi::hb_buffer_get_glyph_infos(self.0.as_ptr(), &mut length as *mut u32);
std::slice::from_raw_parts(glyph_infos as *const _, length as usize)
}
}
pub fn clear(mut self) -> UnicodeBuffer {
self.0.clear();
UnicodeBuffer(self.0)
}
pub fn serializer<'a>(
&'a self,
font: Option<&'a crate::Font<'a>>,
format: SerializeFormat,
flags: SerializeFlags,
) -> BufferSerializer<'a> {
BufferSerializer {
font,
buffer: &self.0,
start: 0,
end: self.len(),
format,
flags,
bytes: std::io::Cursor::new(Vec::with_capacity(128)),
}
}
}
impl fmt::Debug for GlyphBuffer {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("GlyphBuffer")
.field("glyph_positions", &self.glyph_positions())
.field("glyph_infos", &self.glyph_infos())
.finish()
}
}
impl fmt::Display for GlyphBuffer {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut serializer =
self.serializer(None, SerializeFormat::Text, SerializeFlags::default());
let mut string = String::new();
serializer.read_to_string(&mut string).unwrap();
write!(fmt, "{}", string)?;
Ok(())
}
}