From 9675c40216ddcd53ad86d2006486b1ed5a1ac29e Mon Sep 17 00:00:00 2001 From: minjaesong Date: Tue, 18 Jan 2022 17:56:15 +0900 Subject: [PATCH] devanagari ligation wip --- assets/devanagari_variable.tga | 4 +- .../gdx/TerrarumSansBitmap.kt | 400 +++++++++++++----- testing.PNG | Bin 14386 -> 16556 bytes testtext.txt | 18 +- work_files/devanagari_variable.psd | 4 +- 5 files changed, 291 insertions(+), 135 deletions(-) diff --git a/assets/devanagari_variable.tga b/assets/devanagari_variable.tga index 54f31a2..953b8c0 100644 --- a/assets/devanagari_variable.tga +++ b/assets/devanagari_variable.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d3598b11c71ec8cf488c7babcfa103178b7291643937b933d20667c1038e4210 -size 327698 +oid sha256:709d4bc0804e7267f83a3ecec4c8e0a61879f8a8532c51713f55ae17e8c35799 +size 409618 diff --git a/src/net/torvald/terrarumsansbitmap/gdx/TerrarumSansBitmap.kt b/src/net/torvald/terrarumsansbitmap/gdx/TerrarumSansBitmap.kt index 6b5f810..624a04c 100755 --- a/src/net/torvald/terrarumsansbitmap/gdx/TerrarumSansBitmap.kt +++ b/src/net/torvald/terrarumsansbitmap/gdx/TerrarumSansBitmap.kt @@ -97,19 +97,19 @@ internal typealias Hash = Long * Created by minjaesong on 2017-06-15. */ class TerrarumSansBitmap( - fontDir: String, - val noShadow: Boolean = false, - val flipY: Boolean = false, - val invertShadow: Boolean = false, - var errorOnUnknownChar: Boolean = false, - val textCacheSize: Int = 256, - val debug: Boolean = false, - val shadowAlpha: Float = 0.5f, - val shadowAlphaPremultiply: Boolean = false + fontDir: String, + val noShadow: Boolean = false, + val flipY: Boolean = false, + val invertShadow: Boolean = false, + var errorOnUnknownChar: Boolean = false, + val textCacheSize: Int = 256, + val debug: Boolean = false, + val shadowAlpha: Float = 0.5f, + val shadowAlphaPremultiply: Boolean = false ) : BitmapFont() { private fun dbgprn(i: Any) { if (debug) println("[${this.javaClass.simpleName}] $i") } - + constructor(fontDir: String, noShadow: Boolean, flipY: Boolean, invertShadow: Boolean) : this(fontDir, noShadow, flipY, invertShadow, false, 256, false) /* This font is a collection of various subsystems, and thus contains copious amount of quick-and-dirty codes. @@ -158,9 +158,9 @@ class TerrarumSansBitmap( val b = codePoint.and(0x000F) val col = r.shl(28) or r.shl(24) or - g.shl(20) or g.shl(16) or - b.shl(12) or b.shl(8) or - 0xFF + g.shl(20) or g.shl(16) or + b.shl(12) or b.shl(8) or + 0xFF colourBuffer[codePoint] = col @@ -385,8 +385,8 @@ class TerrarumSansBitmap( val c = textBuffer[index] val sheetID = getSheetType(c) val (sheetX, sheetY) = - if (index == 0) getSheetwisePosition(0, c) - else getSheetwisePosition(textBuffer[index - 1], c) + if (index == 0) getSheetwisePosition(0, c) + else getSheetwisePosition(textBuffer[index - 1], c) val hash = getHash(c) // to be used with Bad Transmission Modifier if (isColourCode(c)) { @@ -480,10 +480,10 @@ class TerrarumSansBitmap( } batch.draw(tempLinotype, - x.toFloat(), - (y - pixmapOffsetY).toFloat() + (if (flipY) (tempLinotype.height) else 0) * scale, - tempLinotype.width.toFloat() * scale, - (tempLinotype.height.toFloat()) * (if (flipY) -1 else 1) * scale + x.toFloat(), + (y - pixmapOffsetY).toFloat() + (if (flipY) (tempLinotype.height) else 0) * scale, + tempLinotype.width.toFloat() * scale, + (tempLinotype.height.toFloat()) * (if (flipY) -1 else 1) * scale ) } @@ -852,9 +852,9 @@ class TerrarumSansBitmap( val nextHangulJungseong1 = toHangulJungseongIndex(str.getOrNull(charIndex + 2) ?: 0) ?: -1 val nextHangulJungseong2 = toHangulJungseongIndex(str.getOrNull(charIndex + 3) ?: 0) ?: -1 if (isHangulJungseong(thisChar) && thisHangulJungseongIndex in hangulPeaksWithExtraWidth && ( - nextHangulJungseong1 !in jungseongWide || - nextHangulJungseong2 !in jungseongWide - )) { + nextHangulJungseong1 !in jungseongWide || + nextHangulJungseong2 !in jungseongWide + )) { //dbgprn("char: ${thisChar.charInfo()}\nproperties: $thisProp") //dbgprn("${thisChar.charInfo()} ${str.getOrNull(charIndex + 2)?.charInfo()} ${str.getOrNull(charIndex + 3)?.charInfo()}") extraWidth += 1 @@ -869,11 +869,11 @@ class TerrarumSansBitmap( posXbuffer[charIndex] = -thisProp.nudgeX + when (itsProp.alignWhere) { GlyphProps.ALIGN_RIGHT -> - posXbuffer[nonDiacriticCounter] + W_VAR_INIT + alignmentOffset + interchar + kerning + extraWidth - GlyphProps.ALIGN_CENTRE -> - posXbuffer[nonDiacriticCounter] + HALF_VAR_INIT + itsProp.width + alignmentOffset + interchar + kerning + extraWidth - else -> - posXbuffer[nonDiacriticCounter] + itsProp.width + alignmentOffset + interchar + kerning + extraWidth + posXbuffer[nonDiacriticCounter] + W_VAR_INIT + alignmentOffset + interchar + kerning + extraWidth + GlyphProps.ALIGN_CENTRE -> + posXbuffer[nonDiacriticCounter] + HALF_VAR_INIT + itsProp.width + alignmentOffset + interchar + kerning + extraWidth + else -> + posXbuffer[nonDiacriticCounter] + itsProp.width + alignmentOffset + interchar + kerning + extraWidth } nonDiacriticCounter = charIndex @@ -921,48 +921,48 @@ class TerrarumSansBitmap( // set Y pos according to diacritics position // if (thisProp.alignWhere == GlyphProps.ALIGN_CENTRE) { - when (thisProp.stackWhere) { - GlyphProps.STACK_DOWN -> { - posYbuffer[charIndex] = H_DIACRITICS * stackDownwardCounter * flipY.toSign() - stackDownwardCounter++ + when (thisProp.stackWhere) { + GlyphProps.STACK_DOWN -> { + posYbuffer[charIndex] = H_DIACRITICS * stackDownwardCounter * flipY.toSign() + stackDownwardCounter++ + } + GlyphProps.STACK_UP -> { + posYbuffer[charIndex] = -H_DIACRITICS * stackUpwardCounter * flipY.toSign() + // shift down on lowercase if applicable + if (getSheetType(thisChar) in autoShiftDownOnLowercase && + lastNonDiacriticChar.isLowHeight()) { + //dbgprn("AAARRRRHHHH for character ${thisChar.toHex()}") + //dbgprn("lastNonDiacriticChar: ${lastNonDiacriticChar.toHex()}") + //dbgprn("cond: ${thisProp.alignXPos == GlyphProps.DIA_OVERLAY}, charIndex: $charIndex") + if (diacriticsType == GlyphProps.DIA_OVERLAY) + posYbuffer[charIndex] += H_OVERLAY_LOWERCASE_SHIFTDOWN * flipY.toSign() // if minus-assign doesn't work, try plus-assign + else + posYbuffer[charIndex] += H_STACKUP_LOWERCASE_SHIFTDOWN * flipY.toSign() // if minus-assign doesn't work, try plus-assign } - GlyphProps.STACK_UP -> { - posYbuffer[charIndex] = -H_DIACRITICS * stackUpwardCounter * flipY.toSign() - // shift down on lowercase if applicable - if (getSheetType(thisChar) in autoShiftDownOnLowercase && - lastNonDiacriticChar.isLowHeight()) { - //dbgprn("AAARRRRHHHH for character ${thisChar.toHex()}") - //dbgprn("lastNonDiacriticChar: ${lastNonDiacriticChar.toHex()}") - //dbgprn("cond: ${thisProp.alignXPos == GlyphProps.DIA_OVERLAY}, charIndex: $charIndex") - if (diacriticsType == GlyphProps.DIA_OVERLAY) - posYbuffer[charIndex] += H_OVERLAY_LOWERCASE_SHIFTDOWN * flipY.toSign() // if minus-assign doesn't work, try plus-assign - else - posYbuffer[charIndex] += H_STACKUP_LOWERCASE_SHIFTDOWN * flipY.toSign() // if minus-assign doesn't work, try plus-assign - } - stackUpwardCounter++ + stackUpwardCounter++ // dbgprn("lastNonDiacriticChar: ${lastNonDiacriticChar.charInfo()}; stack counter: $stackUpwardCounter") - } - GlyphProps.STACK_UP_N_DOWN -> { - posYbuffer[charIndex] = H_DIACRITICS * stackDownwardCounter * flipY.toSign() - stackDownwardCounter++ - - - posYbuffer[charIndex] = -H_DIACRITICS * stackUpwardCounter * flipY.toSign() - // shift down on lowercase if applicable - if (getSheetType(thisChar) in autoShiftDownOnLowercase && - lastNonDiacriticChar.isLowHeight()) { - if (diacriticsType == GlyphProps.DIA_OVERLAY) - posYbuffer[charIndex] += H_OVERLAY_LOWERCASE_SHIFTDOWN * flipY.toSign() // if minus-assign doesn't work, try plus-assign - else - posYbuffer[charIndex] += H_STACKUP_LOWERCASE_SHIFTDOWN * flipY.toSign() // if minus-assign doesn't work, try plus-assign - } - - stackUpwardCounter++ - } - // for BEFORE_N_AFTER, do nothing in here } + GlyphProps.STACK_UP_N_DOWN -> { + posYbuffer[charIndex] = H_DIACRITICS * stackDownwardCounter * flipY.toSign() + stackDownwardCounter++ + + + posYbuffer[charIndex] = -H_DIACRITICS * stackUpwardCounter * flipY.toSign() + // shift down on lowercase if applicable + if (getSheetType(thisChar) in autoShiftDownOnLowercase && + lastNonDiacriticChar.isLowHeight()) { + if (diacriticsType == GlyphProps.DIA_OVERLAY) + posYbuffer[charIndex] += H_OVERLAY_LOWERCASE_SHIFTDOWN * flipY.toSign() // if minus-assign doesn't work, try plus-assign + else + posYbuffer[charIndex] += H_STACKUP_LOWERCASE_SHIFTDOWN * flipY.toSign() // if minus-assign doesn't work, try plus-assign + } + + stackUpwardCounter++ + } + // for BEFORE_N_AFTER, do nothing in here + } // } } } @@ -972,8 +972,8 @@ class TerrarumSansBitmap( if (str.isNotEmpty()) { val lastCharProp = glyphProps[str.last()] val penultCharProp = glyphProps[str[nonDiacriticCounter]] ?: - (if (errorOnUnknownChar) throw throw InternalError("No GlyphProps for char '${str[nonDiacriticCounter]}' " + - "(${str[nonDiacriticCounter].charInfo()})") else nullProp) + (if (errorOnUnknownChar) throw throw InternalError("No GlyphProps for char '${str[nonDiacriticCounter]}' " + + "(${str[nonDiacriticCounter].charInfo()})") else nullProp) posXbuffer[posXbuffer.lastIndex] = 1 + posXbuffer[posXbuffer.lastIndex - 1] + // adding 1 to house the shadow if (lastCharProp != null && lastCharProp.writeOnTop >= 0) { val realDiacriticWidth = if (lastCharProp.alignWhere == GlyphProps.ALIGN_CENTRE) { @@ -1035,17 +1035,30 @@ class TerrarumSansBitmap( // basically an Unicode NFD with some additional flavours private fun CodepointSequence.normalise(): CodepointSequence { - val dis = this.utf16to32() val seq = CodepointSequence() val seq2 = CodepointSequence() val yankedCharacters = Stack>() // Stack of ; codepoint use -1 if not applicable + fun emptyOutYanked() { + while (!yankedCharacters.empty()) { + val poppedChar = yankedCharacters.pop() + if (poppedChar.second == DEVANAGARI_RA) + seq.add(DEVANAGARI_RA_SUPER) + else + seq.add(yankedCharacters.pop().second) + } + } + var i = 0 + this.utf16to32().let { dis -> while (i < dis.size) { - val c = dis[i] + val cPrev2 = dis.getOrElse(i-2) { -1 } val cPrev = dis.getOrElse(i-1) { -1 } + val c = dis[i] val cNext = dis.getOrElse(i+1) { -1 } + val cNext2 = dis.getOrElse(i+2) { -1 } + // can't use regular sliding window as the 'i' value is changed way too often // LET THE NORMALISATION BEGIN // @@ -1137,13 +1150,28 @@ class TerrarumSansBitmap( // END of tamil subsystem implementation // BEGIN of devanagari string replacer - else if (c == DEVANAGARI_VIRAMA) { - yankedCharacters.push(i-1 to cPrev) + // Unicode Devanagari Rendering Rule R6-R8 + // (this must precede the ligaturing-machine coded on the 2nd pass, otherwise the rules below will cause undesirable effects) + else if (devanagariConsonants.contains(c) && cNext == DEVANAGARI_VIRAMA && cNext2 == DEVANAGARI_RA) { + seq.addAll(toRaAppended(c)) + i += 2 } - else if (c == DEVANAGARI_RA) { + // Unicode Devanagari Rendering Rule R5 + else if (c == DEVANAGARI_RRA && cNext == DEVANAGARI_VIRAMA || c == DEVANAGARI_RA && cNext == DEVANAGARI_VIRAMA && cNext2 == ZWJ) { + seq.add(DEVANAGARI_EYELASH_RA) + i += 1 + } + // Unicode Devanagari Rendering Rule R2-R4 + else if (c == DEVANAGARI_RA && cNext == DEVANAGARI_VIRAMA && cNext2 != DEVANAGARI_RA) { yankedCharacters.push(i to c) + i += 1 } - // WIP + // Unicode Devanagari Rendering Rule R2-R4 + else if (!isDevanagari(c) && !yankedCharacters.empty()) { + emptyOutYanked() + seq.add(c) + } + // WIP // END of devanagari string replacer // rearrange {letter, before-and-after diacritics} as {before-diacritics, letter, after-diacritics} @@ -1164,7 +1192,11 @@ class TerrarumSansBitmap( i++ } + emptyOutYanked() + } + + // second scan // swap position of {letter, diacritics that comes before the letter} i = 1 while (i <= seq.lastIndex) { @@ -1175,6 +1207,27 @@ class TerrarumSansBitmap( seq[i] = t } + val cPrev2 = seq.getOrElse(i-2) { -1 } + val cPrev = seq.getOrElse(i-1) { -1 } + val c = seq[i] + + // BEGIN of Devanagari String Replacer 2 (lookbehind type) + // Devanagari Ligations (Lookbehind) + if (devanagariConsonants.contains(cPrev2) && cPrev == DEVANAGARI_VIRAMA && devanagariConsonants.contains(c)) { + i -= 2 + + repeat(3) { seq.removeAt(i) } + + val ligature = ligateIndicConsonants(cPrev2, c) + ligature.forEachIndexed { index, char -> + seq.add(i + index, char) + } + + i += ligature.size + } + // END of Devanagari String Replacer 2 + + i++ } @@ -1238,8 +1291,8 @@ class TerrarumSansBitmap( opCue.forEach { if (pixmap.getPixel(it.first, it.second) and 0xFF == 0) { pixmap.drawPixel(it.first, it.second, - // the shadow has the same colour, but alpha halved - pxNow.and(0xFFFFFF00.toInt()).or(0x7F) + // the shadow has the same colour, but alpha halved + pxNow.and(0xFFFFFF00.toInt()).or(0x7F) ) } } @@ -1277,13 +1330,13 @@ class TerrarumSansBitmap( // for now, no semitransparency (in colourcode && spritesheet) val jobQueue = if (!invertShadow) arrayOf( - 1 to 0, - 0 to 1, - 1 to 1 + 1 to 0, + 0 to 1, + 1 to 1 ) else arrayOf( - -1 to 0, - 0 to -1, - -1 to -1 + -1 to 0, + 0 to -1, + -1 to -1 ) jobQueue.forEach { @@ -1328,10 +1381,10 @@ class TerrarumSansBitmap( } private fun Color.toRGBA8888() = - (this.r * 255f).toInt().shl(24) or - (this.g * 255f).toInt().shl(16) or - (this.b * 255f).toInt().shl(8) or - (this.a * 255f).toInt() + (this.r * 255f).toInt().shl(24) or + (this.g * 255f).toInt().shl(16) or + (this.b * 255f).toInt().shl(8) or + (this.a * 255f).toInt() /** * RGBA8888 representation @@ -1343,9 +1396,9 @@ class TerrarumSansBitmap( val otherBytes = IntArray(4) { other.ushr(it * 8).and(255) } return (thisBytes[0] times256 otherBytes[0]) or - (thisBytes[1] times256 otherBytes[1]).shl(8) or - (thisBytes[2] times256 otherBytes[2]).shl(16) or - (thisBytes[3] times256 otherBytes[3]).shl(24) + (thisBytes[1] times256 otherBytes[1]).shl(8) or + (thisBytes[2] times256 otherBytes[2]).shl(16) or + (thisBytes[3] times256 otherBytes[3]).shl(24) } private infix fun Int.times256(other: Int) = multTable255[this][other] @@ -1548,7 +1601,7 @@ class TerrarumSansBitmap( private val autoShiftDownOnLowercase = arrayOf( - SHEET_DIACRITICAL_MARKS_VARW + SHEET_DIACRITICAL_MARKS_VARW ) private val fileList = arrayOf( // MUST BE MATCHING WITH SHEET INDICES!! @@ -1630,13 +1683,130 @@ class TerrarumSansBitmap( 'j'.toInt() to 0x237 ) - private val tamilLigatingConsonants = listOf('க','ங','ச','ஞ','ட','ண','த','ந','ன','ப','ம','ய','ர','ற','ல','ள','ழ','வ').map { it.toInt() }.toIntArray() + private val ZWJ = 0x200D + private val tamilLigatingConsonants = listOf('க','ங','ச','ஞ','ட','ண','த','ந','ன','ப','ம','ய','ர','ற','ல','ள','ழ','வ').map { it.toInt() }.toIntArray() private val TAMIL_KSSA = 0xF00ED private val TAMIL_SHRII = 0xF00EE + private val devanagariConsonants = ((0x0915..0x0939) + (0x0958..0x095F) + (0x0978..0x097F) + (0xF0140..0xF01FF)).toIntArray() + + private val devanagariBaseConsonants = 0x0915..0x0939 + private val devanagariBaseConsonantsWithNukta = 0x0958..0x095F + private val devanagariBaseConsonantsExtended = 0x0978..0x097F + private val devanagariPresentationFormsConsonants = 0xF0140..0xF01FF + private val DEVANAGARI_VIRAMA = 0x94D private val DEVANAGARI_RA = 0x930 + private val DEVANAGARI_RRA = 0x931 + private val DEVANAGARI_RA_SUPER = 0xF0104 + private val DEVANAGARI_EYELASH_RA = 0xF012A + + private val DEVANAGARI_LIG_K_SS = 0xF0181 + private val DEVANAGARI_LIG_J_NY = 0xF0184 + private val DEVANAGARI_LIG_T_T = 0xF018B + private val DEVANAGARI_LIG_T_R = 0xF0154 + private val DEVANAGARI_LIG_SH_R = 0xF0166 + private val DEVANAGARI_HALFLIG_K_SS = 0xF012B + private val DEVANAGARI_HALFLIG_J_NY = 0xF012C + private val DEVANAGARI_HALFLIG_T_T = 0xF012D + private val DEVANAGARI_HALFLIG_T_R = 0xF012E + private val DEVANAGARI_HALFLIG_SH_R = 0xF012F + + private val DEVANAGARI_SYLL_RU = 0xF0100 + private val DEVANAGARI_SYLL_RUU = 0xF0101 + + private val DEVANAGARI_HALF_FORMS = 0xF0100 // starting point for Devanagari half forms + private val DEVANAGARI_LIG_X_R = 0xF0140 // starting point for Devanagari ligature CONSONANT+RA + + private fun CodePoint.toHalfFormOrNull(): CodePoint? { + if (this in devanagariBaseConsonants) return (this - 0x0910 + DEVANAGARI_HALF_FORMS) + if (this in devanagariBaseConsonantsWithNukta) return (this - 0x0920 + DEVANAGARI_HALF_FORMS) + else if (this == DEVANAGARI_LIG_K_SS) return DEVANAGARI_HALFLIG_K_SS + else if (this == DEVANAGARI_LIG_J_NY) return DEVANAGARI_HALFLIG_J_NY + else if (this == DEVANAGARI_LIG_T_T) return DEVANAGARI_HALFLIG_T_T + else if (this == DEVANAGARI_LIG_T_R) return DEVANAGARI_HALFLIG_T_R + else if (this == DEVANAGARI_LIG_SH_R) return DEVANAGARI_HALFLIG_SH_R + // TODO half forms of X_R-ligatures + else return null + } + + // TODO use proper version of Virama for respective scripts + private fun CodePoint.toHalfFormOrVirama(): List = this.toHalfFormOrNull().let { + if (it == null) listOf(this, DEVANAGARI_VIRAMA) else listOf(it) + } + + // TODO use proper version of Virama for respective scripts + private fun toRaAppended(c: CodePoint): List { + if (c in devanagariBaseConsonants) return listOf(c - 0x0910 + DEVANAGARI_LIG_X_R) + else return listOf(c, DEVANAGARI_VIRAMA, DEVANAGARI_RA) + } + + private fun ligateIndicConsonants(c1: CodePoint, c2: CodePoint): List { + if (c2 == DEVANAGARI_RA) return toRaAppended(c1) // Devanagari @.RA + when (c1) { + 0x0915 -> /* Devanagari KA */ when (c2) { + 0x0924 -> return listOf(0xF0180) // K.TA + 0x0937 -> return listOf(DEVANAGARI_LIG_K_SS) // K.SSA + else -> return c1.toHalfFormOrVirama() + c2 + } + 0x0919 -> /* Devanagari NGA */ when (c2) { + 0x0917 -> return listOf(0xF0182) // NG.G + 0x092E -> return listOf(0xF0183) // NG.M + else -> return c1.toHalfFormOrVirama() + c2 + } + 0x091C -> /* Devanagari JA */ when (c2) { + 0x091E -> return listOf(DEVANAGARI_LIG_J_NY) // J.NY + else -> return c1.toHalfFormOrVirama() + c2 + } + 0x091F -> /* Devanagari TTA */ when (c2) { + 0x091F -> return listOf(0xF0185) // TT.TT + 0x0920 -> return listOf(0xF0186) // TT.TTH + else -> return c1.toHalfFormOrVirama() + c2 + } + 0x0920 -> /* Devanagari TTHA */ when (c2) { + 0x0920 -> return listOf(0xF0187) // TTH.TTH + else -> return c1.toHalfFormOrVirama() + c2 + } + 0x0921 -> /* Devanagari DDA */ when (c2) { + 0x0921 -> return listOf(0xF0188) // DD.DD + 0x0922 -> return listOf(0xF0189) // DD.DDH + else -> return c1.toHalfFormOrVirama() + c2 + } + 0x0922 -> /* Devanagari DDHA */ when (c2) { + 0x0922 -> return listOf(0xF018A) // DDH.DDH + else -> return c1.toHalfFormOrVirama() + c2 + } + 0x0924 -> /* Devanagari TA */ when (c2) { + 0x0924 -> return listOf(DEVANAGARI_LIG_T_T) // T.T + else -> return c1.toHalfFormOrVirama() + c2 + } + 0x0926 -> /* Devanagari DA */ when (c2) { + 0x0926 -> return listOf(0xF018C) // D.D + 0x0927 -> return listOf(0xF018D) // D.DH + 0x092C -> return listOf(0xF018E) // D.B + 0x092D -> return listOf(0xF018F) // D.BH + 0x092E -> return listOf(0xF0190) // D.M + 0x092F -> return listOf(0xF0191) // D.Y + 0x0935 -> return listOf(0xF0192) // D.V + else -> return c1.toHalfFormOrVirama() + c2 + } + 0x0928 -> /* Devanagari NA */ when (c2) { + 0x0928 -> return listOf(0xF0193) // N.N + else -> return c1.toHalfFormOrVirama() + c2 + } + 0x0939 -> /* Devanagari HA */ when (c2) { + 0x0923 -> return listOf(0xF0194) // H.NN + 0x0928 -> return listOf(0xF0195) // H.N + 0x092E -> return listOf(0xF0196) // H.M + 0x092F -> return listOf(0xF0197) // H.Y + 0x0932 -> return listOf(0xF0198) // H.L + 0x0935 -> return listOf(0xF0199) // H.v + else -> return c1.toHalfFormOrVirama() + c2 + } + else -> return c1.toHalfFormOrVirama() + c2 // TODO use proper version of Virama for respective scripts + } + } private fun Int.toHex() = "U+${this.toString(16).padStart(4, '0').toUpperCase()}" @@ -1689,13 +1859,13 @@ class TerrarumSansBitmap( */ private fun getHanInitialRow(i: Int, p: Int, f: Int): Int { var ret = - if (p in jungseongI) 3 - else if (p in jungseongOUComplex) 7 - else if (p in jungseongOEWI) 11 - else if (p in jungseongOU) 5 - else if (p in jungseongEU) 9 - else if (p in jungseongYI) 13 - else 1 + if (p in jungseongI) 3 + else if (p in jungseongOUComplex) 7 + else if (p in jungseongOEWI) 11 + else if (p in jungseongOU) 5 + else if (p in jungseongEU) 9 + else if (p in jungseongYI) 13 + else 1 if (f != 0) ret += 1 @@ -1717,17 +1887,17 @@ class TerrarumSansBitmap( private fun isHangulJongseong(c: CodePoint) = c in (0x11A8..0x11FF) || c in (0xD7CB..0xD7FB) private fun toHangulChoseongIndex(c: CodePoint) = - if (!isHangulChoseong(c)) throw IllegalArgumentException("This Hangul sequence does not begin with Choseong (${c.toHex()})") - else if (c in 0x1100..0x115F) c - 0x1100 - else c - 0xA960 + 96 + if (!isHangulChoseong(c)) throw IllegalArgumentException("This Hangul sequence does not begin with Choseong (${c.toHex()})") + else if (c in 0x1100..0x115F) c - 0x1100 + else c - 0xA960 + 96 private fun toHangulJungseongIndex(c: CodePoint) = - if (!isHangulJungseong(c)) null - else if (c in 0x1160..0x11A7) c - 0x1160 - else c - 0xD7B0 + 72 + if (!isHangulJungseong(c)) null + else if (c in 0x1160..0x11A7) c - 0x1160 + else c - 0xD7B0 + 72 private fun toHangulJongseongIndex(c: CodePoint) = - if (!isHangulJongseong(c)) null - else if (c in 0x11A8..0x11FF) c - 0x11A8 + 1 - else c - 0xD7CB + 88 + 1 + if (!isHangulJongseong(c)) null + else if (c in 0x11A8..0x11FF) c - 0x11A8 + 1 + else c - 0xD7CB + 88 + 1 /** * X-position in the spritesheet @@ -1821,9 +1991,9 @@ class TerrarumSansBitmap( private fun kanaIndexX(c: CodePoint) = c % 16 private fun kanaIndexY(c: CodePoint) = - if (c in 0x31F0..0x31FF) 12 - else if (c in 0x1B000..0x1B00F) 13 - else (c - 0x3040) / 16 + if (c in 0x31F0..0x31FF) 12 + else if (c in 0x1B000..0x1B00F) 13 + else (c - 0x3040) / 16 private fun cjkPunctIndexX(c: CodePoint) = c % 16 private fun cjkPunctIndexY(c: CodePoint) = (c - 0x3000) / 16 @@ -1902,7 +2072,7 @@ class TerrarumSansBitmap( private fun tamilIndexX(c: CodePoint) = c % 16 private fun tamilIndexY(c: CodePoint) = (if (c < 0xF0000) (c - 0x0B80) else (c - 0xF0040)) / 16 - + val charsetOverrideDefault = Character.toChars(CHARSET_OVERRIDE_DEFAULT).toSurrogatedString() val charsetOverrideBulgarian = Character.toChars(CHARSET_OVERRIDE_BG_BG).toSurrogatedString() val charsetOverrideSerbian = Character.toChars(CHARSET_OVERRIDE_SR_SR).toSurrogatedString() @@ -1960,12 +2130,12 @@ class TerrarumSansBitmap( * J·K */ private val kerningRules = arrayListOf( - Kem(ing("_`_@___`__"),ing("`_`___@___")), // ул - Kem(ing("_@_`___`__"),ing("`_________")), - Kem(ing("_@_@___`__"),ing("`___@_@___"),1,1), - Kem(ing("_@_@_`_`__"),ing("`_____@___")), - Kem(ing("___`_`____"),ing("`___@_`___")), - Kem(ing("___`_`____"),ing("`_@___`___")), + Kem(ing("_`_@___`__"),ing("`_`___@___")), // ул + Kem(ing("_@_`___`__"),ing("`_________")), + Kem(ing("_@_@___`__"),ing("`___@_@___"),1,1), + Kem(ing("_@_@_`_`__"),ing("`_____@___")), + Kem(ing("___`_`____"),ing("`___@_`___")), + Kem(ing("___`_`____"),ing("`_@___`___")), ) init { diff --git a/testing.PNG b/testing.PNG index 185a67ccb94d18e3ef00f5e37284cef572fa3d67..97d30fab0deb911fe56ce9a379061b4761db99a6 100755 GIT binary patch delta 2591 zcmXw5eOQu*7JsevdFSjdo27}{b@#fBYt0#@iO|gSwpG?zV}?T7hfBgQL`1~5^)Xjh zWj&_OFId->HU(0LUPHvvM2AYGLB1+v1gHqFiGsw}>^{%^=RD`1^E7&D%cxyi^ZAf0Xy z1_9RXFk{_LNdV|jr;D8ysb7Uzu{2t;2G$4wU_Mgx;V9+^f`dL^(^u_s82Dn>f*lr% zjkgzT4e`|sI9F_lcFlEO(sV-BN98je%-8BG^^&)MkLU**m^J9b9wAQKwbHxii&&-d zhX-d;_$dX+7>-@zR_Z_^yB{oXHFuF})d!6B?-~Wqu9rk!NWf~auE*RMw z;I1ZqZ@T~!WR9?sn%iQ-hnBg{BW*Ie)sQiYjA}vD0{~4l7nv$WM$jZxg=(RQ6e-O!29h&5Sn~erQS%F@03z&{3*uw2K`7-f~?2v zkk#PLhj3q?qd3X-4jmfMLFs(BlI+fX*S5@@i6)n zorscPLX6ZC{P+5lmpAt5zgTZ(qHxmx(l#+E|SBtwcgw>~heb+Lr zsRN1CDQDEE5%M`RXO>7$91I}(nfu2y8MID;IKrNg$Q+hk0QLW!h`dwBzZ}XRz;&u( z6wJP97n~3X%rAjx3qlZtoqE-pe!PnBtQV)%L3xg0rEQo#T+&W$e2K)|OC}8pP}p#5 zSu?wUr#fr2InP_F&_Z}bZRY2SYW-8lhXdqcMD=8NjBX83aENsUTKJ|1nLf)Ax1XU` zYqPT!H~3_g5I>c}-|_N5kd zrr5mUg0#6JNXOqTP7ZYs*cM*RG&f?G3Y6$N4cEzQ(`rVlILqB7HcF=@FCJtB7a=On zJ4EkyzPk#?GA^Jn#UZKmcR|!SMTs@Lh;L$?bA_JfU6r1YDxW}=jdGk%~<1os@`{-NoF{;YaXMzwJRF&>p-i)0BCFm3hUij5L zbW&|XHe7tmwl9x9Kx_^zX8$m4ST{C8@>>AaLd(U0O6 z)9Nx2Sg0fYj8I3U;lTCt*Z;K!=wgqwW729Js%@tcbm^wf2;Ggd&xhhRDG}n?N%Mq& zih9vgizMN3Nfo%=Jaz-j%;%c>;nYd(No6B7BkrLSBf+lzQnm`FI4m~ zpC(A@6)gWm^4Q)VQrL~!P8hvG%vh6WjEtu}OvUIF+(z1^EMLuccCA$o1vla~b4;&d zkhe60yaseDDSJm1m|v2HYB%4MVZz7uHc#X^W)F@E_1m_=AN|zzWs{NlxL=ML$>Zem zV#p$~ahRJ)<3UZ6ZD^s*aFeq=UV?~DRssuIg zd1ruJ8j%JJi?!;$9AsU3waen}CR2&U_K&Gv@2QjMH8~0?z zy&60K;N{zeP#F>748+@y76rW8S^#P_^MT;K4FCY6wx^QB3AC0aDUI{Y)M~L68Oy~D z%Xd*&=d;QV{)Ihz)um>vGhsE*jr1&pRApCZHV(+279z))3Jj-tGK(C?r7t$Kyk>un zI+K^5tqL74*^u7QJAo@pk4phW(#z6Tk6T z&y7};W!e!4dI11&=e?^w z(C@7RNuH!}GIuoqTt9LZTDYBOqs5K~V{4MKg*Q+MWBO1fQ}NAP#WDSrAr+XeAI^Sg zOe~JDCw(viW>yz8FYQu}+4MviL@r?vGV?uv=O5Qck?CKF-Y%c%Wf-IFJ^9tzT*gX+ zDHBHOG&R{ZVyoiQ%95wYb`7zNge!+YcHczH78L#tKQr6TT{0F&VhK{`@F4j2l33PG z0O;(Qu{MwsDk}Z&dY}Bjq)r`Yd{F-jjMZ* zqrC#|+849`{7Z}YM#D+r6YB3>5zVddaZ_}}AGBpQev{wIGK|>`Lz+`C=-f{Vl9Q$c z)E1G?K`B%BASBNK9ed`Vxa}m~nnJu4&R{(6f6eQK7Merhzv4~cIae!b4RDeFBD;Yr ziZgyE6qQbEbKJggI@q4`M7-OAje=wUZ=mkD|%CC+uWI~Ph3EJe!}&$zWi)7)x~VDjWV zdc^>d)H?oEfsu_#TM_mb73#XS94REviEVGLr91w>;5qB*i_gkXHA|y*1wk;`*oQv7 zNZ-n2%Z699&(UVRIe~fKC{F-*Kjux|yS}w}eUW$T`|EO6t$KiM_48ll*P5}L>+!!( fnz38BdkKt*awdwiB757=6rrMvqwRuICkVa#iKGhv@H@Z_aH%5MlkdBUD{UXQ_MGn#Ex4 z=2rM%FQkrVs!qFh0Wcx|3(r1Dy}#|w`(7_bDAko&BvaL#xiLm)j7s4Epb|a^rBb>e zs%g8#pb_s56tX0FB$r?9_xdYY!u8O+; zFHQNQ{IVibIa3~n(Jyq`E+m8?^C&k@<3;TY{9jY^SZ$GgSx%28CNPNRj zm(C;oSHk~X8bh_Bl}!Fa?{$M`HK-gnB$=n} zjSEXZF0vRJOa&QzFK0}cf{z)!;VR#7Z6_1Clvo6lMx4tR04gJOX66X8$DJ&^Ka6ba z1qGgfZGX#=UvDq&u|ZkPHbzB~A;x~GF=mAan-)Q~VveS-9^h#=Jqjuw7}i4lp%`tZ z(d{8wmoe1}>_@cNxXWWL+iDCdT$sRUSFS@cISyQ=oiwGH!iLy~A1n8_PBJ7o)rwj( zh$9yhAvcMyL ieov)>%AI~8+rFyBMF$g8`?*Lf;7IDxl(wXt-~I=zxtAaS diff --git a/testtext.txt b/testtext.txt index fc3ea3c..5fcec6e 100755 --- a/testtext.txt +++ b/testtext.txt @@ -1,17 +1,3 @@ - A ดุ ตี ปู่ พี่ ป่ ม่ ปั มั พีุ ทิ่ท่ท่ิ ปิ่ป่ป่ิ ทิ้ ปิ้ มำด มําด - -이는 일본의 요미가나(読み仮名)와 비슷한 용법이다. - -Sugarさとう설탕砂糖 - -বাংলাদেশ - -தமிழ் லூ லு - -QWனோT -னோ - -எழுத்து வடிவங்களுக்கு வார்த்தைகள் மற்றும் வாக்கியங்கள் போலவே தொனி, ஒலி பண்பு, தன்மை உண்டு. - -க்ஷ ஶ்ரீ க்ஷௌ \ No newline at end of file +फ़ॊण्ज़ीणू क्की क्कि र्क र्त्सा र्र्ल ऱ्ड क्राप् ठ्री त्र् त्र्मोत्र्यो ज्ञज्ञ्रत्त न्न +ह्णह्नह्मह्यह्लह्वह्र णनमयलव ज़्लतान diff --git a/work_files/devanagari_variable.psd b/work_files/devanagari_variable.psd index 2099e32..2bd4d2f 100644 --- a/work_files/devanagari_variable.psd +++ b/work_files/devanagari_variable.psd @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c8784363133aa8b52b3759649e2c2590450e92bf8b06e941a82879eafebad7e0 -size 371114 +oid sha256:d224d6b0941ec2f947672d76b801033cb189851e848b936e352f453fd1fb1554 +size 446470