keming machine dot removal directive

This commit is contained in:
minjaesong
2026-03-07 22:41:24 +09:00
parent 163e3d7b3e
commit 2008bbf6dd
8 changed files with 27 additions and 21 deletions

View File

@@ -46,8 +46,8 @@ Rightmost vertical column (should be 20 px tall) contains the tags. Tags are def
W |= Width of the character W |= Width of the character
W | W |
W -' W -'
m --Is this character lowheight?
K -, K -,
K |
K |= Tags used by the "Keming Machine" K |= Tags used by the "Keming Machine"
K -' K -'
Q ---Compiler Directive (see below) Q ---Compiler Directive (see below)

View File

@@ -370,10 +370,9 @@ def build_font(assets_dir, output_path, no_bitmap=False, no_features=False):
x_offset = 0 x_offset = 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 # For marks (write_on_top >= 0), positive nudge_y means shift UP
# means "shift content down to below baseline". The sign convention # in the bitmap engine (opposite to non-marks where positive = down).
# is opposite to non-marks where positive nudge_y means shift down. if g.props.write_on_top >= 0:
if g.props.stack_where == SC.STACK_DOWN and g.props.write_on_top >= 0:
y_offset = g.props.nudge_y * SCALE y_offset = g.props.nudge_y * SCALE
else: else:
y_offset = -g.props.nudge_y * SCALE y_offset = -g.props.nudge_y * SCALE

View File

