use alloc::{string::String, vec::Vec};
use core::convert::TryFrom;
use core::cmp::min;
use ttf_parser::GlyphId;
use super::buffer::glyph_flag::{UNSAFE_TO_BREAK, UNSAFE_TO_CONCAT};
use super::face::GlyphExtents;
use super::unicode::{CharExt, GeneralCategoryExt};
use super::{hb_font_t, hb_mask_t};
use crate::{script, BufferClusterLevel, BufferFlags, Direction, Language, Script, SerializeFlags};
const CONTEXT_LENGTH: usize = 5;
pub mod glyph_flag {
pub const UNSAFE_TO_BREAK: u32 = 0x00000001;
pub const UNSAFE_TO_CONCAT: u32 = 0x00000002;
pub const DEFINED: u32 = 0x00000003; }
#[repr(C)]
#[derive(Clone, Copy, Default, Debug)]
pub struct GlyphPosition {
pub x_advance: i32,
pub y_advance: i32,
pub x_offset: i32,
pub y_offset: i32,
var: u32,
}
unsafe impl bytemuck::Zeroable for GlyphPosition {}
unsafe impl bytemuck::Pod for GlyphPosition {}
impl GlyphPosition {
#[inline]
pub(crate) fn attach_chain(&self) -> i16 {
let v: &[i16; 2] = bytemuck::cast_ref(&self.var);
v[0]
}
#[inline]
pub(crate) fn set_attach_chain(&mut self, n: i16) {
let v: &mut [i16; 2] = bytemuck::cast_mut(&mut self.var);
v[0] = n;
}
#[inline]
pub(crate) fn attach_type(&self) -> u8 {
let v: &[u8; 4] = bytemuck::cast_ref(&self.var);
v[2]
}
#[inline]
pub(crate) fn set_attach_type(&mut self, n: u8) {
let v: &mut [u8; 4] = bytemuck::cast_mut(&mut self.var);
v[2] = n;
}
}
#[repr(C)]
#[derive(Clone, Copy, Default, Debug)]
pub struct hb_glyph_info_t {
pub glyph_id: u32,
pub(crate) mask: hb_mask_t,
pub cluster: u32,
pub(crate) var1: u32,
pub(crate) var2: u32,
}
unsafe impl bytemuck::Zeroable for hb_glyph_info_t {}
unsafe impl bytemuck::Pod for hb_glyph_info_t {}
impl hb_glyph_info_t {
pub fn unsafe_to_break(&self) -> bool {
self.mask & glyph_flag::UNSAFE_TO_BREAK != 0
}
#[inline]
pub(crate) fn as_char(&self) -> char {
char::try_from(self.glyph_id).unwrap()
}
#[inline]
pub(crate) fn as_glyph(&self) -> GlyphId {
debug_assert!(self.glyph_id <= u32::from(u16::MAX));
GlyphId(self.glyph_id as u16)
}
#[inline]
pub(crate) fn unicode_props(&self) -> u16 {
let v: &[u16; 2] = bytemuck::cast_ref(&self.var2);
v[0]
}
#[inline]
pub(crate) fn set_unicode_props(&mut self, n: u16) {
let v: &mut [u16; 2] = bytemuck::cast_mut(&mut self.var2);
v[0] = n;
}
pub(crate) fn init_unicode_props(&mut self, scratch_flags: &mut hb_buffer_scratch_flags_t) {
let u = self.as_char();
let gc = u.general_category();
let mut props = gc.to_rb() as u16;
if u as u32 >= 0x80 {
*scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
if u.is_default_ignorable() {
props |= UnicodeProps::IGNORABLE.bits();
*scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
match u as u32 {
0x200C => props |= UnicodeProps::CF_ZWNJ.bits(),
0x200D => props |= UnicodeProps::CF_ZWJ.bits(),
0x180B..=0x180D | 0x180F => props |= UnicodeProps::HIDDEN.bits(),
0xE0020..=0xE007F => props |= UnicodeProps::HIDDEN.bits(),
0x034F => {
props |= UnicodeProps::HIDDEN.bits();
*scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CGJ;
}
_ => {}
}
}
if gc.is_mark() {
props |= UnicodeProps::CONTINUATION.bits();
props |= (u.modified_combining_class() as u16) << 8;
}
}
self.set_unicode_props(props);
}
#[inline]
pub(crate) fn is_hidden(&self) -> bool {
self.unicode_props() & UnicodeProps::HIDDEN.bits() != 0
}
#[inline]
pub(crate) fn unhide(&mut self) {
let mut n = self.unicode_props();
n &= !UnicodeProps::HIDDEN.bits();
self.set_unicode_props(n);
}
#[inline]
pub(crate) fn lig_props(&self) -> u8 {
let v: &[u8; 4] = bytemuck::cast_ref(&self.var1);
v[2]
}
#[inline]
pub(crate) fn set_lig_props(&mut self, n: u8) {
let v: &mut [u8; 4] = bytemuck::cast_mut(&mut self.var1);
v[2] = n;
}
#[inline]
pub(crate) fn glyph_props(&self) -> u16 {
let v: &[u16; 2] = bytemuck::cast_ref(&self.var1);
v[0]
}
#[inline]
pub(crate) fn set_glyph_props(&mut self, n: u16) {
let v: &mut [u16; 2] = bytemuck::cast_mut(&mut self.var1);
v[0] = n;
}
#[inline]
pub(crate) fn syllable(&self) -> u8 {
let v: &[u8; 4] = bytemuck::cast_ref(&self.var1);
v[3]
}
#[inline]
pub(crate) fn set_syllable(&mut self, n: u8) {
let v: &mut [u8; 4] = bytemuck::cast_mut(&mut self.var1);
v[3] = n;
}
#[inline]
pub(crate) fn glyph_index(&mut self) -> u32 {
self.var1
}
#[inline]
pub(crate) fn set_glyph_index(&mut self, n: u32) {
self.var1 = n;
}
}
pub type hb_buffer_cluster_level_t = u32;
pub const HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES: u32 = 0;
pub const HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS: u32 = 1;
pub const HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: u32 = 2;
pub const HB_BUFFER_CLUSTER_LEVEL_DEFAULT: u32 = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES;
pub struct hb_buffer_t {
pub flags: BufferFlags,
pub cluster_level: hb_buffer_cluster_level_t,
pub invisible: Option<GlyphId>,
pub direction: Direction,
pub script: Option<Script>,
pub language: Option<Language>,
pub successful: bool,
pub(crate) have_output: bool,
pub have_separate_output: bool,
pub have_positions: bool,
pub idx: usize,
pub len: usize,
pub out_len: usize,
pub info: Vec<hb_glyph_info_t>,
pub pos: Vec<GlyphPosition>,
pub context: [[char; CONTEXT_LENGTH]; 2],
pub context_len: [usize; 2],
pub serial: u8,
pub scratch_flags: hb_buffer_scratch_flags_t,
pub max_len: usize,
pub max_ops: i32,
}
impl hb_buffer_t {
pub const MAX_LEN_FACTOR: usize = 64;
pub const MAX_LEN_MIN: usize = 16384;
pub const MAX_LEN_DEFAULT: usize = 0x3FFFFFFF;
pub const MAX_OPS_FACTOR: i32 = 1024;
pub const MAX_OPS_MIN: i32 = 16384;
pub const MAX_OPS_DEFAULT: i32 = 0x1FFFFFFF;
pub fn new() -> Self {
hb_buffer_t {
flags: BufferFlags::empty(),
cluster_level: HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
invisible: None,
scratch_flags: HB_BUFFER_SCRATCH_FLAG_DEFAULT,
max_len: Self::MAX_LEN_DEFAULT,
max_ops: Self::MAX_OPS_DEFAULT,
direction: Direction::Invalid,
script: None,
language: None,
successful: true,
have_output: false,
have_positions: false,
idx: 0,
len: 0,
out_len: 0,
info: Vec::new(),
pos: Vec::new(),
have_separate_output: false,
serial: 0,
context: [
['\0', '\0', '\0', '\0', '\0'],
['\0', '\0', '\0', '\0', '\0'],
],
context_len: [0, 0],
}
}
#[inline]
pub fn info_slice(&self) -> &[hb_glyph_info_t] {
&self.info[..self.len]
}
#[inline]
pub fn info_slice_mut(&mut self) -> &mut [hb_glyph_info_t] {
&mut self.info[..self.len]
}
#[inline]
pub fn out_info(&self) -> &[hb_glyph_info_t] {
if self.have_separate_output {
bytemuck::cast_slice(self.pos.as_slice())
} else {
&self.info
}
}
#[inline]
pub fn out_info_mut(&mut self) -> &mut [hb_glyph_info_t] {
if self.have_separate_output {
bytemuck::cast_slice_mut(self.pos.as_mut_slice())
} else {
&mut self.info
}
}
#[inline]
fn set_out_info(&mut self, i: usize, info: hb_glyph_info_t) {
self.out_info_mut()[i] = info;
}
#[inline]
pub fn cur(&self, i: usize) -> &hb_glyph_info_t {
&self.info[self.idx + i]
}
#[inline]
pub fn cur_mut(&mut self, i: usize) -> &mut hb_glyph_info_t {
let idx = self.idx + i;
&mut self.info[idx]
}
#[inline]
pub fn cur_pos_mut(&mut self) -> &mut GlyphPosition {
let i = self.idx;
&mut self.pos[i]
}
#[inline]
pub fn prev(&self) -> &hb_glyph_info_t {
let idx = self.out_len.saturating_sub(1);
&self.out_info()[idx]
}
#[inline]
pub fn prev_mut(&mut self) -> &mut hb_glyph_info_t {
let idx = self.out_len.saturating_sub(1);
&mut self.out_info_mut()[idx]
}
fn clear(&mut self) {
self.direction = Direction::Invalid;
self.script = None;
self.language = None;
self.successful = true;
self.have_output = false;
self.have_positions = false;
self.idx = 0;
self.info.clear();
self.pos.clear();
self.len = 0;
self.out_len = 0;
self.have_separate_output = false;
self.context = [
['\0', '\0', '\0', '\0', '\0'],
['\0', '\0', '\0', '\0', '\0'],
];
self.context_len = [0, 0];
self.serial = 0;
self.scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
self.cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
}
#[inline]
pub fn backtrack_len(&self) -> usize {
if self.have_output {
self.out_len
} else {
self.idx
}
}
#[inline]
pub fn lookahead_len(&self) -> usize {
self.len - self.idx
}
#[inline]
fn next_serial(&mut self) -> u8 {
self.serial += 1;
if self.serial == 0 {
self.serial += 1;
}
self.serial
}
fn add(&mut self, codepoint: u32, cluster: u32) {
self.ensure(self.len + 1);
let i = self.len;
self.info[i] = hb_glyph_info_t {
glyph_id: codepoint,
mask: 0,
cluster,
var1: 0,
var2: 0,
};
self.len += 1;
}
#[inline]
pub fn reverse(&mut self) {
if self.is_empty() {
return;
}
self.reverse_range(0, self.len);
}
pub fn reverse_range(&mut self, start: usize, end: usize) {
if end - start < 2 {
return;
}
self.info[start..end].reverse();
if self.have_positions {
self.pos[start..end].reverse();
}
}
pub fn reverse_groups<F>(&mut self, group: F, merge_clusters: bool)
where
F: Fn(&hb_glyph_info_t, &hb_glyph_info_t) -> bool,
{
if self.is_empty() {
return;
}
let mut start = 0;
for i in 1..self.len {
if !group(&self.info[i - 1], &self.info[i]) {
if merge_clusters {
self.merge_clusters(start, i);
}
self.reverse_range(start, i);
start = i;
}
if merge_clusters {
self.merge_clusters(start, i);
}
self.reverse_range(start, i);
self.reverse();
}
}
pub fn group_end<F>(&self, mut start: usize, group: F) -> usize
where
F: Fn(&hb_glyph_info_t, &hb_glyph_info_t) -> bool,
{
start += 1;
while start < self.len && group(&self.info[start - 1], &self.info[start]) {
start += 1;
}
start
}
#[inline]
fn reset_clusters(&mut self) {
for (i, info) in self.info.iter_mut().enumerate() {
info.cluster = i as u32;
}
}
pub fn guess_segment_properties(&mut self) {
if self.script.is_none() {
for info in &self.info {
match info.as_char().script() {
crate::script::COMMON | crate::script::INHERITED | crate::script::UNKNOWN => {}
s => {
self.script = Some(s);
break;
}
}
}
}
if self.direction == Direction::Invalid {
if let Some(script) = self.script {
self.direction = Direction::from_script(script).unwrap_or_default();
}
if self.direction == Direction::Invalid {
self.direction = Direction::LeftToRight;
}
}
}
pub fn sync(&mut self) {
assert!(self.have_output);
assert!(self.idx <= self.len);
if !self.successful {
self.have_output = false;
self.out_len = 0;
self.idx = 0;
return;
}
self.next_glyphs(self.len - self.idx);
if self.have_separate_output {
let info: Vec<GlyphPosition> = bytemuck::cast_vec(core::mem::take(&mut self.info));
let pos: Vec<hb_glyph_info_t> = bytemuck::cast_vec(core::mem::take(&mut self.pos));
self.pos = info;
self.info = pos;
}
self.len = self.out_len;
self.have_output = false;
self.out_len = 0;
self.idx = 0;
}
pub fn clear_output(&mut self) {
self.have_output = true;
self.have_positions = false;
self.idx = 0;
self.out_len = 0;
self.have_separate_output = false;
}
pub fn clear_positions(&mut self) {
self.have_output = false;
self.have_positions = true;
self.out_len = 0;
self.have_separate_output = false;
for pos in &mut self.pos {
*pos = GlyphPosition::default();
}
}
pub fn replace_glyphs(&mut self, num_in: usize, num_out: usize, glyph_data: &[u32]) {
if !self.make_room_for(num_in, num_out) {
return;
}
assert!(self.idx + num_in <= self.len);
self.merge_clusters(self.idx, self.idx + num_in);
let orig_info = self.info[self.idx];
for i in 0..num_out {
let ii = self.out_len + i;
self.set_out_info(ii, orig_info);
self.out_info_mut()[ii].glyph_id = glyph_data[i];
}
self.idx += num_in;
self.out_len += num_out;
}
pub fn replace_glyph(&mut self, glyph_index: u32) {
if self.have_separate_output || self.out_len != self.idx {
if !self.make_room_for(1, 1) {
return;
}
self.set_out_info(self.out_len, self.info[self.idx]);
}
let out_len = self.out_len;
self.out_info_mut()[out_len].glyph_id = glyph_index;
self.idx += 1;
self.out_len += 1;
}
pub fn output_glyph(&mut self, glyph_index: u32) {
if !self.make_room_for(0, 1) {
return;
}
if self.idx == self.len && self.out_len == 0 {
return;
}
let out_len = self.out_len;
if self.idx < self.len {
self.set_out_info(out_len, self.info[self.idx]);
} else {
let info = self.out_info()[out_len - 1];
self.set_out_info(out_len, info);
}
self.out_info_mut()[out_len].glyph_id = glyph_index;
self.out_len += 1;
}
pub fn output_info(&mut self, glyph_info: hb_glyph_info_t) {
if !self.make_room_for(0, 1) {
return;
}
self.set_out_info(self.out_len, glyph_info);
self.out_len += 1;
}
pub fn copy_glyph(&mut self) {
if !self.make_room_for(0, 1) {
return;
}
self.set_out_info(self.out_len, self.info[self.idx]);
self.out_len += 1;
}
pub fn next_glyph(&mut self) {
if self.have_output {
if self.have_separate_output || self.out_len != self.idx {
if !self.make_room_for(1, 1) {
return;
}
self.set_out_info(self.out_len, self.info[self.idx]);
}
self.out_len += 1;
}
self.idx += 1;
}
pub fn next_glyphs(&mut self, n: usize) {
if self.have_output {
if self.have_separate_output || self.out_len != self.idx {
if !self.make_room_for(n, n) {
return;
}
for i in 0..n {
self.set_out_info(self.out_len + i, self.info[self.idx + i]);
}
}
self.out_len += n;
}
self.idx += n;
}
pub fn skip_glyph(&mut self) {
self.idx += 1;
}
pub fn reset_masks(&mut self, mask: hb_mask_t) {
for info in &mut self.info[..self.len] {
info.mask = mask;
}
}
pub fn set_masks(
&mut self,
mut value: hb_mask_t,
mask: hb_mask_t,
cluster_start: u32,
cluster_end: u32,
) {
let not_mask = !mask;
value &= mask;
if mask == 0 {
return;
}
if cluster_start == 0 && cluster_end == core::u32::MAX {
for info in &mut self.info[..self.len] {
info.mask = (info.mask & not_mask) | value;
}
return;
}
for info in &mut self.info[..self.len] {
if cluster_start <= info.cluster && info.cluster < cluster_end {
info.mask = (info.mask & not_mask) | value;
}
}
}
pub fn merge_clusters(&mut self, start: usize, end: usize) {
if end - start < 2 {
return;
}
self.merge_clusters_impl(start, end)
}
fn merge_clusters_impl(&mut self, mut start: usize, mut end: usize) {
if self.cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS {
self.unsafe_to_break(Some(start), Some(end));
return;
}
let mut cluster = self.info[start].cluster;
for i in start + 1..end {
cluster = core::cmp::min(cluster, self.info[i].cluster);
}
while end < self.len && self.info[end - 1].cluster == self.info[end].cluster {
end += 1;
}
while end < start && self.info[start - 1].cluster == self.info[start].cluster {
start -= 1;
}
if self.idx == start {
let mut i = self.out_len;
while i != 0 && self.out_info()[i - 1].cluster == self.info[start].cluster {
Self::set_cluster(&mut self.out_info_mut()[i - 1], cluster, 0);
i -= 1;
}
}
for i in start..end {
Self::set_cluster(&mut self.info[i], cluster, 0);
}
}
pub fn merge_out_clusters(&mut self, mut start: usize, mut end: usize) {
if self.cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS {
return;
}
if end - start < 2 {
return;
}
let mut cluster = self.out_info()[start].cluster;
for i in start + 1..end {
cluster = core::cmp::min(cluster, self.out_info()[i].cluster);
}
while start != 0 && self.out_info()[start - 1].cluster == self.out_info()[start].cluster {
start -= 1;
}
while end < self.out_len && self.out_info()[end - 1].cluster == self.out_info()[end].cluster
{
end += 1;
}
if end == self.out_len {
let mut i = self.idx;
while i < self.len && self.info[i].cluster == self.out_info()[end - 1].cluster {
Self::set_cluster(&mut self.info[i], cluster, 0);
i += 1;
}
}
for i in start..end {
Self::set_cluster(&mut self.out_info_mut()[i], cluster, 0);
}
}
pub fn delete_glyph(&mut self) {
let cluster = self.info[self.idx].cluster;
if self.idx + 1 < self.len && cluster == self.info[self.idx + 1].cluster {
self.skip_glyph();
return;
}
if self.out_len != 0 {
if cluster < self.out_info()[self.out_len - 1].cluster {
let mask = self.info[self.idx].mask;
let old_cluster = self.out_info()[self.out_len - 1].cluster;
let mut i = self.out_len;
while i != 0 && self.out_info()[i - 1].cluster == old_cluster {
Self::set_cluster(&mut self.out_info_mut()[i - 1], cluster, mask);
i -= 1;
}
}
self.skip_glyph();
return;
}
if self.idx + 1 < self.len {
self.merge_clusters(self.idx, self.idx + 2);
}
self.skip_glyph();
}
pub fn delete_glyphs_inplace(&mut self, filter: impl Fn(&hb_glyph_info_t) -> bool) {
let mut j = 0;
for i in 0..self.len {
if filter(&self.info[i]) {
let cluster = self.info[i].cluster;
if i + 1 < self.len && cluster == self.info[i + 1].cluster {
continue;
}
if j != 0 {
if cluster < self.info[j - 1].cluster {
let mask = self.info[i].mask;
let old_cluster = self.info[j - 1].cluster;
let mut k = j;
while k > 0 && self.info[k - 1].cluster == old_cluster {
Self::set_cluster(&mut self.info[k - 1], cluster, mask);
k -= 1;
}
}
continue;
}
if i + 1 < self.len {
self.merge_clusters(i, i + 2);
}
continue;
}
if j != i {
self.info[j] = self.info[i];
self.pos[j] = self.pos[i];
}
j += 1;
}
self.len = j;
}
pub fn unsafe_to_break(&mut self, start: Option<usize>, end: Option<usize>) {
self._set_glyph_flags(
UNSAFE_TO_BREAK | UNSAFE_TO_CONCAT,
start,
end,
Some(true),
None,
);
}
fn _set_glyph_flags(
&mut self,
mask: hb_mask_t,
start: Option<usize>,
end: Option<usize>,
interior: Option<bool>,
from_out_buffer: Option<bool>,
) {
let start = start.unwrap_or(0);
let end = min(end.unwrap_or(self.len), self.len);
let interior = interior.unwrap_or(false);
let from_out_buffer = from_out_buffer.unwrap_or(false);
if interior && !from_out_buffer && end - start < 2 {
return;
}
self.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
if !from_out_buffer || !self.have_output {
if !interior {
for i in start..end {
self.info[i].mask |= mask;
}
} else {
let cluster = Self::_infos_find_min_cluster(&self.info, start, end, None);
if Self::_infos_set_glyph_flags(&mut self.info, start, end, cluster, mask) {
self.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
}
}
} else {
assert!(start <= self.out_len);
assert!(self.idx <= end);
if !interior {
for i in start..self.out_len {
self.out_info_mut()[i].mask |= mask;
}
for i in self.idx..end {
self.info[i].mask |= mask;
}
} else {
let mut cluster = Self::_infos_find_min_cluster(&self.info, self.idx, end, None);
cluster = Self::_infos_find_min_cluster(
&self.out_info(),
start,
self.out_len,
Some(cluster),
);
let out_len = self.out_len;
let first = Self::_infos_set_glyph_flags(
&mut self.out_info_mut(),
start,
out_len,
cluster,
mask,
);
let second =
Self::_infos_set_glyph_flags(&mut self.info, self.idx, end, cluster, mask);
if first || second {
self.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
}
}
}
}
pub fn unsafe_to_concat(&mut self, start: Option<usize>, end: Option<usize>) {
if !self.flags.contains(BufferFlags::PRODUCE_UNSAFE_TO_CONCAT) {
return;
}
self._set_glyph_flags(UNSAFE_TO_CONCAT, start, end, Some(true), None);
}
pub fn unsafe_to_break_from_outbuffer(&mut self, start: Option<usize>, end: Option<usize>) {
if !self.flags.contains(BufferFlags::PRODUCE_UNSAFE_TO_CONCAT) {
return;
}
self._set_glyph_flags(
UNSAFE_TO_BREAK | UNSAFE_TO_CONCAT,
start,
end,
Some(true),
Some(true),
);
}
pub fn unsafe_to_concat_from_outbuffer(&mut self, start: Option<usize>, end: Option<usize>) {
self._set_glyph_flags(UNSAFE_TO_CONCAT, start, end, Some(false), Some(true));
}
pub fn move_to(&mut self, i: usize) -> bool {
if !self.have_output {
assert!(i <= self.len);
self.idx = i;
return true;
}
if !self.successful {
return false;
}
assert!(i <= self.out_len + (self.len - self.idx));
if self.out_len < i {
let count = i - self.out_len;
if !self.make_room_for(count, count) {
return false;
}
for j in 0..count {
self.set_out_info(self.out_len + j, self.info[self.idx + j]);
}
self.idx += count;
self.out_len += count;
} else if self.out_len > i {
let count = self.out_len - i;
if self.idx < count {
self.shift_forward(count - self.idx);
}
assert!(self.idx >= count);
self.idx -= count;
self.out_len -= count;
for j in 0..count {
self.info[self.idx + j] = self.out_info()[self.out_len + j];
}
}
true
}
pub fn ensure(&mut self, size: usize) -> bool {
if size < self.len {
return true;
}
if size > self.max_len {
self.successful = false;
return false;
}
self.info.resize(size, hb_glyph_info_t::default());
self.pos.resize(size, GlyphPosition::default());
true
}
pub fn set_len(&mut self, len: usize) {
self.ensure(len);
self.len = len;
}
fn make_room_for(&mut self, num_in: usize, num_out: usize) -> bool {
if !self.ensure(self.out_len + num_out) {
return false;
}
if !self.have_separate_output && self.out_len + num_out > self.idx + num_in {
assert!(self.have_output);
self.have_separate_output = true;
for i in 0..self.out_len {
self.set_out_info(i, self.info[i]);
}
}
true
}
fn shift_forward(&mut self, count: usize) {
assert!(self.have_output);
self.ensure(self.len + count);
for i in (0..(self.len - self.idx)).rev() {
self.info[self.idx + count + i] = self.info[self.idx + i];
}
if self.idx + count > self.len {
for info in &mut self.info[self.len..self.idx + count] {
*info = hb_glyph_info_t::default();
}
}
self.len += count;
self.idx += count;
}
fn clear_context(&mut self, side: usize) {
self.context_len[side] = 0;
}
pub fn sort(
&mut self,
start: usize,
end: usize,
cmp: impl Fn(&hb_glyph_info_t, &hb_glyph_info_t) -> bool,
) {
assert!(!self.have_positions);
for i in start + 1..end {
let mut j = i;
while j > start && cmp(&self.info[j - 1], &self.info[i]) {
j -= 1;
}
if i == j {
continue;
}
self.merge_clusters(j, i + 1);
{
let t = self.info[i];
for idx in (0..i - j).rev() {
self.info[idx + j + 1] = self.info[idx + j];
}
self.info[j] = t;
}
}
}
pub fn set_cluster(info: &mut hb_glyph_info_t, cluster: u32, mask: hb_mask_t) {
if info.cluster != cluster {
info.mask = (info.mask & !glyph_flag::DEFINED) | (mask & glyph_flag::DEFINED);
}
info.cluster = cluster;
}
pub(crate) fn enter(&mut self) {
self.serial = 0;
self.scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
if let Some(len) = self.len.checked_mul(hb_buffer_t::MAX_LEN_FACTOR) {
self.max_len = len.max(hb_buffer_t::MAX_LEN_MIN);
}
if let Ok(len) = i32::try_from(self.len) {
if let Some(ops) = len.checked_mul(hb_buffer_t::MAX_OPS_FACTOR) {
self.max_ops = ops.max(hb_buffer_t::MAX_OPS_MIN);
}
}
}
pub(crate) fn leave(&mut self) {
self.max_len = hb_buffer_t::MAX_LEN_DEFAULT;
self.max_ops = hb_buffer_t::MAX_OPS_DEFAULT;
self.serial = 0;
}
fn _infos_find_min_cluster(
info: &[hb_glyph_info_t],
start: usize,
end: usize,
cluster: Option<u32>,
) -> u32 {
let mut cluster = cluster.unwrap_or(core::u32::MAX);
for glyph_info in &info[start..end] {
cluster = core::cmp::min(cluster, glyph_info.cluster);
}
cluster
}
#[must_use]
fn _infos_set_glyph_flags(
info: &mut [hb_glyph_info_t],
start: usize,
end: usize,
cluster: u32,
mask: hb_mask_t,
) -> bool {
let mut unsafe_to_break = false;
for glyph_info in &mut info[start..end] {
if glyph_info.cluster != cluster {
glyph_info.mask |= mask;
unsafe_to_break = true;
}
}
unsafe_to_break
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
fn push_str(&mut self, text: &str) {
self.ensure(self.len + text.chars().count());
for (i, c) in text.char_indices() {
self.add(c as u32, i as u32);
}
}
fn set_pre_context(&mut self, text: &str) {
self.clear_context(0);
for (i, c) in text.chars().rev().enumerate().take(CONTEXT_LENGTH) {
self.context[0][i] = c;
self.context_len[0] += 1;
}
}
fn set_post_context(&mut self, text: &str) {
self.clear_context(1);
for (i, c) in text.chars().enumerate().take(CONTEXT_LENGTH) {
self.context[1][i] = c;
self.context_len[1] += 1;
}
}
pub fn next_syllable(&self, mut start: usize) -> usize {
if start >= self.len {
return start;
}
let syllable = self.info[start].syllable();
start += 1;
while start < self.len && syllable == self.info[start].syllable() {
start += 1;
}
start
}
#[inline]
pub fn allocate_lig_id(&mut self) -> u8 {
let mut lig_id = self.next_serial() & 0x07;
if lig_id == 0 {
lig_id = self.allocate_lig_id();
}
lig_id
}
}
pub(crate) fn _cluster_group_func(a: &hb_glyph_info_t, b: &hb_glyph_info_t) -> bool {
a.cluster == b.cluster
}
macro_rules! foreach_cluster {
($buffer:expr, $start:ident, $end:ident, $($body:tt)*) => {
foreach_group!($buffer, $start, $end, crate::hb::buffer::_cluster_group_func, $($body)*)
};
}
macro_rules! foreach_group {
($buffer:expr, $start:ident, $end:ident, $group_func:expr, $($body:tt)*) => {{
let count = $buffer.len;
let mut $start = 0;
let mut $end = if count > 0 { $buffer.group_end(0, $group_func) } else { 0 };
while $start < count {
$($body)*;
$start = $end;
$end = $buffer.group_end($start, $group_func);
}
}};
}
macro_rules! foreach_syllable {
($buffer:expr, $start:ident, $end:ident, $($body:tt)*) => {{
let mut $start = 0;
let mut $end = $buffer.next_syllable(0);
while $start < $buffer.len {
$($body)*;
$start = $end;
$end = $buffer.next_syllable($start);
}
}};
}
macro_rules! foreach_grapheme {
($buffer:expr, $start:ident, $end:ident, $($body:tt)*) => {
foreach_group!($buffer, $start, $end, crate::hb::ot_layout::_hb_grapheme_group_func, $($body)*)
};
}
bitflags::bitflags! {
#[derive(Default, Debug, Clone, Copy)]
pub struct UnicodeProps: u16 {
const GENERAL_CATEGORY = 0x001F;
const IGNORABLE = 0x0020;
const HIDDEN = 0x0040;
const CONTINUATION = 0x0080;
const CF_ZWJ = 0x0100;
const CF_ZWNJ = 0x0200;
}
}
bitflags::bitflags! {
#[derive(Default, Debug, Clone, Copy)]
pub struct GlyphPropsFlags: u16 {
const BASE_GLYPH = 0x02;
const LIGATURE = 0x04;
const MARK = 0x08;
const CLASS_MASK = Self::BASE_GLYPH.bits() | Self::LIGATURE.bits() | Self::MARK.bits();
const SUBSTITUTED = 0x10;
const LIGATED = 0x20;
const MULTIPLIED = 0x40;
const PRESERVE = Self::SUBSTITUTED.bits() | Self::LIGATED.bits() | Self::MULTIPLIED.bits();
}
}
pub type hb_buffer_scratch_flags_t = u32;
pub const HB_BUFFER_SCRATCH_FLAG_DEFAULT: u32 = 0x00000000;
pub const HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII: u32 = 0x00000001;
pub const HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES: u32 = 0x00000002;
pub const HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK: u32 = 0x00000004;
pub const HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT: u32 = 0x00000008;
pub const HB_BUFFER_SCRATCH_FLAG_HAS_CGJ: u32 = 0x00000010;
pub const HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS: u32 = 0x00000020;
pub const HB_BUFFER_SCRATCH_FLAG_COMPLEX0: u32 = 0x01000000;
pub struct UnicodeBuffer(pub(crate) hb_buffer_t);
impl UnicodeBuffer {
#[inline]
pub fn new() -> UnicodeBuffer {
UnicodeBuffer(hb_buffer_t::new())
}
#[inline]
pub fn len(&self) -> usize {
self.0.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
pub fn push_str(&mut self, str: &str) {
self.0.push_str(str);
}
#[inline]
pub fn set_pre_context(&mut self, str: &str) {
self.0.set_pre_context(str)
}
#[inline]
pub fn set_post_context(&mut self, str: &str) {
self.0.set_post_context(str)
}
#[inline]
pub fn add(&mut self, codepoint: char, cluster: u32) {
self.0.add(codepoint as u32, cluster);
self.0.context_len[1] = 0;
}
#[inline]
pub fn set_direction(&mut self, direction: Direction) {
self.0.direction = direction;
}
#[inline]
pub fn direction(&self) -> Direction {
self.0.direction
}
#[inline]
pub fn set_script(&mut self, script: Script) {
self.0.script = Some(script);
}
pub fn script(&self) -> Script {
self.0.script.unwrap_or(script::UNKNOWN)
}
#[inline]
pub fn set_language(&mut self, lang: Language) {
self.0.language = Some(lang);
}
#[inline]
pub fn language(&self) -> Option<Language> {
self.0.language.clone()
}
#[inline]
pub fn guess_segment_properties(&mut self) {
self.0.guess_segment_properties()
}
#[inline]
pub fn set_flags(&mut self, flags: BufferFlags) {
self.0.flags = flags;
}
#[inline]
pub fn flags(&self) -> BufferFlags {
self.0.flags
}
#[inline]
pub fn set_cluster_level(&mut self, cluster_level: BufferClusterLevel) {
self.0.cluster_level = match cluster_level {
BufferClusterLevel::MonotoneGraphemes => HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES,
BufferClusterLevel::MonotoneCharacters => HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS,
BufferClusterLevel::Characters => HB_BUFFER_CLUSTER_LEVEL_CHARACTERS,
}
}
#[inline]
pub fn cluster_level(&self) -> BufferClusterLevel {
match self.0.cluster_level {
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES => BufferClusterLevel::MonotoneGraphemes,
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS => BufferClusterLevel::MonotoneCharacters,
HB_BUFFER_CLUSTER_LEVEL_CHARACTERS => BufferClusterLevel::Characters,
_ => BufferClusterLevel::MonotoneGraphemes,
}
}
#[inline]
pub fn reset_clusters(&mut self) {
self.0.reset_clusters();
}
#[inline]
pub fn clear(&mut self) {
self.0.clear()
}
}
impl core::fmt::Debug for UnicodeBuffer {
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::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) hb_buffer_t);
impl GlyphBuffer {
#[inline]
pub fn len(&self) -> usize {
self.0.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
pub fn glyph_infos(&self) -> &[hb_glyph_info_t] {
&self.0.info[0..self.0.len]
}
#[inline]
pub fn glyph_positions(&self) -> &[GlyphPosition] {
&self.0.pos[0..self.0.len]
}
#[inline]
pub fn clear(mut self) -> UnicodeBuffer {
self.0.clear();
UnicodeBuffer(self.0)
}
pub fn serialize(&self, face: &hb_font_t, flags: SerializeFlags) -> String {
self.serialize_impl(face, flags).unwrap_or_default()
}
fn serialize_impl(
&self,
face: &hb_font_t,
flags: SerializeFlags,
) -> Result<String, core::fmt::Error> {
use core::fmt::Write;
let mut s = String::with_capacity(64);
let info = self.glyph_infos();
let pos = self.glyph_positions();
let mut x = 0;
let mut y = 0;
for (info, pos) in info.iter().zip(pos) {
if !flags.contains(SerializeFlags::NO_GLYPH_NAMES) {
match face.glyph_name(info.as_glyph()) {
Some(name) => s.push_str(name),
None => write!(&mut s, "gid{}", info.glyph_id)?,
}
} else {
write!(&mut s, "{}", info.glyph_id)?;
}
if !flags.contains(SerializeFlags::NO_CLUSTERS) {
write!(&mut s, "={}", info.cluster)?;
}
if !flags.contains(SerializeFlags::NO_POSITIONS) {
if x + pos.x_offset != 0 || y + pos.y_offset != 0 {
write!(&mut s, "@{},{}", x + pos.x_offset, y + pos.y_offset)?;
}
if !flags.contains(SerializeFlags::NO_ADVANCES) {
write!(&mut s, "+{}", pos.x_advance)?;
if pos.y_advance != 0 {
write!(&mut s, ",{}", pos.y_advance)?;
}
}
}
if flags.contains(SerializeFlags::GLYPH_FLAGS) {
if info.mask & glyph_flag::DEFINED != 0 {
write!(&mut s, "#{:X}", info.mask & glyph_flag::DEFINED)?;
}
}
if flags.contains(SerializeFlags::GLYPH_EXTENTS) {
let mut extents = GlyphExtents::default();
face.glyph_extents(info.as_glyph(), &mut extents);
write!(
&mut s,
"<{},{},{},{}>",
extents.x_bearing, extents.y_bearing, extents.width, extents.height
)?;
}
if flags.contains(SerializeFlags::NO_ADVANCES) {
x += pos.x_advance;
y += pos.y_advance;
}
s.push('|');
}
if !s.is_empty() {
s.pop();
}
Ok(s)
}
}
impl core::fmt::Debug for GlyphBuffer {
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
fmt.debug_struct("GlyphBuffer")
.field("glyph_positions", &self.glyph_positions())
.field("glyph_infos", &self.glyph_infos())
.finish()
}
}