Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions examples/shape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ OPTIONS:
--show-flags Output glyph flags
--single-par Treat the input string as a single paragraph
--ned No Extra Data; Do not output clusters or advances
-V, --trace Output interim shaping results

ARGS:
<FONT-FILE> A font file
Expand Down Expand Up @@ -67,6 +68,7 @@ struct Args {
single_par: bool,
ned: bool,
free: Vec<String>,
trace: bool,
}

fn parse_args() -> Result<Args, pico_args::Error> {
Expand Down Expand Up @@ -105,6 +107,7 @@ fn parse_args() -> Result<Args, pico_args::Error> {
show_flags: args.contains("--show-flags"),
single_par: args.contains("--single-par"),
ned: args.contains("--ned"),
trace: args.contains(["-V", "--trace"]),
free: args
.finish()
.iter()
Expand Down Expand Up @@ -185,6 +188,13 @@ fn main() {
let mut buffer = harfrust::UnicodeBuffer::new();
buffer.push_str(text);

if args.trace {
buffer.set_message_function(Box::new(|_buf, _font, msg| {
println!("trace: {msg}");
true
}));
}

if let Some(d) = args.direction {
buffer.set_direction(d);
}
Expand Down
4 changes: 4 additions & 0 deletions src/hb/aat/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,7 @@ pub fn substitute(
}

let mut c = AatApplyContext::new(plan, face, buffer);
message_return!(c, "start table morx");
layout_morx_table::apply(
&mut c,
if features.is_empty() {
Expand All @@ -523,6 +524,7 @@ pub fn substitute(
&aat_map
},
);
message!(c, "end table morx");
}

fn is_deleted_glyph(info: &GlyphInfo) -> bool {
Expand All @@ -545,7 +547,9 @@ pub fn remove_deleted_glyphs(buffer: &mut hb_buffer_t) {
#[doc(alias = "hb_aat_layout_position")]
pub fn position(plan: &hb_ot_shape_plan_t, face: &hb_font_t, buffer: &mut hb_buffer_t) {
let mut c = AatApplyContext::new(plan, face, buffer);
message_return!(c, "start table kerx");
layout_kerx_table::apply(&mut c);
message!(c, "end table kerx");
}

/// HB: hb_aat_layout_track
Expand Down
9 changes: 9 additions & 0 deletions src/hb/aat/layout_kerx_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,18 @@ pub(crate) fn apply(c: &mut AatApplyContext) -> Option<()> {
c.start_end_safe_to_break = subtable_cache.start_end_safe_to_break;

if !c.buffer_intersects_machine() {
message!(
c,
"skipping kerning subtable {} because no glyph matches",
subtable_idx
);
continue;
}

let reverse = c.buffer.direction.is_backward();

message_continue!(c, "start subtable {}", subtable_idx);

if !seen_cross_stream && subtable.is_cross_stream() {
seen_cross_stream = true;

Expand Down Expand Up @@ -138,6 +145,8 @@ pub(crate) fn apply(c: &mut AatApplyContext) -> Option<()> {
}
}
}

message!(c, "end subtable {}", subtable_idx);
if c.buffer_is_reversed {
c.reverse_buffer();
}
Expand Down
9 changes: 9 additions & 0 deletions src/hb/aat/layout_morx_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ pub fn apply<'a>(c: &mut AatApplyContext<'a>, map: &'a AatMap) -> Option<()> {
c.start_end_safe_to_break = subtable_cache.start_end_safe_to_break;

if !c.buffer_intersects_machine() {
message!(
c,
"skipped chainsubtable {} because no glyph matches",
subtable_idx
);

continue;
}

Expand Down Expand Up @@ -159,13 +165,16 @@ pub fn apply<'a>(c: &mut AatApplyContext<'a>, map: &'a AatMap) -> Option<()> {
subtable.is_backwards() != c.buffer.direction.is_backward()
};

message_continue!(c, "start chainsubtable {}", subtable_idx);

if reverse != c.buffer_is_reversed {
c.reverse_buffer();
}

if let Ok(kind) = subtable.kind() {
apply_subtable(kind, c);
}
message!(c, "end chainsubtable {}", subtable_idx);
}
if c.buffer_is_reversed {
c.reverse_buffer();
Expand Down
115 changes: 115 additions & 0 deletions src/hb/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ pub const HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: u32 = 2;
pub const HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES: u32 = 3;
pub const HB_BUFFER_CLUSTER_LEVEL_DEFAULT: u32 = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES;

pub type MessageFunction<'a> = Box<dyn FnMut(&hb_buffer_t, &hb_font_t, &str) -> bool + 'a>;
pub struct hb_buffer_t {
// Information about how the text in the buffer should be treated.
pub flags: BufferFlags,
Expand Down Expand Up @@ -440,6 +441,17 @@ pub struct hb_buffer_t {
pub max_len: usize,
/// Maximum allowed operations.
pub max_ops: i32,

pub(crate) message_depth: usize,

/// Callback used to receive a message
///
/// The function gets called with the `Buffer`, the `Font` the
/// buffer is shaped with, and a message describing what step of the shaping
/// process will be performed.
/// The function should return `true` to perform the shaping step, or `false`
/// to skip it and move to the next one.
pub message_function: Option<MessageFunction<'static>>,
}

impl hb_buffer_t {
Expand Down Expand Up @@ -481,6 +493,8 @@ impl hb_buffer_t {
context_len: [0, 0],
digest: hb_set_digest_t::new(),
glyph_set: U32Set::default(),
message_depth: 0,
message_function: None,
}
}

Expand Down Expand Up @@ -785,6 +799,25 @@ impl hb_buffer_t {
true
}

#[cfg(feature = "std")]
pub(crate) fn sync_so_far(&mut self) -> usize {
let had_output = self.have_output;
let out_i = self.out_len;
let i = self.idx;
let old_idx = self.idx;
if self.sync() {
self.idx = out_i;
} else {
self.idx = i;
}
if had_output {
self.have_output = true;
self.out_len = self.idx;
}
debug_assert!(self.idx <= self.len);
self.idx - old_idx
}

pub fn clear_output(&mut self) {
self.have_output = true;
self.have_positions = false;
Expand Down Expand Up @@ -1604,6 +1637,78 @@ impl hb_buffer_t {

lig_id
}

#[inline]
pub fn set_message_function(&mut self, func: MessageFunction<'static>) {
#[cfg(feature = "std")]
{
self.message_function = Some(func);
}
}

#[inline]
pub(crate) fn message(&mut self, font: &hb_font_t, msg: &str) -> bool {
if let Some(mut func) = self.message_function.take() {
self.message_depth += 1;
let ret = func(self, font, msg);
self.message_depth -= 1;
self.message_function = Some(func);
ret
} else {
true
}
}

#[cfg(feature = "std")]
#[inline]
pub(crate) fn messaging(&self) -> bool {
self.message_function.is_some()
}
}

macro_rules! message {
($ctx:expr, $($arg:tt)*) => {
#[cfg(feature = "std")]
if $ctx.buffer.messaging() {
let msg = format!($($arg)*);
$ctx.buffer.message($ctx.face, &msg);
}
};
}

macro_rules! message_sync {
($ctx:expr, $($arg:tt)*) => {
#[cfg(feature = "std")]
if $ctx.buffer.messaging() {
$ctx.buffer.sync_so_far();
let msg = format!($($arg)*);
$ctx.buffer.message($ctx.face, &msg);
}
};
}

macro_rules! message_return {
($ctx:expr, $($arg:tt)*) => {
#[cfg(feature = "std")]
if $ctx.buffer.messaging() {
let msg = format!($($arg)*);
if !$ctx.buffer.message($ctx.face, &msg) {
return;
}
}
};
}

macro_rules! message_continue {
($ctx:expr, $($arg:tt)*) => {
#[cfg(feature = "std")]
if $ctx.buffer.messaging() {
let msg = format!($($arg)*);
if !$ctx.buffer.message($ctx.face, &msg) {
continue;
}
}
};
}

pub(crate) fn _cluster_group_func(a: &GlyphInfo, b: &GlyphInfo) -> bool {
Expand Down Expand Up @@ -1852,6 +1957,13 @@ impl UnicodeBuffer {
pub fn clear(&mut self) {
self.0.clear();
}

/// Sets a function to be called when HarfBuzz wants to emit a message.
#[cfg(feature = "std")]
#[inline]
pub fn set_message_function(&mut self, func: MessageFunction<'static>) {
self.0.set_message_function(func);
}
}

impl core::fmt::Debug for UnicodeBuffer {
Expand Down Expand Up @@ -1900,6 +2012,9 @@ impl GlyphBuffer {
/// Get the glyph positions.
#[inline]
pub fn glyph_positions(&self) -> &[GlyphPosition] {
if self.0.message_depth > 0 {
return &[];
}
&self.0.pos[0..self.0.len]
}

Expand Down
7 changes: 7 additions & 0 deletions src/hb/kerning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ pub fn hb_ot_layout_kern(
) -> Option<()> {
let mut c = AatApplyContext::new(plan, face, buffer);

#[cfg(feature = "std")]
if !c.buffer.message(face, "start table kern") {
return None;
}

let (kern, subtable_caches) = c.face.aat_tables.kern.as_ref()?;

let mut subtable_idx = 0;
Expand Down Expand Up @@ -115,6 +120,8 @@ pub fn hb_ot_layout_kern(
if c.buffer_is_reversed {
c.reverse_buffer();
}
#[cfg(feature = "std")]
c.buffer.message(face, "end table kern");
Some(())
}

Expand Down
4 changes: 4 additions & 0 deletions src/hb/ot/gpos/cursive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ impl Apply for CursivePosFormat1<'_> {
let j = ctx.buffer.idx;
ctx.buffer.unsafe_to_break(Some(i), Some(j + 1));

message!(ctx, "cursive attaching glyph at {} to glyph at {}", i, j);

let pos = &mut ctx.buffer.pos;
match direction {
Direction::LeftToRight => {
Expand Down Expand Up @@ -122,6 +124,8 @@ impl Apply for CursivePosFormat1<'_> {
}
}

message!(ctx, "cursive attached glyph at {} to glyph at {}", i, j);

ctx.buffer.idx += 1;
Some(())
}
Expand Down
16 changes: 16 additions & 0 deletions src/hb/ot/gpos/mark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,29 @@ impl MarkArrayExt for MarkArray<'_> {
.unsafe_to_break(Some(glyph_pos), Some(ctx.buffer.idx + 1));

let idx = ctx.buffer.idx;

message!(
ctx,
"attaching mark glyph at {} to glyph at {}",
idx,
glyph_pos
);

let pos = ctx.buffer.cur_pos_mut();
pos.x_offset = base_x - mark_x;
pos.y_offset = base_y - mark_y;
pos.set_attach_type(attach_type::MARK);
pos.set_attach_chain((glyph_pos as isize - idx as isize) as i16);

ctx.buffer.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;

message!(
ctx,
"attached mark glyph at {} to glyph at {}",
idx,
glyph_pos
);

ctx.buffer.idx += 1;

Some(())
Expand Down
Loading
Loading