-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #101 from Pi-Cla/4.2.1
Finish syncing to 4.2.1
- Loading branch information
Showing
29 changed files
with
659 additions
and
381 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(()) | ||
} | ||
} |
Oops, something went wrong.