mirror of
https://github.com/curioustorvald/Terrarum-sans-bitmap.git
synced 2026-03-07 20:01:52 +09:00
fix: quirks with getting width of blocks and typesetting
This commit is contained in:
@@ -8,7 +8,12 @@ import net.torvald.terrarumsansbitmap.gdx.CodePoint
|
||||
import net.torvald.terrarumsansbitmap.gdx.CodepointSequence
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.FIXED_BLOCK_1
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.NBSP
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.OBJ
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.SHY
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.ZWSP
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.getHash
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.glueCharToGlueSize
|
||||
import kotlin.math.*
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
@@ -87,7 +92,7 @@ class MovableType(
|
||||
fun dequeue() = boxes.removeFirst()
|
||||
fun addHyphenatedTail(box: NoTexGlyphLayout) = boxes.add(0, box)
|
||||
fun addToSlug(box: NoTexGlyphLayout) {
|
||||
val nextPosX = (slug.lastOrNull()?.getEndPos() ?: 0)
|
||||
val nextPosX = slug.getSlugEndPos()
|
||||
slug.add(Block(nextPosX, box))
|
||||
slugWidth += box.width
|
||||
|
||||
@@ -140,6 +145,9 @@ class MovableType(
|
||||
|
||||
slug = ArrayList()
|
||||
slugWidth = 0
|
||||
|
||||
|
||||
// println("Frozen slug: ${frozen.toReadable()}")
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -153,7 +161,7 @@ class MovableType(
|
||||
slug.removeLastOrNull()
|
||||
}
|
||||
|
||||
var slugWidth = (slug.lastOrNull()?.getEndPos() ?: 0) - exdentSize
|
||||
var slugWidth = slug.getSlugEndPos() - exdentSize
|
||||
if (slug.isNotEmpty() && slug.last().block.penultimateCharOrNull != null && hangable.contains(slug.last().block.penultimateCharOrNull))
|
||||
slugWidth -= hangWidth
|
||||
else if (slug.isNotEmpty() && slug.last().block.penultimateCharOrNull != null && hangableFW.contains(slug.last().block.penultimateCharOrNull))
|
||||
@@ -174,7 +182,7 @@ class MovableType(
|
||||
}*/
|
||||
|
||||
// add the box to the slug copy
|
||||
val nextPosX = (slug.lastOrNull()?.getEndPos() ?: 0)
|
||||
val nextPosX = slug.getSlugEndPos()
|
||||
slug.add(Block(nextPosX, box))
|
||||
|
||||
var slugWidth = slugWidth + box.width - exdentSize
|
||||
@@ -198,7 +206,7 @@ class MovableType(
|
||||
// - the word is too short (5 chars or less)
|
||||
// - the word is pre-hyphenated (ends with hyphen-null)
|
||||
val glyphCount = box.text.count { it in 32..0xFFF6F && it !in 0xFFF0..0xFFFF }
|
||||
if (glyphCount <= (if (paperWidth < 350) 4 else if (paperWidth < 480) 5 else 6) || box.text.penultimate() == 0x2D)
|
||||
if (glyphCount <= (if (paperWidth < 350) 3 else if (paperWidth < 480) 4 else 5) || box.text.penultimate() == 0x2D)
|
||||
return Triple(Double.POSITIVE_INFINITY, 2147483647, null)
|
||||
|
||||
val slug = slug.toMutableList() // ends with a glue
|
||||
@@ -222,7 +230,7 @@ class MovableType(
|
||||
return Triple(Double.POSITIVE_INFINITY, 2147483647, null)
|
||||
|
||||
// add the hyphHead to the slug copy
|
||||
val nextPosX = (slug.lastOrNull()?.getEndPos() ?: 0)
|
||||
val nextPosX = slug.getSlugEndPos()
|
||||
slug.add(Block(nextPosX, hyphHead)) // now ends with 'word-' (but not in Hangul)
|
||||
val hasHyphen = hyphHead.penultimateCharOrNull == 0x2D
|
||||
|
||||
@@ -322,7 +330,7 @@ class MovableType(
|
||||
|
||||
if (badnessH.isInfinite() && badnessW.isInfinite() && badnessT.isInfinite()) {
|
||||
throw Error(
|
||||
"Typesetting failed: badness of all three strategies diverged to infinity\ntext (${slug.size} tokens): ${
|
||||
"Typesetting failed: badness of all three strategies diverged to infinity. Try adding white spaces to the text.\nThe text (${slug.size} tokens): ${
|
||||
slug.map { it.block.text }.filter { it.isNotGlue() }
|
||||
.joinToString(" ") { it.toReadable() }
|
||||
}"
|
||||
@@ -586,9 +594,9 @@ class MovableType(
|
||||
var cM: CodePoint? = null
|
||||
var glue = 0
|
||||
|
||||
fun getControlHeader(row: Int, word: Int): CodepointSequence {
|
||||
fun getControlHeader(row: Int, word: Int): List<Int> {
|
||||
val index = row * 65536 or word
|
||||
val ret = CodepointSequence(controlCharList.filter { index > it.second }.map { it.first })
|
||||
val ret = controlCharList.filter { index > it.second }.map { it.first }
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -832,13 +840,6 @@ class MovableType(
|
||||
return lines
|
||||
}
|
||||
|
||||
private fun <E> java.util.ArrayList<E>.penultimate(): E {
|
||||
return this[this.size - 2]
|
||||
}
|
||||
private fun <E> java.util.ArrayList<E>.penultimateOrNull(): E? {
|
||||
return this.getOrNull(this.size - 2)
|
||||
}
|
||||
|
||||
private fun penaliseWidening(score: Int, availableGlues: Double): Double =
|
||||
100.0 * (score / availableGlues).pow(3.0)
|
||||
// pow(score.toDouble(), 2.0)
|
||||
@@ -873,16 +874,6 @@ class MovableType(
|
||||
private fun CodePoint?.isThaiConso() = if (this == null) false else this in 0x0E01..0x0E2F
|
||||
private fun CodePoint?.isThaiVowel() = if (this == null) false else (this in 0x0E30..0x0E3E || this in 0x0E40..0x0E4E)
|
||||
|
||||
private fun CodepointSequence.isGlue() = this.size == 1 && (this[0] == ZWSP || this[0] in 0xFFFE0..0xFFFFF)
|
||||
private fun CodepointSequence.isNotGlue() = !this.isGlue()
|
||||
private fun CodepointSequence.isZeroGlue() = this.size == 1 && (this[0] == ZWSP)
|
||||
private fun CodePoint.glueCharToGlueSize() = when (this) {
|
||||
ZWSP -> 0
|
||||
in 0xFFFE0..0xFFFEF -> -(this - 0xFFFE0 + 1)
|
||||
in 0xFFFF0..0xFFFFF -> this - 0xFFFF0 + 1
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
|
||||
private fun CodePoint?.isWesternPunctOrQuotes() = if (this == null) false else (westernPuncts.contains(this) || quots.contains(this))
|
||||
private fun CodePoint?.isParens() = if (this == null) false else parens.contains(this)
|
||||
private fun CodePoint?.isParenOpen() = if (this == null) false else parenOpen.contains(this)
|
||||
@@ -997,7 +988,7 @@ class MovableType(
|
||||
0x20 to 4,
|
||||
0x2009 to 2,
|
||||
0x200A to 1,
|
||||
0x200B to 0,
|
||||
ZWSP to 0,
|
||||
0x3000 to 16,
|
||||
0xF0520 to 7, // why????
|
||||
)
|
||||
@@ -1010,10 +1001,6 @@ class MovableType(
|
||||
private val parenOpen = listOf(0x28,0x5B,0x7B).toSortedSet().also { it.addAll(cjparenStarts) }
|
||||
private val parenClose = listOf(0x29,0x5D,0x7D).toSortedSet().also { it.addAll(cjparenEnds) }
|
||||
|
||||
const val ZWSP = 0x200B
|
||||
const val SHY = 0xAD
|
||||
const val NBSP = 0xA0
|
||||
const val OBJ = 0xFFFC
|
||||
const val GLUE_POSITIVE_ONE = 0xFFFF0
|
||||
const val GLUE_POSITIVE_SIXTEEN = 0xFFFFF
|
||||
const val GLUE_NEGATIVE_ONE = 0xFFFE0
|
||||
@@ -1023,54 +1010,6 @@ class MovableType(
|
||||
|
||||
private inline fun Int.codepointToString() = Character.toChars(this).toSurrogatedString()
|
||||
|
||||
fun CodepointSequence.toReadable() = this.joinToString("") {
|
||||
if (it in 0x00..0x1f)
|
||||
"${(0x2400 + it).toChar()}"
|
||||
else if (it == 0x20 || it == 0xF0520)
|
||||
"\u2423"
|
||||
else if (it == NBSP)
|
||||
"{NBSP}"
|
||||
else if (it == SHY)
|
||||
"{SHY}"
|
||||
else if (it == ZWSP)
|
||||
"{ZWSP}"
|
||||
else if (it == OBJ)
|
||||
"{OBJ:"
|
||||
else if (it in FIXED_BLOCK_1..FIXED_BLOCK_1+15)
|
||||
" <block ${it - FIXED_BLOCK_1 + 1}>"
|
||||
else if (it in GLUE_NEGATIVE_ONE..GLUE_POSITIVE_SIXTEEN)
|
||||
" <glue ${it.glueCharToGlueSize()}> "
|
||||
else if (it == 0x100000)
|
||||
"{CC:null}"
|
||||
else if (it in 0x10F000..0x10FFFF) {
|
||||
val r = ((it and 0xF00) ushr 8).toString(16).toUpperCase()
|
||||
val g = ((it and 0x0F0) ushr 4).toString(16).toUpperCase()
|
||||
val b = ((it and 0x00F) ushr 0).toString(16).toUpperCase()
|
||||
"{CC:#$r$g$b}"
|
||||
}
|
||||
else if (it in 0xFFF70..0xFFF79)
|
||||
(it - 0xFFF70 + 0x30).codepointToString()
|
||||
else if (it == 0xFFF7D)
|
||||
"-"
|
||||
else if (it in 0xFFF80..0xFFF9A)
|
||||
(it - 0xFFF80 + 0x40).codepointToString()
|
||||
else if (it == 0xFFF9F)
|
||||
"}"
|
||||
else if (it in 0xF0541..0xF055A)
|
||||
(it - 0xF0541 + 0x1D670).codepointToString()
|
||||
else if (it in 0xF0561..0xF057A)
|
||||
(it - 0xF0561 + 0x1D68A).codepointToString()
|
||||
else if (it in 0xF0530..0xF0539)
|
||||
(it - 0xF0530 + 0x1D7F6).codepointToString()
|
||||
else if (it in 0xF0520..0xF057F)
|
||||
(it - 0xF0520 + 0x20).codepointToString()
|
||||
else if (it >= 0xF0000)
|
||||
it.toHex() + " "
|
||||
else
|
||||
Character.toString(it.toChar())
|
||||
}
|
||||
|
||||
|
||||
private fun List<ArrayList<CodepointSequence>>.debugprint() {
|
||||
println("Tokenised (${this.size} lines):")
|
||||
this.forEach {
|
||||
@@ -1139,13 +1078,15 @@ class MovableType(
|
||||
val input = this.filter { it.block.text.isNotGlue() }
|
||||
if (input.isEmpty()) return out
|
||||
|
||||
// println("freezeIntoCodepointSequence ${input.joinToString { "${it.posX}..${it.getEndPos()}" }}")
|
||||
|
||||
// process line indents
|
||||
if (input.first().posX > 0)
|
||||
out.addAll(input.first().posX.glueSizeToGlueChars())
|
||||
|
||||
// process blocks
|
||||
input.forEachIndexed { index, it ->
|
||||
val posX = it.posX + 1 - font.interchar * 2
|
||||
val posX = it.posX - font.interchar * 2
|
||||
val prevEndPos = if (index == 0) 0 else input[index-1].getEndPos()
|
||||
if (index > 0 && posX != prevEndPos) {
|
||||
out.addAll((posX - prevEndPos).glueSizeToGlueChars())
|
||||
@@ -1187,7 +1128,7 @@ class MovableType(
|
||||
|
||||
// process blocks
|
||||
input.forEachIndexed { index, it ->
|
||||
val posX = it.posX + 1 - font.interchar * 2
|
||||
val posX = it.posX - font.interchar * 2
|
||||
val prevEndPos = if (index == 0) 0 else input[index-1].getEndPos()
|
||||
if (index > 0 && posX != prevEndPos) {
|
||||
out += posX - prevEndPos
|
||||
@@ -1199,6 +1140,10 @@ class MovableType(
|
||||
|
||||
inline fun Boolean.toInt(shift: Int = 0) = if (this) 1.shl(shift) else 0
|
||||
|
||||
private fun List<Block>.getSlugEndPos(): Int {
|
||||
return this.lastOrNull()?.getEndPos() ?: 0
|
||||
}
|
||||
} // end of companion object
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,18 +33,133 @@ import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import net.torvald.terrarumsansbitmap.DiacriticsAnchor
|
||||
import net.torvald.terrarumsansbitmap.GlyphProps
|
||||
import net.torvald.terrarumsansbitmap.MovableType
|
||||
import net.torvald.terrarumsansbitmap.MovableType.Companion.GLUE_NEGATIVE_ONE
|
||||
import net.torvald.terrarumsansbitmap.MovableType.Companion.GLUE_POSITIVE_SIXTEEN
|
||||
import net.torvald.terrarumsansbitmap.TypesettingStrategy
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.FIXED_BLOCK_1
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.NBSP
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.OBJ
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.SHY
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.ZWSP
|
||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap.Companion.glueCharToGlueSize
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.util.*
|
||||
import java.util.zip.CRC32
|
||||
import java.util.zip.GZIPInputStream
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.sign
|
||||
|
||||
typealias CodepointSequence = ArrayList<CodePoint>
|
||||
class CodepointSequence {
|
||||
private val data = ArrayList<CodePoint>()
|
||||
|
||||
constructor()
|
||||
|
||||
constructor(chars: Collection<CodePoint>) {
|
||||
data.addAll(chars)
|
||||
}
|
||||
|
||||
val size; get() = data.size
|
||||
val indices; get() = data.indices
|
||||
val lastIndex; get() = data.lastIndex
|
||||
|
||||
fun forEach(action: (CodePoint) -> Unit) = data.forEach(action)
|
||||
fun forEachIndexed(action: (Int, CodePoint) -> Unit) = data.forEachIndexed(action)
|
||||
fun map(action: (CodePoint) -> Any?) = data.map(action)
|
||||
fun mapInxeded(action: (Int, CodePoint) -> Any?) = data.mapIndexed(action)
|
||||
fun first() = data.first()
|
||||
fun firstOrNull() = data.firstOrNull()
|
||||
fun first(predicate: (CodePoint) -> Boolean) = data.first(predicate)
|
||||
fun firstOrNull(predicate: (CodePoint) -> Boolean) = data.firstOrNull(predicate)
|
||||
fun last() = data.last()
|
||||
fun lastOrNull() = data.lastOrNull()
|
||||
fun last(predicate: (CodePoint) -> Boolean) = data.last(predicate)
|
||||
fun lastOrNull(predicate: (CodePoint) -> Boolean) = data.lastOrNull(predicate)
|
||||
fun filter(predicate: (CodePoint) -> Boolean) = data.filter(predicate)
|
||||
fun add(index: Int, char: CodePoint) = data.add(index, char)
|
||||
operator fun set(index: Int, char: CodePoint) {
|
||||
data[index] = char
|
||||
}
|
||||
fun add(char: CodePoint) = data.add(char)
|
||||
fun addAll(chars: Collection<CodePoint>) = data.addAll(chars)
|
||||
fun addAll(cs: CodepointSequence) = data.addAll(cs.data)
|
||||
fun removeAt(index: Int) = data.removeAt(index)
|
||||
fun remove(char: CodePoint) = data.remove(char)
|
||||
operator fun get(index: Int) = data[index]
|
||||
fun getOrNull(index: Int) = data.getOrNull(index)
|
||||
fun getOrElse(index: Int, action: (Int) -> CodePoint) = data.getOrElse(index, action)
|
||||
fun isEmpty() = data.isEmpty()
|
||||
fun isNotEmpty() = data.isNotEmpty()
|
||||
fun count(predicate: (CodePoint) -> Boolean) = data.count(predicate)
|
||||
fun addAll(index: Int, elements: Collection<CodePoint>) = data.addAll(index, elements)
|
||||
fun addAll(index: Int, elements: CodepointSequence) = data.addAll(index, elements.data)
|
||||
fun subList(fromIndex: Int, toIndex: Int) = data.subList(fromIndex, toIndex)
|
||||
fun slice(indices: IntRange) = data.slice(indices)
|
||||
|
||||
fun penultimate() = data[data.size - 2]
|
||||
fun penultimateOrNull() = data.getOrNull(data.size - 2)
|
||||
|
||||
fun toArray() = data.toArray()
|
||||
fun toList() = data.toList()
|
||||
|
||||
|
||||
fun isGlue() = data.size == 1 && (data[0] == ZWSP || data[0] in 0xFFFE0..0xFFFFF)
|
||||
fun isNotGlue() = !isGlue()
|
||||
fun isZeroGlue() = data.size == 1 && (data[0] == ZWSP)
|
||||
|
||||
private fun CharArray.toSurrogatedString(): String = if (this.size == 1) "${this[0]}" else "${this[0]}${this[1]}"
|
||||
private inline fun Int.codepointToString() = Character.toChars(this).toSurrogatedString()
|
||||
private fun CodePoint.toHex() = "U+${this.toString(16).padStart(4, '0').toUpperCase()}"
|
||||
|
||||
fun toHexes() = data.joinToString(" ") { it.toHex() }
|
||||
|
||||
fun toReadable() = data.joinToString("") {
|
||||
if (it in 0x00..0x1f)
|
||||
"${(0x2400 + it).toChar()}"
|
||||
else if (it == 0x20 || it == 0xF0520)
|
||||
"\u2423"
|
||||
else if (it == NBSP)
|
||||
"{NBSP}"
|
||||
else if (it == SHY)
|
||||
"{SHY}"
|
||||
else if (it == ZWSP)
|
||||
"{ZWSP}"
|
||||
else if (it == OBJ)
|
||||
"{OBJ:"
|
||||
else if (it in FIXED_BLOCK_1..FIXED_BLOCK_1 +15)
|
||||
" <block ${it - FIXED_BLOCK_1 + 1}>"
|
||||
else if (it in GLUE_NEGATIVE_ONE..GLUE_POSITIVE_SIXTEEN)
|
||||
" <glue ${it.glueCharToGlueSize()}> "
|
||||
else if (it == 0x100000)
|
||||
"{CC:null}"
|
||||
else if (it in 0x10F000..0x10FFFF) {
|
||||
val r = ((it and 0xF00) ushr 8).toString(16).toUpperCase()
|
||||
val g = ((it and 0x0F0) ushr 4).toString(16).toUpperCase()
|
||||
val b = ((it and 0x00F) ushr 0).toString(16).toUpperCase()
|
||||
"{CC:#$r$g$b}"
|
||||
}
|
||||
else if (it in 0xFFF70..0xFFF79)
|
||||
(it - 0xFFF70 + 0x30).codepointToString()
|
||||
else if (it == 0xFFF7D)
|
||||
"-"
|
||||
else if (it in 0xFFF80..0xFFF9A)
|
||||
(it - 0xFFF80 + 0x40).codepointToString()
|
||||
else if (it == 0xFFF9F)
|
||||
"}"
|
||||
else if (it in 0xF0541..0xF055A)
|
||||
(it - 0xF0541 + 0x1D670).codepointToString()
|
||||
else if (it in 0xF0561..0xF057A)
|
||||
(it - 0xF0561 + 0x1D68A).codepointToString()
|
||||
else if (it in 0xF0530..0xF0539)
|
||||
(it - 0xF0530 + 0x1D7F6).codepointToString()
|
||||
else if (it in 0xF0520..0xF057F)
|
||||
(it - 0xF0520 + 0x20).codepointToString()
|
||||
else if (it >= 0xF0000)
|
||||
it.toHex() + " "
|
||||
else
|
||||
Character.toString(it.toChar())
|
||||
}
|
||||
}
|
||||
internal typealias CodePoint = Int
|
||||
internal typealias ARGB8888 = Int
|
||||
internal typealias Hash = Long
|
||||
@@ -330,7 +445,7 @@ class TerrarumSansBitmap(
|
||||
private val offsetCustomSym = (H - SIZE_CUSTOM_SYM) / 2
|
||||
|
||||
private var flagFirstRun = true
|
||||
private var textBuffer = CodepointSequence(256)
|
||||
private var textBuffer = CodepointSequence()
|
||||
|
||||
private lateinit var tempLinotype: Texture
|
||||
|
||||
@@ -918,19 +1033,38 @@ class TerrarumSansBitmap(
|
||||
for (i in 0xFFF70..0xFFF9F) {
|
||||
glyphProps[i] = GlyphProps(0)
|
||||
}
|
||||
|
||||
glyphProps[ZWNJ] = GlyphProps(0)
|
||||
glyphProps[ZWJ] = GlyphProps(0)
|
||||
glyphProps[ZWSP] = GlyphProps(0)
|
||||
glyphProps[SHY] = GlyphProps(0)
|
||||
glyphProps[OBJ] = GlyphProps(0)
|
||||
}
|
||||
|
||||
private fun setupDynamicTextReplacer() {
|
||||
// replace NBSP into a block of same width
|
||||
val spaceWidth = glyphProps[32]?.width ?: throw IllegalStateException()
|
||||
if (spaceWidth > 16) throw InternalError("Space (U+0020) character is too wide ($spaceWidth)")
|
||||
textReplaces[0xA0] = FIXED_BLOCK_1 + (spaceWidth - 1)
|
||||
textReplaces[NBSP] = FIXED_BLOCK_1 + (spaceWidth - 1)
|
||||
}
|
||||
|
||||
fun getWidth(text: String) = getWidthNormalised(text.toCodePoints())
|
||||
fun getWidth(s: CodepointSequence) = getWidthNormalised(s.normalise())
|
||||
|
||||
fun getWidthNormalised(s: CodepointSequence): Int {
|
||||
if (s.isEmpty())
|
||||
return 0
|
||||
|
||||
if (s.size == 1) {
|
||||
return glyphProps[s.first()]?.width ?: (
|
||||
if (errorOnUnknownChar)
|
||||
throw InternalError("No GlyphProps for char '${s.first().toHex()}' " +
|
||||
"(${s.first().charInfo()})")
|
||||
else
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
val cacheObj = getCache(s.getHash())
|
||||
|
||||
if (cacheObj != null) {
|
||||
@@ -949,7 +1083,7 @@ class TerrarumSansBitmap(
|
||||
* @return Pair of X-positions and Y-positions, of which the X-position's size is greater than the string
|
||||
* and the last element marks the width of entire string.
|
||||
*/
|
||||
private fun buildPosMap(str: List<Int>): Posmap {
|
||||
private fun buildPosMap(str: CodepointSequence): Posmap {
|
||||
val posXbuffer = IntArray(str.size + 1) { 0 }
|
||||
val posYbuffer = IntArray(str.size) { 0 }
|
||||
|
||||
@@ -1130,7 +1264,7 @@ class TerrarumSansBitmap(
|
||||
val penultCharProp = glyphProps[str[nonDiacriticCounter]] ?:
|
||||
(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
|
||||
posXbuffer[posXbuffer.lastIndex] = posXbuffer[posXbuffer.lastIndex - 1] + // DON'T add 1 to house the shadow, it totally breaks stuffs
|
||||
if (lastCharProp != null && lastCharProp.writeOnTop >= 0) {
|
||||
val realDiacriticWidth = if (lastCharProp.alignWhere == GlyphProps.ALIGN_CENTRE) {
|
||||
(lastCharProp.width).div(2) + penultCharProp.diacriticsAnchors[0].x
|
||||
@@ -2221,6 +2355,13 @@ class TerrarumSansBitmap(
|
||||
|
||||
companion object {
|
||||
|
||||
internal fun CodePoint.glueCharToGlueSize() = when (this) {
|
||||
ZWSP -> 0
|
||||
in 0xFFFE0..0xFFFEF -> -(this - 0xFFFE0 + 1)
|
||||
in 0xFFFF0..0xFFFFF -> this - 0xFFFF0 + 1
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
|
||||
const internal val linotypePaddingX = 16
|
||||
const internal val linotypePaddingY = 10
|
||||
|
||||
@@ -2467,8 +2608,12 @@ class TerrarumSansBitmap(
|
||||
|
||||
internal fun Int.charInfo() = "U+${this.toString(16).padStart(4, '0').toUpperCase()}: ${Character.getName(this)}"
|
||||
|
||||
private const val ZWNJ = 0x200C
|
||||
private const val ZWJ = 0x200D
|
||||
const val ZWNJ = 0x200C
|
||||
const val ZWJ = 0x200D
|
||||
const val ZWSP = 0x200B
|
||||
const val SHY = 0xAD
|
||||
const val NBSP = 0xA0
|
||||
const val OBJ = 0xFFFC
|
||||
|
||||
private val tamilLigatingConsonants = listOf('க','ங','ச','ஞ','ட','ண','த','ந','ன','ப','ம','ய','ர','ற','ல','ள','ழ','வ').map { it.toInt() }.toIntArray() // this is the only thing that .indexOf() is called against, so NO HASHSET
|
||||
private const val TAMIL_KSSA = 0xF00ED
|
||||
|
||||
@@ -278,7 +278,7 @@ class TerrarumTypewriterBitmap(
|
||||
private val pixmapOffsetY = 10
|
||||
private val linotypePad = 16
|
||||
private var flagFirstRun = true
|
||||
private @Volatile var textBuffer = CodepointSequence(256)
|
||||
private @Volatile var textBuffer = CodepointSequence()
|
||||
private @Volatile lateinit var tempLinotype: Texture
|
||||
private var nullProp = GlyphProps(15)
|
||||
|
||||
@@ -396,6 +396,8 @@ class TerrarumTypewriterBitmap(
|
||||
}
|
||||
|
||||
|
||||
private fun buildPosMap(str: CodepointSequence) = buildPosMap(str.toList())
|
||||
|
||||
/**
|
||||
* posXbuffer's size is greater than the string, last element marks the width of entire string.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user