From 23e748cc88f64e53334344b7afcd7e8a24b5a624 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sat, 28 Feb 2026 05:30:46 +0900 Subject: [PATCH] tamil vowel positioning fix --- OTFbuild/calligra_font_tests.odt | Bin 14920 -> 15232 bytes OTFbuild/font_builder.py | 17 +++++++++-------- OTFbuild/opentype_features.py | 4 +++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/OTFbuild/calligra_font_tests.odt b/OTFbuild/calligra_font_tests.odt index c73d93446b54b7ce367a82b34094819cbbc972be..f6cd61ba0750993cc391d8b9d5d4c8f7051d479e 100644 GIT binary patch delta 13957 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 diff --git a/OTFbuild/font_builder.py b/OTFbuild/font_builder.py index 96ba4b5..58378fe 100644 --- a/OTFbuild/font_builder.py +++ b/OTFbuild/font_builder.py @@ -267,21 +267,22 @@ def build_font(assets_dir, output_path, no_bitmap=False, no_features=False): # ALIGN_BEFORE: offset = 0 # The bitmap cell width depends on the sheet type. # nudge_x shifts the glyph left by that many pixels in the - # bitmap engine. For zero-advance glyphs (marks and width-0 - # non-marks like U+0361) this is a pure visual shift that must - # be baked into the contours. For positive-advance glyphs the - # bitmap engine's nudge/extraWidth mechanism already maps to - # the OTF advance, so we must NOT shift contours. + # bitmap engine. The Kotlin engine always applies nudge_x to + # the drawing position (posXbuffer = -nudgeX + ...) and the + # next glyph compensates via extraWidth, so the effective + # origin-to-origin advance stays at `width`. We must bake + # the same leftward shift into the contour x_offset. import math - bm_cols = len(g.bitmap[0]) if g.bitmap and g.bitmap[0] else 0 + # The Kotlin engine always uses W_VAR_INIT for alignment calculations, + # even for EXTRAWIDE sheets. Use W_VAR_INIT here to match. + bm_cols = SC.W_VAR_INIT if g.props.align_where == SC.ALIGN_RIGHT: x_offset = (g.props.width - bm_cols) * SCALE elif g.props.align_where == SC.ALIGN_CENTRE: x_offset = math.ceil((g.props.width - bm_cols) / 2) * SCALE else: x_offset = 0 - if advance == 0: - x_offset -= g.props.nudge_x * SCALE + x_offset -= g.props.nudge_x * SCALE # For STACK_DOWN marks (below-base diacritics), negative nudge_y # means "shift content down to below baseline". The sign convention diff --git a/OTFbuild/opentype_features.py b/OTFbuild/opentype_features.py index 988db62..2f12232 100644 --- a/OTFbuild/opentype_features.py +++ b/OTFbuild/opentype_features.py @@ -1278,7 +1278,9 @@ def _generate_mark(glyphs, has): # uses (W_VAR_INIT + 1) / 2 instead (1 px nudge left). # mark_x must match font_builder's total x_offset # (alignment + nudge) so column `half` sits on the anchor. - bm_cols = len(g.bitmap[0]) if g.bitmap and g.bitmap[0] else 0 + # The Kotlin engine always uses W_VAR_INIT for alignment, + # even for EXTRAWIDE sheets. + bm_cols = SC.W_VAR_INIT if 0x0900 <= cp <= 0x0902: half = (SC.W_VAR_INIT + 1) // 2 else: