Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finish syncing to 4.2.1 #101

Merged
merged 19 commits into from
Apr 13, 2024
Merged
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
4 changes: 2 additions & 2 deletions src/hb/aat_layout_morx_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,13 @@ pub fn apply(plan: &hb_ot_shape_plan_t, face: &hb_font_t, buffer: &mut hb_buffer
};

if reverse {
_hb_ot_layout_reverse_graphemes(buffer);
buffer.reverse();
}

apply_subtable(&subtable.kind, buffer, face);

if reverse {
_hb_ot_layout_reverse_graphemes(buffer);
buffer.reverse();
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/hb/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod face;
mod glyph_set;
mod kerning;
mod machine_cursor;
mod ot;
mod ot_layout;
mod ot_layout_common;
mod ot_layout_gpos_table;
Expand Down
33 changes: 33 additions & 0 deletions src/hb/ot/layout/GSUB/alternate_set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use crate::hb::ot_layout_gsubgpos::Apply;
use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
use crate::hb::ot_map::hb_ot_map_t;
use std::convert::TryFrom;
use ttf_parser::gsub::AlternateSet;

impl Apply for AlternateSet<'_> {
fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
let len = self.alternates.len();
if len == 0 {
return None;
}

let glyph_mask = ctx.buffer.cur(0).mask;

// Note: This breaks badly if two features enabled this lookup together.
let shift = ctx.lookup_mask.trailing_zeros();
let mut alt_index = (ctx.lookup_mask & glyph_mask) >> shift;

// If alt_index is MAX_VALUE, randomize feature if it is the rand feature.
if alt_index == hb_ot_map_t::MAX_VALUE && ctx.random {
// Maybe we can do better than unsafe-to-break all; but since we are
// changing random state, it would be hard to track that. Good 'nough.
ctx.buffer.unsafe_to_break(Some(0), Some(ctx.buffer.len));
alt_index = ctx.random_number() % u32::from(len) + 1;
}

let idx = u16::try_from(alt_index).ok()?.checked_sub(1)?;
ctx.replace_glyph(self.alternates.get(idx)?);

Some(())
}
}
20 changes: 20 additions & 0 deletions src/hb/ot/layout/GSUB/alternate_subst.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
use crate::hb::ot_layout_gsubgpos::{Apply, WouldApply, WouldApplyContext};
use ttf_parser::gsub::AlternateSubstitution;

// AlternateSubstFormat1::would_apply
impl WouldApply for AlternateSubstitution<'_> {
fn would_apply(&self, ctx: &WouldApplyContext) -> bool {
ctx.glyphs.len() == 1 && self.coverage.get(ctx.glyphs[0]).is_some()
}
}

// AlternateSubstFormat1::apply
impl Apply for AlternateSubstitution<'_> {
fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
let glyph = ctx.buffer.cur(0).as_glyph();
let index = self.coverage.get(glyph)?;
let set = self.alternate_sets.get(index)?;
set.apply(ctx)
}
}
62 changes: 62 additions & 0 deletions src/hb/ot/layout/GSUB/ligature.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use crate::hb::ot_layout::MAX_CONTEXT_LENGTH;
use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
use crate::hb::ot_layout_gsubgpos::{
ligate_input, match_glyph, match_input, Apply, WouldApply, WouldApplyContext,
};
use ttf_parser::gsub::Ligature;

impl WouldApply for Ligature<'_> {
fn would_apply(&self, ctx: &WouldApplyContext) -> bool {
ctx.glyphs.len() == usize::from(self.components.len()) + 1
&& self
.components
.into_iter()
.enumerate()
.all(|(i, comp)| ctx.glyphs[i + 1] == comp)
}
}