@@ -1878,12 +1878,16 @@ def _generate_mark(glyphs, has):
lines.append(f"lookup {mkmk_name} {{") lines.append(f"lookup {mkmk_name} {{")
if scat == 'up': if scat == 'up':
m2y = SC.ASCENT + SC.H_DIACRITICS * SC.SCALE m2y_base = SC.ASCENT + SC.H_DIACRITICS * SC.SCALE
else: # 'dn' else: # 'dn'
m2y = SC.ASCENT - SC.H_DIACRITICS * SC.SCALE m2y_base = SC.ASCENT - SC.H_DIACRITICS * SC.SCALE
for cp, g in mark_list: for cp, g in mark_list:
mx = mark_anchors.get(cp, 0) mx = mark_anchors.get(cp, 0)
# Cascade nudge_y: the mark2 anchor includes this mark's
# nudge so that the next stacked mark inherits the shift,
# matching the Kotlin engine's nudgeUpwardCounter / nudgeDownwardCounter.
m2y = m2y_base + g.props.nudge_y * SC.SCALE
lines.append( lines.append(
f" pos mark {glyph_name(cp)}" f" pos mark {glyph_name(cp)}"
f" <anchor {mx} {m2y}> mark {class_name};" f" <anchor {mx} {m2y}> mark {class_name};"

View File

@@ -106,3 +106,5 @@ dot removal for diacritics:
- encoding: - encoding:
- <MSB> RRRRRRRR GGGGGGGG BBBBBBBB <LSB> - <MSB> RRRRRRRR GGGGGGGG BBBBBBBB <LSB>
--- Pixel 3
Unused for now.

Binary file not shown.

View File

@@ -1,5 +1,7 @@
package net.torvald.terrarumsansbitmap package net.torvald.terrarumsansbitmap
import net.torvald.terrarumsansbitmap.gdx.CodePoint
/** /**
* Created by minjaesong on 2021-11-25. * Created by minjaesong on 2021-11-25.
*/ */
@@ -29,6 +31,8 @@ data class GlyphProps(
val isKernYtype: Boolean = false, val isKernYtype: Boolean = false,
val kerningMask: Int = 255, val kerningMask: Int = 255,
val dotRemoval: CodePoint? = null,
val directiveOpcode: Int = 0, // 8-bits wide val directiveOpcode: Int = 0, // 8-bits wide
val directiveArg1: Int = 0, // 8-bits wide val directiveArg1: Int = 0, // 8-bits wide
val directiveArg2: Int = 0, // 8-bits wide val directiveArg2: Int = 0, // 8-bits wide

View File

@@ -921,9 +921,9 @@ class TerrarumSansBitmap(
val isLowHeight = (pixmap.getPixel(codeStartX, codeStartY + 5).and(255) != 0) val isLowHeight = (pixmap.getPixel(codeStartX, codeStartY + 5).and(255) != 0)
// Keming machine parameters // Keming machine parameters
val kerningBit1 = pixmap.getPixel(codeStartX, codeStartY + 6).tagify() val kerningBit1 = pixmap.getPixel(codeStartX, codeStartY + 6).tagify() // glyph shape
val kerningBit2 = pixmap.getPixel(codeStartX, codeStartY + 7).tagify() val kerningBit2 = pixmap.getPixel(codeStartX, codeStartY + 7).tagify() // dot removal
val kerningBit3 = pixmap.getPixel(codeStartX, codeStartY + 8).tagify() val kerningBit3 = pixmap.getPixel(codeStartX, codeStartY + 8).tagify() // unused
var isKernYtype = ((kerningBit1 and 0x80000000.toInt()) != 0) var isKernYtype = ((kerningBit1 and 0x80000000.toInt()) != 0)
var kerningMask = kerningBit1.ushr(8).and(0xFFFFFF) var kerningMask = kerningBit1.ushr(8).and(0xFFFFFF)
val hasKernData = kerningBit1 and 255 != 0//(kerningBit1 and 255 != 0 && kerningMask != 0xFFFF) val hasKernData = kerningBit1 and 255 != 0//(kerningBit1 and 255 != 0 && kerningMask != 0xFFFF)
@@ -971,7 +971,9 @@ class TerrarumSansBitmap(
GlyphProps.STACK_DONT GlyphProps.STACK_DONT
else (0..1).fold(0) { acc, y -> acc or ((pixmap.getPixel(codeStartX, codeStartY + y + 18).and(255) != 0).toInt() shl y) } else (0..1).fold(0) { acc, y -> acc or ((pixmap.getPixel(codeStartX, codeStartY + y + 18).and(255) != 0).toInt() shl y) }
glyphProps[code] = GlyphProps(width, isLowHeight, nudgeX, nudgeY, diacriticsAnchors, alignWhere, writeOnTop, stackWhere, IntArray(15), hasKernData, isKernYtype, kerningMask, directiveOpcode, directiveArg1, directiveArg2) val dotRemoval = if (kerningBit2 == 0) null else kerningBit2.ushr(8)
glyphProps[code] = GlyphProps(width, isLowHeight, nudgeX, nudgeY, diacriticsAnchors, alignWhere, writeOnTop, stackWhere, IntArray(15), hasKernData, isKernYtype, kerningMask, dotRemoval, directiveOpcode, directiveArg1, directiveArg2)
// extra info // extra info
val extCount = glyphProps[code]?.requiredExtInfoCount() ?: 0 val extCount = glyphProps[code]?.requiredExtInfoCount() ?: 0
@@ -1533,8 +1535,8 @@ class TerrarumSansBitmap(
} }
// for lowercase i and j, if cNext is a diacritic that goes on top, remove the dots // for lowercase i and j, if cNext is a diacritic that goes on top, remove the dots
else if (diacriticDotRemoval.containsKey(c) && (glyphProps[cNext]?.writeOnTop ?: -1) >= 0 && glyphProps[cNext]?.stackWhere == GlyphProps.STACK_UP) { else if (glyphProps[c]!!.dotRemoval != null && (glyphProps[cNext]?.writeOnTop ?: -1) >= 0 && glyphProps[cNext]?.stackWhere == GlyphProps.STACK_UP) {
seq.add(diacriticDotRemoval[c]!!) seq.add(glyphProps[c]!!.dotRemoval!!)
} }
// BEGIN of tamil subsystem implementation // BEGIN of tamil subsystem implementation
@@ -2747,11 +2749,6 @@ class TerrarumSansBitmap(
0x20..0x7F, 0x20..0x7F,
) )
private val diacriticDotRemoval = hashMapOf(
'i'.toInt() to 0x131,
'j'.toInt() to 0x237
)
internal fun Int.charInfo() = "U+${this.toString(16).padStart(4, '0').toUpperCase()}: ${Character.getName(this)}" internal fun Int.charInfo() = "U+${this.toString(16).padStart(4, '0').toUpperCase()}: ${Character.getName(this)}"
const val NQSP = 0x2000 const val NQSP = 0x2000

Binary file not shown.