mirror of
https://github.com/curioustorvald/Terrarum-sans-bitmap.git
synced 2026-03-07 20:01:52 +09:00
almost working...
This commit is contained in:
@@ -2,6 +2,8 @@ package net.torvald.terrarumsansbitmap
|
|||||||
|
|
||||||
import com.badlogic.gdx.graphics.g2d.Batch
|
import com.badlogic.gdx.graphics.g2d.Batch
|
||||||
import com.badlogic.gdx.utils.Disposable
|
import com.badlogic.gdx.utils.Disposable
|
||||||
|
import net.torvald.terrarumsansbitmap.MovableType.Companion.isGlue
|
||||||
|
import net.torvald.terrarumsansbitmap.MovableType.Companion.isNotGlue
|
||||||
import net.torvald.terrarumsansbitmap.gdx.CodePoint
|
import net.torvald.terrarumsansbitmap.gdx.CodePoint
|
||||||
import net.torvald.terrarumsansbitmap.gdx.CodepointSequence
|
import net.torvald.terrarumsansbitmap.gdx.CodepointSequence
|
||||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap
|
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap
|
||||||
@@ -12,6 +14,10 @@ import java.lang.Math.pow
|
|||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Despite "CJK" texts needing their own typesetting rule, in this code Korean texts are typesetted much like
|
||||||
|
* the western texts minus the hyphenation rule (it does hyphenate just like the western texts, but omits the
|
||||||
|
* actual hyphen character), therefore only the "CJ" texts get their own typesetting rule.
|
||||||
|
*
|
||||||
* Created by minjaesong on 2024-03-24.
|
* Created by minjaesong on 2024-03-24.
|
||||||
*/
|
*/
|
||||||
class MovableType(
|
class MovableType(
|
||||||
@@ -41,17 +47,20 @@ class MovableType(
|
|||||||
init { if (inputText.isNotEmpty() && !isNull) {
|
init { if (inputText.isNotEmpty() && !isNull) {
|
||||||
if (paperWidth < 100) throw IllegalArgumentException("Width too narrow; width must be at least 100 pixels (got $paperWidth)")
|
if (paperWidth < 100) throw IllegalArgumentException("Width too narrow; width must be at least 100 pixels (got $paperWidth)")
|
||||||
|
|
||||||
|
println("Paper width: $paperWidth")
|
||||||
|
|
||||||
val lines = inputText.tokenise()
|
val lines = inputText.tokenise()
|
||||||
lines.debugprint()
|
lines.debugprint()
|
||||||
|
|
||||||
TODO()
|
lines.forEachIndexed { linenum, it ->
|
||||||
|
println("Processing input text line ${linenum + 1} (word count: ${it.size})...")
|
||||||
|
|
||||||
lines.forEach {
|
|
||||||
val boxes: MutableList<TextCacheObj> = it.map { font.createTextCache(it) }.toMutableList()
|
val boxes: MutableList<TextCacheObj> = it.map { font.createTextCache(it) }.toMutableList()
|
||||||
var slug = ArrayList<Block>() // slug of the linotype machine
|
var slug = ArrayList<Block>() // slug of the linotype machine
|
||||||
var slugWidth = 0
|
var slugWidth = 0
|
||||||
|
var ignoreThisLine = false
|
||||||
|
|
||||||
fun dequeue() = boxes.removeAt(0)
|
fun dequeue() = boxes.removeFirst()
|
||||||
fun addHyphenatedTail(box: TextCacheObj) = boxes.add(0, box)
|
fun addHyphenatedTail(box: TextCacheObj) = boxes.add(0, box)
|
||||||
fun addToSlug(box: TextCacheObj) {
|
fun addToSlug(box: TextCacheObj) {
|
||||||
val nextPosX = (slug.lastOrNull()?.getEndPos() ?: 0)
|
val nextPosX = (slug.lastOrNull()?.getEndPos() ?: 0)
|
||||||
@@ -67,9 +76,65 @@ class MovableType(
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
fun getBadnessW(): Pair<Float, Int> = TODO()
|
// the slug is likely end with a glue, must take care of it (but don't modify the slug itself)
|
||||||
fun getBadnessT(): Pair<Float, Int> = TODO()
|
fun getBadnessW(box: TextCacheObj): Pair<Float, Int> {
|
||||||
fun getBadnessH(): Pair<Float, Int> = TODO()
|
val slug = slug.toMutableList()
|
||||||
|
|
||||||
|
// remove the trailing glue(s?) in the slug copy
|
||||||
|
while (slug.lastOrNull()?.block?.isGlue() == true) {
|
||||||
|
slug.removeLastOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
var slugWidth = slug.lastOrNull()?.getEndPos() ?: 0
|
||||||
|
if (slug.isNotEmpty() && hangable.contains(slug.last().block.penultimateChar))
|
||||||
|
slugWidth -= hangWidth
|
||||||
|
else if (slug.isNotEmpty() && hangableFW.contains(slug.last().block.penultimateChar))
|
||||||
|
slugWidth -= hangWidthFW
|
||||||
|
|
||||||
|
val difference = (paperWidth - slugWidth).absoluteValue
|
||||||
|
val badness = difference.toFloat()
|
||||||
|
|
||||||
|
return badness to difference
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBadnessT(box: TextCacheObj): Pair<Float, Int> {
|
||||||
|
val slug = slug.toMutableList()
|
||||||
|
|
||||||
|
// add the box to the slug copy
|
||||||
|
val nextPosX = (slug.lastOrNull()?.getEndPos() ?: 0)
|
||||||
|
slug.add(Block(nextPosX, box))
|
||||||
|
|
||||||
|
var slugWidth = slugWidth + box.width
|
||||||
|
if (slug.isNotEmpty() && hangable.contains(slug.last().block.penultimateChar))
|
||||||
|
slugWidth -= hangWidth
|
||||||
|
else if (slug.isNotEmpty() && hangableFW.contains(slug.last().block.penultimateChar))
|
||||||
|
slugWidth -= hangWidthFW
|
||||||
|
|
||||||
|
val difference = (paperWidth - slugWidth).absoluteValue
|
||||||
|
val badness = penaliseTightening(difference)
|
||||||
|
|
||||||
|
return badness to difference
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBadnessH(box: TextCacheObj): Pair<Float, Int> {
|
||||||
|
val slug = slug.toMutableList()
|
||||||
|
val (hyphHead, hyphTail) = box.text.hyphenate().toList().map { font.createTextCache(it) }
|
||||||
|
|
||||||
|
// add the hyphHead to the slug copy
|
||||||
|
val nextPosX = (slug.lastOrNull()?.getEndPos() ?: 0)
|
||||||
|
slug.add(Block(nextPosX, hyphHead))
|
||||||
|
|
||||||
|
var slugWidth = slugWidth + hyphHead.width
|
||||||
|
if (slug.isNotEmpty() && hangable.contains(slug.last().block.penultimateChar))
|
||||||
|
slugWidth -= hangWidth
|
||||||
|
else if (slug.isNotEmpty() && hangableFW.contains(slug.last().block.penultimateChar))
|
||||||
|
slugWidth -= hangWidthFW
|
||||||
|
|
||||||
|
val difference = (paperWidth - slugWidth)
|
||||||
|
val badness = penaliseHyphenation(difference.absoluteValue)
|
||||||
|
|
||||||
|
return badness to difference
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -77,13 +142,21 @@ class MovableType(
|
|||||||
val box = dequeue()
|
val box = dequeue()
|
||||||
|
|
||||||
if (box.isNotGlue()) {
|
if (box.isNotGlue()) {
|
||||||
// if adding a box would cause overflow
|
// deal with the hangables
|
||||||
if (slugWidth + spaceWidth + box.width >= paperWidth) {
|
val slugWidthForOverflowCalc = if (hangable.contains(box.penultimateChar))
|
||||||
|
slugWidth - hangWidth
|
||||||
|
else if (hangableFW.contains(box.penultimateChar))
|
||||||
|
slugWidth - hangWidthFW
|
||||||
|
else
|
||||||
|
slugWidth
|
||||||
|
|
||||||
|
// if adding the box would cause overflow
|
||||||
|
if (slugWidthForOverflowCalc + box.width > paperWidth) {
|
||||||
// badness: always positive and weighted
|
// badness: always positive and weighted
|
||||||
// widthDelta: can be positive or negative
|
// widthDelta: can be positive or negative
|
||||||
val (badnessW, widthDeltaW) = getBadnessW()
|
val (badnessW, widthDeltaW) = getBadnessW(box) // widthDeltaW is always positive
|
||||||
val (badnessT, widthDeltaT) = getBadnessT()
|
val (badnessT, widthDeltaT) = getBadnessT(box) // widthDeltaT is always positive
|
||||||
val (badnessH, widthDeltaH) = getBadnessH()
|
val (badnessH, widthDeltaH) = getBadnessH(box) // widthDeltaH can be anything
|
||||||
|
|
||||||
val (selectedBadness, selectedWidthDelta, selectedStrat) = listOf(
|
val (selectedBadness, selectedWidthDelta, selectedStrat) = listOf(
|
||||||
Triple(badnessW, widthDeltaW, "Widen"),
|
Triple(badnessW, widthDeltaW, "Widen"),
|
||||||
@@ -91,18 +164,63 @@ class MovableType(
|
|||||||
Triple(badnessH, widthDeltaH, "Hyphenate"),
|
Triple(badnessH, widthDeltaH, "Hyphenate"),
|
||||||
).minByOrNull { it.first }!!
|
).minByOrNull { it.first }!!
|
||||||
|
|
||||||
|
println(" Line ${typesettedSlugs.size + 1} Strat: $selectedStrat (badness $selectedBadness, delta $selectedWidthDelta; full badness WTH = $badnessW, $badnessT, $badnessH; full delta WTH = $widthDeltaW, $widthDeltaT, $widthDeltaH)")
|
||||||
|
println(" Interim Slug: [ ${slug.map { it.block.text.toReadable() }.joinToString(" | ")} ]")
|
||||||
|
|
||||||
when (selectedStrat) {
|
when (selectedStrat) {
|
||||||
"Widen" -> {
|
"Widen", "Tighten" -> {
|
||||||
TODO()
|
// widen/tighten the spacing between blocks
|
||||||
}
|
|
||||||
"Tighten" -> {
|
// widen: 1, tighten: -1
|
||||||
TODO()
|
val operation = if (selectedStrat == "Widen") 1 else -1
|
||||||
|
|
||||||
|
// Widen: remove the trailing glue(s?) in the slug
|
||||||
|
if (selectedStrat == "Widen") {
|
||||||
|
while (slug.lastOrNull()?.block?.isGlue() == true) {
|
||||||
|
slug.removeLast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Tighten: add the box to the slug
|
||||||
|
else {
|
||||||
|
addToSlug(box)
|
||||||
|
// remove glues on the upcoming blocks
|
||||||
|
while (boxes.firstOrNull()?.isGlue() == true) {
|
||||||
|
boxes.removeFirst()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
moveSlugsToFitTheWidth(operation, slug, selectedWidthDelta)
|
||||||
|
|
||||||
|
// put the trailing word back into the upcoming words
|
||||||
|
if (selectedStrat == "Widen") {
|
||||||
|
addHyphenatedTail(box)
|
||||||
|
}
|
||||||
|
// if tightening leaves an empty line behind, signal the typesetter to discard that line
|
||||||
|
else if (selectedStrat == "Tighten" && boxes.isEmpty()) {
|
||||||
|
ignoreThisLine = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"Hyphenate" -> {
|
"Hyphenate" -> {
|
||||||
TODO()
|
// insert hyphen-head to the slug
|
||||||
|
// widen/tighten the spacing between blocks using widthDeltaH
|
||||||
|
// insert hyphen-tail to the list of upcoming boxes
|
||||||
|
|
||||||
|
val (hyphHead, hyphTail) = box.text.hyphenate().toList().map { font.createTextCache(it) }
|
||||||
|
|
||||||
|
// widen: 1, tighten: -1
|
||||||
|
val operation = widthDeltaH.sign
|
||||||
|
|
||||||
|
// insert hyphHead into the slug
|
||||||
|
addToSlug(hyphHead)
|
||||||
|
|
||||||
|
moveSlugsToFitTheWidth(operation, slug, selectedWidthDelta)
|
||||||
|
|
||||||
|
// put the tail into the upcoming words
|
||||||
|
addHyphenatedTail(hyphTail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println(" > Line ${typesettedSlugs.size + 1} Final Slug: [ ${slug.map { it.block.text.toReadable() }.joinToString(" | ")} ]")
|
||||||
dispatchSlug()
|
dispatchSlug()
|
||||||
}
|
}
|
||||||
// typeset the boxes normally
|
// typeset the boxes normally
|
||||||
@@ -110,15 +228,18 @@ class MovableType(
|
|||||||
addToSlug(box)
|
addToSlug(box)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else { // box is glue
|
||||||
addToSlug(box)
|
addToSlug(box)
|
||||||
}
|
}
|
||||||
} // end of while (boxes.isNotEmpty())
|
} // end of while (boxes.isNotEmpty())
|
||||||
|
|
||||||
dispatchSlug()
|
if (!ignoreThisLine) {
|
||||||
|
println(" > Line ${typesettedSlugs.size + 1} Final Slug: [ ${slug.map { it.block.text.toReadable() }.joinToString(" | ")} ]")
|
||||||
|
dispatchSlug()
|
||||||
|
}
|
||||||
} // end of lines.forEach
|
} // end of lines.forEach
|
||||||
|
|
||||||
TODO()
|
height = typesettedSlugs.size
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
|
||||||
@@ -370,11 +491,84 @@ class MovableType(
|
|||||||
private val quots = listOf(0x22, 0x27, 0xAB, 0xBB, 0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F, 0x2039, 0x203A).toSortedSet()
|
private val quots = listOf(0x22, 0x27, 0xAB, 0xBB, 0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F, 0x2039, 0x203A).toSortedSet()
|
||||||
private val commas = listOf(0x2C, 0x3B, 0x3001, 0xff0c).toSortedSet()
|
private val commas = listOf(0x2C, 0x3B, 0x3001, 0xff0c).toSortedSet()
|
||||||
private val hangable = listOf(0x2E, 0x2C).toSortedSet()
|
private val hangable = listOf(0x2E, 0x2C).toSortedSet()
|
||||||
|
private val hangableFW = listOf(0x3001, 0x3002, 0xff0c, 0xff0e).toSortedSet()
|
||||||
private const val spaceWidth = 5
|
private const val spaceWidth = 5
|
||||||
private const val hangWidth = 6
|
private const val hangWidth = 6
|
||||||
|
private const val hangWidthFW = TerrarumSansBitmap.W_ASIAN_PUNCT
|
||||||
|
|
||||||
private fun CodePoint.toHex() = "U+${this.toString(16).padStart(4, '0').toUpperCase()}"
|
private fun CodePoint.toHex() = "U+${this.toString(16).padStart(4, '0').toUpperCase()}"
|
||||||
|
|
||||||
|
private fun moveSlugsToFitTheWidth(operation: Int, slug: ArrayList<Block>, selectedWidthDelta: Int) {
|
||||||
|
var gluesInfo = slug.mapIndexed { index, block -> block to index }.filter { (block, index) ->
|
||||||
|
block.block.isGlue()
|
||||||
|
}.map { (block, index) ->
|
||||||
|
val prevBlockEndsWith = if (index == 0) null else slug[index - 1].block.penultimateChar // last() will just return {NUL}
|
||||||
|
Triple(block, index, prevBlockEndsWith)
|
||||||
|
}
|
||||||
|
// if there are no glues, put spaces between all characters
|
||||||
|
if (gluesInfo.isEmpty()) {
|
||||||
|
gluesInfo = slug.subList(1, slug.size).mapIndexed { index, block ->
|
||||||
|
val prevBlockEndsWith = slug[index].block.penultimateChar // last() will just return {NUL}
|
||||||
|
Triple(block, index + 1, prevBlockEndsWith)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val gluesMoveAmounts0 = getGluesMoveAmounts(gluesInfo, selectedWidthDelta) // first order derivative of gluesMoveAmounts
|
||||||
|
val gluesMoveAmounts = IntArray(slug.size) // actual move values
|
||||||
|
for (i in 1 until gluesMoveAmounts.size){
|
||||||
|
gluesMoveAmounts[i] = gluesMoveAmounts[i - 1] + gluesMoveAmounts0.getOrElse(i) { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// move blocks using gluesMoveAmounts
|
||||||
|
gluesMoveAmounts.forEachIndexed { index, moveAmounts ->
|
||||||
|
slug[index].posX += moveAmounts * operation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns move amounts in following format:
|
||||||
|
* intArray(0, 0, <absolute value of move amount>, 0, 0, 0, <absolute value of move amount>, ...)
|
||||||
|
*/
|
||||||
|
private fun getGluesMoveAmounts(gluesInfo: List<Triple<Block, Int, CodePoint?>>, moveAmount: Int): IntArray {
|
||||||
|
if (gluesInfo.isEmpty()) throw IllegalArgumentException("Glues info is empty!")
|
||||||
|
|
||||||
|
val operations = HashMap<Int, Int>() // key: index, value: number of hits
|
||||||
|
var operationsSize = 0
|
||||||
|
|
||||||
|
while (operationsSize < moveAmount) {
|
||||||
|
val li = gluesInfo.sortedBy { (block, index, thisWordEnd) ->
|
||||||
|
val priority = if (thisWordEnd == null)
|
||||||
|
255
|
||||||
|
else if (periods.contains(thisWordEnd))
|
||||||
|
1
|
||||||
|
else if (quots.contains(thisWordEnd) or quots.contains(block.block.text.firstOrNull()))
|
||||||
|
2
|
||||||
|
else if (commas.contains(thisWordEnd))
|
||||||
|
3
|
||||||
|
else
|
||||||
|
255
|
||||||
|
|
||||||
|
(Math.random() * 65535).toInt().or(priority.shl(16))
|
||||||
|
}
|
||||||
|
var c = 0
|
||||||
|
while (operationsSize < moveAmount && c < li.size) {
|
||||||
|
val index = li[c].second
|
||||||
|
operations[index] = (operations[index] ?: 0) + 1
|
||||||
|
|
||||||
|
c += 1
|
||||||
|
operationsSize += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val arrayoid = operations.entries.toList().map { it.key to it.value }.sortedBy { it.first }
|
||||||
|
if (arrayoid.isEmpty()) return IntArray(0)
|
||||||
|
|
||||||
|
val array = IntArray(arrayoid.last().first + 1)
|
||||||
|
arrayoid.forEach { (index, hits) ->
|
||||||
|
array[index] = hits
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return indices of blocks in the `currentLine`
|
* @return indices of blocks in the `currentLine`
|
||||||
*/
|
*/
|
||||||
@@ -417,7 +611,7 @@ class MovableType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return: [ job count for 0th word, job count for 1st word, job count for 2nd word, ... ]
|
// return: [ job count for 0th word, job count for 1st word, job count for 2nd word, ... ]
|
||||||
private fun coalesceIndices(listOfJobs: List<Int>): IntArray {
|
private fun coalesceIndices(listOfJobs: IntArray): IntArray {
|
||||||
if (listOfJobs.isEmpty()) return IntArray(0)
|
if (listOfJobs.isEmpty()) return IntArray(0)
|
||||||
|
|
||||||
// println(" sample: ${listOfJobs.joinToString()}")
|
// println(" sample: ${listOfJobs.joinToString()}")
|
||||||
@@ -477,8 +671,20 @@ class MovableType(
|
|||||||
tokens.add(CodepointSequence(listOf(GLUE_POSITIVE_ONE + (glue - 1))))
|
tokens.add(CodepointSequence(listOf(GLUE_POSITIVE_ONE + (glue - 1))))
|
||||||
else
|
else
|
||||||
tokens.add(CodepointSequence(listOf(GLUE_NEGATIVE_ONE + (glue.absoluteValue - 1))))
|
tokens.add(CodepointSequence(listOf(GLUE_NEGATIVE_ONE + (glue.absoluteValue - 1))))
|
||||||
else
|
else {
|
||||||
throw IllegalStateException("Glue too large ($glue)")
|
val fullGlues = glue.absoluteValue / 16
|
||||||
|
val smallGlues = glue.absoluteValue % 16
|
||||||
|
if (glue > 0)
|
||||||
|
tokens.add(CodepointSequence(
|
||||||
|
List(fullGlues) { GLUE_POSITIVE_SIXTEEN } +
|
||||||
|
listOf(GLUE_POSITIVE_ONE + (smallGlues - 1))
|
||||||
|
))
|
||||||
|
else
|
||||||
|
tokens.add(CodepointSequence(
|
||||||
|
List(fullGlues) { GLUE_NEGATIVE_SIXTEEN } +
|
||||||
|
listOf(GLUE_NEGATIVE_ONE + (smallGlues - 1))
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
glue = 0
|
glue = 0
|
||||||
}
|
}
|
||||||
@@ -608,7 +814,7 @@ class MovableType(
|
|||||||
|
|
||||||
private fun penaliseHyphenation(score: Int): Float = (10.0 * pow(score.toDouble(), 1.0/3.0) + 0.47*score).toFloat()
|
private fun penaliseHyphenation(score: Int): Float = (10.0 * pow(score.toDouble(), 1.0/3.0) + 0.47*score).toFloat()
|
||||||
|
|
||||||
private fun CodePoint?.isCJ() = if (this == null) false else listOf(4, 6).any {
|
private fun CodePoint?.isCJ() = if (this == null) false else listOf(4, 6, 20).any {
|
||||||
TerrarumSansBitmap.codeRange[it].contains(this)
|
TerrarumSansBitmap.codeRange[it].contains(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,6 +828,7 @@ class MovableType(
|
|||||||
private fun CodePoint?.isColourCode() = if (this == null) false else colourCodes.contains(this)
|
private fun CodePoint?.isColourCode() = if (this == null) false else colourCodes.contains(this)
|
||||||
|
|
||||||
private fun CodepointSequence.isGlue() = this.size == 1 && (this[0] == ZWSP || this[0] in 0xFFFE0..0xFFFFF)
|
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 CodepointSequence.isZeroGlue() = this.size == 1 && (this[0] == ZWSP)
|
||||||
private fun CodePoint.toGlueSize() = when (this) {
|
private fun CodePoint.toGlueSize() = when (this) {
|
||||||
ZWSP -> 0
|
ZWSP -> 0
|
||||||
@@ -732,18 +939,23 @@ class MovableType(
|
|||||||
|
|
||||||
private const val ZWSP = 0x200B
|
private const val ZWSP = 0x200B
|
||||||
private const val SHY = 0xAD
|
private const val SHY = 0xAD
|
||||||
|
private const val NBSP = 0xA0
|
||||||
private const val GLUE_POSITIVE_ONE = 0xFFFF0
|
private const val GLUE_POSITIVE_ONE = 0xFFFF0
|
||||||
|
private const val GLUE_POSITIVE_SIXTEEN = 0xFFFFF
|
||||||
private const val GLUE_NEGATIVE_ONE = 0xFFFE0
|
private const val GLUE_NEGATIVE_ONE = 0xFFFE0
|
||||||
|
private const val GLUE_NEGATIVE_SIXTEEN = 0xFFFEF
|
||||||
|
|
||||||
private fun CodepointSequence.toReadable() = this.joinToString("") {
|
private fun CodepointSequence.toReadable() = this.joinToString("") {
|
||||||
if (it in 0x00..0x1f)
|
if (it in 0x00..0x1f)
|
||||||
"${(0x2400 + it).toChar()}"
|
"${(0x2400 + it).toChar()}"
|
||||||
else if (it == 0x20)
|
else if (it == 0x20)
|
||||||
"\u2423"
|
"\u2423"
|
||||||
else if (it == 0xA0)
|
else if (it == NBSP)
|
||||||
"{NBSP}"
|
"{NBSP}"
|
||||||
else if (it == 0xAD)
|
else if (it == SHY)
|
||||||
"{SHY}"
|
"{SHY}"
|
||||||
|
else if (it == ZWSP)
|
||||||
|
"{ZWSP}"
|
||||||
else if (it >= 0xF0000)
|
else if (it >= 0xF0000)
|
||||||
it.toHex() + " "
|
it.toHex() + " "
|
||||||
else
|
else
|
||||||
@@ -767,6 +979,9 @@ class MovableType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun TextCacheObj.isNotGlue(): Boolean {
|
private fun TextCacheObj.isNotGlue(): Boolean {
|
||||||
|
return this.glyphLayout!!.textBuffer.isNotGlue()
|
||||||
|
}
|
||||||
|
private fun TextCacheObj.isGlue(): Boolean {
|
||||||
return this.glyphLayout!!.textBuffer.isGlue()
|
return this.glyphLayout!!.textBuffer.isGlue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2074,6 +2074,8 @@ class TerrarumSansBitmap(
|
|||||||
get() = glyphLayout!!.width
|
get() = glyphLayout!!.width
|
||||||
val texture: Texture
|
val texture: Texture
|
||||||
get() = glyphLayout!!.linotype
|
get() = glyphLayout!!.linotype
|
||||||
|
val penultimateChar: CodePoint
|
||||||
|
get() = text[text.size - 2]
|
||||||
|
|
||||||
fun dispose() {
|
fun dispose() {
|
||||||
glyphLayout?.linotype?.dispose()
|
glyphLayout?.linotype?.dispose()
|
||||||
|
|||||||
Reference in New Issue
Block a user