impl Apply for Ligature<'_> {
fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
// Special-case to make it in-place and not consider this
// as a "ligated" substitution.
if self.components.is_empty() {
ctx.replace_glyph(self.glyph);
Some(())
} else {
let f = |glyph, num_items| {
let index = self.components.len() - num_items;
let value = self.components.get(index).unwrap();
match_glyph(glyph, value.0)
};

let mut match_end = 0;
let mut match_positions = [0; MAX_CONTEXT_LENGTH];
let mut total_component_count = 0;

if !match_input(
ctx,
self.components.len(),
&f,
&mut match_end,
&mut match_positions,
Some(&mut total_component_count),
) {
ctx.buffer
.unsafe_to_concat(Some(ctx.buffer.idx), Some(match_end));
return None;
}

let count = usize::from(self.components.len()) + 1;
ligate_input(
ctx,
count,
&match_positions,
match_end,
total_component_count,
self.glyph,
);
return Some(());
}
}
}
20 changes: 20 additions & 0 deletions src/hb/ot/layout/GSUB/ligature_set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
use crate::hb::ot_layout_gsubgpos::{Apply, WouldApply, WouldApplyContext};
use ttf_parser::gsub::LigatureSet;

impl WouldApply for LigatureSet<'_> {
fn would_apply(&self, ctx: &WouldApplyContext) -> bool {
self.into_iter().any(|lig| lig.would_apply(ctx))
}
}

impl Apply for LigatureSet<'_> {
fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
for lig in self.into_iter() {
if lig.apply(ctx).is_some() {
return Some(());
}
}
None
}
}
24 changes: 24 additions & 0 deletions src/hb/ot/layout/GSUB/ligature_subst.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
use crate::hb::ot_layout_gsubgpos::{Apply, WouldApply, WouldApplyContext};
use ttf_parser::gsub::LigatureSubstitution;

// LigatureSubstFormat1::would_apply
impl WouldApply for LigatureSubstitution<'_> {
fn would_apply(&self, ctx: &WouldApplyContext) -> bool {
self.coverage
.get(ctx.glyphs[0])
.and_then(|index| self.ligature_sets.get(index))
.map_or(false, |set| set.would_apply(ctx))
}
}

// LigatureSubstFormat1::apply
impl Apply for LigatureSubstitution<'_> {
fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
let glyph = ctx.buffer.cur(0).as_glyph();
self.coverage
.get(glyph)
.and_then(|index| self.ligature_sets.get(index))
.and_then(|set| set.apply(ctx))
}
}
9 changes: 9 additions & 0 deletions src/hb/ot/layout/GSUB/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
mod alternate_set;
mod alternate_subst;
mod ligature;
mod ligature_set;
mod ligature_subst;
mod multi_subst;
mod reverse_chain_single_subst;
mod sequence;
mod single_subst;
20 changes: 20 additions & 0 deletions src/hb/ot/layout/GSUB/multi_subst.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
use crate::hb::ot_layout_gsubgpos::{Apply, WouldApply, WouldApplyContext};
use ttf_parser::gsub::MultipleSubstitution;

// MultipleSubstFormat1::would_apply
impl WouldApply for MultipleSubstitution<'_> {
fn would_apply(&self, ctx: &WouldApplyContext) -> bool {
ctx.glyphs.len() == 1 && self.coverage.get(ctx.glyphs[0]).is_some()
}
}

// MultipleSubstFormat1::apply
impl Apply for MultipleSubstitution<'_> {
fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
let glyph = ctx.buffer.cur(0).as_glyph();
let index = self.coverage.get(glyph)?;
let seq = self.sequences.get(index)?;
seq.apply(ctx)
}
}
69 changes: 69 additions & 0 deletions src/hb/ot/layout/GSUB/reverse_chain_single_subst.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use crate::hb::ot_layout::MAX_NESTING_LEVEL;
use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
use crate::hb::ot_layout_gsubgpos::{
match_backtrack, match_lookahead, Apply, WouldApply, WouldApplyContext,
};
use ttf_parser::gsub::ReverseChainSingleSubstitution;

// ReverseChainSingleSubstFormat1::would_apply
impl WouldApply for ReverseChainSingleSubstitution<'_> {
fn would_apply(&self, ctx: &WouldApplyContext) -> bool {
ctx.glyphs.len() == 1 && self.coverage.get(ctx.glyphs[0]).is_some()
}
}

// ReverseChainSingleSubstFormat1::apply
impl Apply for ReverseChainSingleSubstitution<'_> {
fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
// No chaining to this type.
if ctx.nesting_level_left != MAX_NESTING_LEVEL {
return None;
}

let glyph = ctx.buffer.cur(0).as_glyph();
let index = self.coverage.get(glyph)?;
if index >= self.substitutes.len() {
return None;
}

