mirror of
https://github.com/curioustorvald/Terrarum-sans-bitmap.git
synced 2026-03-16 16:06:06 +09:00
keming machine dot removal directive for OTF
This commit is contained in:
Binary file not shown.
@@ -38,6 +38,7 @@ class GlyphProps:
|
|||||||
has_kern_data: bool = False
|
has_kern_data: bool = False
|
||||||
is_kern_y_type: bool = False
|
is_kern_y_type: bool = False
|
||||||
kerning_mask: int = 255
|
kerning_mask: int = 255
|
||||||
|
dot_removal: Optional[int] = None # codepoint to replace with when followed by a STACK_UP mark
|
||||||
directive_opcode: int = 0
|
directive_opcode: int = 0
|
||||||
directive_arg1: int = 0
|
directive_arg1: int = 0
|
||||||
directive_arg2: int = 0
|
directive_arg2: int = 0
|
||||||
@@ -131,7 +132,8 @@ def parse_variable_sheet(image, sheet_index, cell_w, cell_h, cols, is_xy_swapped
|
|||||||
|
|
||||||
# Kerning data
|
# Kerning data
|
||||||
kerning_bit1 = _tagify(image.get_pixel(code_start_x, code_start_y + 6))
|
kerning_bit1 = _tagify(image.get_pixel(code_start_x, code_start_y + 6))
|
||||||
# kerning_bit2 and kerning_bit3 are reserved
|
kerning_bit2 = _tagify(image.get_pixel(code_start_x, code_start_y + 7))
|
||||||
|
dot_removal = None if kerning_bit2 == 0 else (kerning_bit2 >> 8)
|
||||||
is_kern_y_type = (kerning_bit1 & 0x80000000) != 0
|
is_kern_y_type = (kerning_bit1 & 0x80000000) != 0
|
||||||
kerning_mask = (kerning_bit1 >> 8) & 0xFFFFFF
|
kerning_mask = (kerning_bit1 >> 8) & 0xFFFFFF
|
||||||
has_kern_data = (kerning_bit1 & 0xFF) != 0
|
has_kern_data = (kerning_bit1 & 0xFF) != 0
|
||||||
@@ -188,7 +190,7 @@ def parse_variable_sheet(image, sheet_index, cell_w, cell_h, cols, is_xy_swapped
|
|||||||
align_where=align_where, write_on_top=write_on_top,
|
align_where=align_where, write_on_top=write_on_top,
|
||||||
stack_where=stack_where, ext_info=ext_info,
|
stack_where=stack_where, ext_info=ext_info,
|
||||||
has_kern_data=has_kern_data, is_kern_y_type=is_kern_y_type,
|
has_kern_data=has_kern_data, is_kern_y_type=is_kern_y_type,
|
||||||
kerning_mask=kerning_mask,
|
kerning_mask=kerning_mask, dot_removal=dot_removal,
|
||||||
directive_opcode=directive_opcode, directive_arg1=directive_arg1,
|
directive_opcode=directive_opcode, directive_arg1=directive_arg1,
|
||||||
directive_arg2=directive_arg2,
|
directive_arg2=directive_arg2,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -70,6 +70,11 @@ languagesystem sund dflt;
|
|||||||
if ccmp_code:
|
if ccmp_code:
|
||||||
parts.append(ccmp_code)
|
parts.append(ccmp_code)
|
||||||
|
|
||||||
|
# ccmp: dot removal (e.g. i→ı, j→ȷ when followed by STACK_UP marks)
|
||||||
|
dot_removal_code = _generate_dot_removal(glyphs, has)
|
||||||
|
if dot_removal_code:
|
||||||
|
parts.append(dot_removal_code)
|
||||||
|
|
||||||
# Hangul jamo GSUB assembly
|
# Hangul jamo GSUB assembly
|
||||||
hangul_code = _generate_hangul_gsub(glyphs, has, jamo_data)
|
hangul_code = _generate_hangul_gsub(glyphs, has, jamo_data)
|
||||||
if hangul_code:
|
if hangul_code:
|
||||||
@@ -162,6 +167,54 @@ def _generate_ccmp(replacewith_subs, has):
|
|||||||
return '\n'.join(lines)
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_dot_removal(glyphs, has):
|
||||||
|
"""Generate ccmp contextual substitution for dot removal.
|
||||||
|
|
||||||
|
When a base glyph tagged with dot_removal (kerning bit 2, pixel Y+7) is
|
||||||
|
followed by a STACK_UP mark, substitute the base with its dotless form.
|
||||||
|
Matches the Kotlin engine's dotRemoval logic.
|
||||||
|
"""
|
||||||
|
# Collect all STACK_UP marks
|
||||||
|
stack_up_marks = []
|
||||||
|
for cp, g in glyphs.items():
|
||||||
|
if g.props.write_on_top >= 0 and g.props.stack_where == SC.STACK_UP and has(cp):
|
||||||
|
stack_up_marks.append(cp)
|
||||||
|
|
||||||
|
if not stack_up_marks:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# Collect all base glyphs with dot_removal
|
||||||
|
dot_removal_subs = []
|
||||||
|
for cp, g in glyphs.items():
|
||||||
|
if g.props.dot_removal is not None and has(cp) and has(g.props.dot_removal):
|
||||||
|
dot_removal_subs.append((cp, g.props.dot_removal))
|
||||||
|
|
||||||
|
if not dot_removal_subs:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
# Define the STACK_UP marks class
|
||||||
|
mark_names = ' '.join(glyph_name(cp) for cp in sorted(stack_up_marks))
|
||||||
|
lines.append(f"@stackUpMarks = [{mark_names}];")
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
# Single substitution lookup for the replacements
|
||||||
|
lines.append("lookup DotRemoval {")
|
||||||
|
for src_cp, dst_cp in sorted(dot_removal_subs):
|
||||||
|
lines.append(f" sub {glyph_name(src_cp)} by {glyph_name(dst_cp)};")
|
||||||
|
lines.append("} DotRemoval;")
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
# Contextual rules in ccmp
|
||||||
|
lines.append("feature ccmp {")
|
||||||
|
for src_cp, _ in sorted(dot_removal_subs):
|
||||||
|
lines.append(f" sub {glyph_name(src_cp)}' lookup DotRemoval @stackUpMarks;")
|
||||||
|
lines.append("} ccmp;")
|
||||||
|
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
def _generate_hangul_gsub(glyphs, has, jamo_data):
|
def _generate_hangul_gsub(glyphs, has, jamo_data):
|
||||||
"""
|
"""
|
||||||
Generate Hangul jamo GSUB lookups for syllable assembly.
|
Generate Hangul jamo GSUB lookups for syllable assembly.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
--- Pixel 0
|
--- Pixel 0
|
||||||
- Lowheight bit
|
- Lowheight bit
|
||||||
- encoding: has pixel - it's low height
|
- encoding: has pixel - it's low height
|
||||||
- used by the diacritics system to quickly look up if the character is low height without parsing the Pixel 1
|
- bit must be set if above-diacritics should be lowered (e.g. lowercase b, which has 'A' shape bit but considered lowheight)
|
||||||
|
|
||||||
### Legends
|
### Legends
|
||||||
#
|
#
|
||||||
|
|||||||
Reference in New Issue
Block a user