let subst = self.substitutes.get(index)?;

let f1 = |glyph, num_items| {
let index = self.backtrack_coverages.len() - num_items;
let value = self.backtrack_coverages.get(index).unwrap();
value.contains(glyph)
};

let f2 = |glyph, num_items| {
let index = self.lookahead_coverages.len() - num_items;
let value = self.lookahead_coverages.get(index).unwrap();
value.contains(glyph)
};

let mut start_index = 0;
let mut end_index = 0;

if match_backtrack(ctx, self.backtrack_coverages.len(), &f1, &mut start_index) {
if match_lookahead(
ctx,
self.lookahead_coverages.len(),
&f2,
ctx.buffer.idx + 1,
&mut end_index,
) {
ctx.buffer
.unsafe_to_break_from_outbuffer(Some(start_index), Some(end_index));
ctx.replace_glyph_inplace(subst);

// Note: We DON'T decrease buffer.idx. The main loop does it
// for us. This is useful for preventing surprises if someone
// calls us through a Context lookup.
return Some(());
}
}

ctx.buffer
.unsafe_to_concat_from_outbuffer(Some(start_index), Some(end_index));
return None;
}
}
44 changes: 44 additions & 0 deletions src/hb/ot/layout/GSUB/sequence.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::hb::buffer::GlyphPropsFlags;
use crate::hb::ot_layout::{
_hb_glyph_info_get_lig_id, _hb_glyph_info_is_ligature,
_hb_glyph_info_set_lig_props_for_component,
};
use crate::hb::ot_layout_gsubgpos::Apply;
use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
use ttf_parser::gsub::Sequence;

impl Apply for Sequence<'_> {
fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
match self.substitutes.len() {
// Spec disallows this, but Uniscribe allows it.
// https://github.com/harfbuzz/harfbuzz/issues/253
0 => ctx.buffer.delete_glyph(),

// Special-case to make it in-place and not consider this
// as a "multiplied" substitution.
1 => ctx.replace_glyph(self.substitutes.get(0)?),

_ => {
let class = if _hb_glyph_info_is_ligature(ctx.buffer.cur(0)) {
GlyphPropsFlags::BASE_GLYPH
} else {
GlyphPropsFlags::empty()
};
let lig_id = _hb_glyph_info_get_lig_id(ctx.buffer.cur(0));

for (i, subst) in self.substitutes.into_iter().enumerate() {
// If is attached to a ligature, don't disturb that.
// https://github.com/harfbuzz/harfbuzz/issues/3069
if lig_id == 0 {
// Index is truncated to 4 bits anway, so we can safely cast to u8.
_hb_glyph_info_set_lig_props_for_component(ctx.buffer.cur_mut(0), i as u8);
}
ctx.output_glyph_for_component(subst, class);
}

ctx.buffer.skip_glyph();
}
}
Some(())
}
}
38 changes: 38 additions & 0 deletions src/hb/ot/layout/GSUB/single_subst.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
use crate::hb::ot_layout_gsubgpos::{Apply, WouldApply, WouldApplyContext};
use ttf_parser::gsub::SingleSubstitution;
use ttf_parser::GlyphId;

// SingleSubstFormat1::would_apply
// SingleSubstFormat2::would_apply
impl WouldApply for SingleSubstitution<'_> {
fn would_apply(&self, ctx: &WouldApplyContext) -> bool {
ctx.glyphs.len() == 1 && self.coverage().get(ctx.glyphs[0]).is_some()
}
}

// SingleSubstFormat1::apply
// SingleSubstFormat2::apply
impl Apply for SingleSubstitution<'_> {
fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
let glyph = ctx.buffer.cur(0).as_glyph();
let subst = match *self {
Self::Format1 { coverage, delta } => {
coverage.get(glyph)?;
// According to the Adobe Annotated OpenType Suite, result is always
// limited to 16bit, so we explicitly want to truncate.
GlyphId((i32::from(glyph.0) + i32::from(delta)) as u16)
}
Self::Format2 {
coverage,
substitutes,
} => {
let index = coverage.get(glyph)?;
substitutes.get(index)?
}
};

ctx.replace_glyph(subst);
Some(())
}
}
Loading
Loading