hopefully alleviating a bug involving multithreaded (or mixed thread?) usage

This commit is contained in:
minjaesong
2021-11-26 21:06:05 +09:00
parent c3f9ea47fd
commit 45b464ee13
2 changed files with 383 additions and 359 deletions

View File

@@ -394,79 +394,86 @@ class TerrarumSansBitmap(
var index = 0 var index = 0
while (index <= textBuffer.lastIndex) { while (index <= textBuffer.lastIndex) {
val c = textBuffer[index] try {
val sheetID = getSheetType(c) val c = textBuffer[index]
val (sheetX, sheetY) = val sheetID = getSheetType(c)
if (index == 0) getSheetwisePosition(0, c) val (sheetX, sheetY) =
else getSheetwisePosition(textBuffer[index - 1], c) if (index == 0) getSheetwisePosition(0, c)
val hash = getHash(c) // to be used with Bad Transmission Modifier else getSheetwisePosition(textBuffer[index - 1], c)
val hash = getHash(c) // to be used with Bad Transmission Modifier
if (isColourCode(c)) {
if (c == 0x100000) {
renderCol = -1
}
else {
renderCol = getColour(c)
}
}
else if (isCharsetOverride(c)) {
charsetOverride = c - CHARSET_OVERRIDE_DEFAULT
}
else if (sheetID == SHEET_HANGUL) {
// Flookahead for {I, P, F}
val cNext = if (index + 1 < textBuffer.size) textBuffer[index + 1] else 0
val cNextNext = if (index + 2 < textBuffer.size) textBuffer[index + 2] else 0
val hangulLength = if (isHangulJongseong(cNextNext) && isHangulJungseong(cNext))
3
else if (isHangulJungseong(cNext))
2
else
1
val (indices, rows) = toHangulIndexAndRow(c, cNext, cNextNext)
val (indexCho, indexJung, indexJong) = indices
val (choRow, jungRow, jongRow) = rows
val hangulSheet = sheets[SHEET_HANGUL]
val choTex = hangulSheet.get(indexCho, choRow)
val jungTex = hangulSheet.get(indexJung, jungRow)
val jongTex = hangulSheet.get(indexJong, jongRow)
linotypePixmap.drawPixmap(choTex, posXbuffer[index], pixmapOffsetY, renderCol)
linotypePixmap.drawPixmap(jungTex, posXbuffer[index], pixmapOffsetY, renderCol)
linotypePixmap.drawPixmap(jongTex, posXbuffer[index], pixmapOffsetY, renderCol)
index += hangulLength - 1
if (isColourCode(c)) {
if (c == 0x100000) {
renderCol = -1
} }
else { else {
renderCol = getColour(c) try {
val posY = posYbuffer[index].flipY() +
if (sheetID == SHEET_UNIHAN) // evil exceptions
offsetUnihan
else if (sheetID == SHEET_CUSTOM_SYM)
offsetCustomSym
else 0
val posX = posXbuffer[index]
val texture = sheets[sheetID].get(sheetX, sheetY)
linotypePixmap.drawPixmap(texture, posX, posY + pixmapOffsetY, renderCol)
}
catch (noSuchGlyph: ArrayIndexOutOfBoundsException) {
}
} }
index++
} }
else if (isCharsetOverride(c)) { catch (e: NullPointerException) {
charsetOverride = c - CHARSET_OVERRIDE_DEFAULT System.err.println("Shit hit the multithreaded fan")
e.printStackTrace()
break
} }
else if (sheetID == SHEET_HANGUL) {
// Flookahead for {I, P, F}
val cNext = if (index + 1 < textBuffer.size) textBuffer[index + 1] else 0
val cNextNext = if (index + 2 < textBuffer.size) textBuffer[index + 2] else 0
val hangulLength = if (isHangulJongseong(cNextNext) && isHangulJungseong(cNext))
3
else if (isHangulJungseong(cNext))
2
else
1
val (indices, rows) = toHangulIndexAndRow(c, cNext, cNextNext)
val (indexCho, indexJung, indexJong) = indices
val (choRow, jungRow, jongRow) = rows
val hangulSheet = sheets[SHEET_HANGUL]
val choTex = hangulSheet.get(indexCho, choRow)
val jungTex = hangulSheet.get(indexJung, jungRow)
val jongTex = hangulSheet.get(indexJong, jongRow)
linotypePixmap.drawPixmap(choTex, posXbuffer[index], pixmapOffsetY, renderCol)
linotypePixmap.drawPixmap(jungTex, posXbuffer[index], pixmapOffsetY, renderCol)
linotypePixmap.drawPixmap(jongTex, posXbuffer[index], pixmapOffsetY, renderCol)
index += hangulLength - 1
}
else {
try {
val posY = posYbuffer[index].flipY() +
if (sheetID == SHEET_UNIHAN) // evil exceptions
offsetUnihan
else if (sheetID == SHEET_CUSTOM_SYM)
offsetCustomSym
else 0
val posX = posXbuffer[index]
val texture = sheets[sheetID].get(sheetX, sheetY)
linotypePixmap.drawPixmap(texture, posX, posY + pixmapOffsetY, renderCol)
}
catch (noSuchGlyph: ArrayIndexOutOfBoundsException) {
}
}
index++
} }
@@ -846,166 +853,169 @@ class TerrarumSansBitmap(
// persisting value. the value is set a few characters before the actual usage // persisting value. the value is set a few characters before the actual usage
var extraWidth = 0 var extraWidth = 0
for (charIndex in 0 until posXbuffer.size - 1) { try {
if (charIndex > 0) { for (charIndex in 0 until posXbuffer.size - 1) {
// nonDiacriticCounter allows multiple diacritics if (charIndex > 0) {
// nonDiacriticCounter allows multiple diacritics
val thisChar = str[charIndex] val thisChar = str[charIndex]
if (glyphProps[thisChar] == null && errorOnUnknownChar) { if (glyphProps[thisChar] == null && errorOnUnknownChar) {
val errorGlyphSB = StringBuilder() val errorGlyphSB = StringBuilder()
Character.toChars(thisChar).forEach { errorGlyphSB.append(it) } Character.toChars(thisChar).forEach { errorGlyphSB.append(it) }
throw InternalError("No GlyphProps for char '$errorGlyphSB' " + throw InternalError("No GlyphProps for char '$errorGlyphSB' " +
"(${thisChar.charInfo()})") "(${thisChar.charInfo()})")
} }
val thisProp = glyphProps[thisChar] ?: nullProp val thisProp = glyphProps[thisChar] ?: nullProp
val lastNonDiacriticChar = str[nonDiacriticCounter] val lastNonDiacriticChar = str[nonDiacriticCounter]
val itsProp = glyphProps[lastNonDiacriticChar] ?: nullProp val itsProp = glyphProps[lastNonDiacriticChar] ?: nullProp
val kerning = getKerning(lastNonDiacriticChar, thisChar) val kerning = getKerning(lastNonDiacriticChar, thisChar)
//dbgprn("char: ${thisChar.charInfo()}\nproperties: $thisProp")
var alignmentOffset = when (thisProp.alignWhere) {
GlyphProps.ALIGN_LEFT -> 0
GlyphProps.ALIGN_RIGHT -> thisProp.width - W_VAR_INIT
GlyphProps.ALIGN_CENTRE -> Math.ceil((thisProp.width - W_VAR_INIT) / 2.0).toInt()
else -> 0 // implies "diacriticsBeforeGlyph = true"
}
// shoehorn the wider-hangul-width thingamajig
// widen only when the next hangul char is not "jungseongWide"
// (애 in "애슬론" should not be widened)
val thisHangulJungseongIndex = toHangulJungseongIndex(thisChar)
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
)) {
//dbgprn("char: ${thisChar.charInfo()}\nproperties: $thisProp") //dbgprn("char: ${thisChar.charInfo()}\nproperties: $thisProp")
//dbgprn("${thisChar.charInfo()} ${str.getOrNull(charIndex + 2)?.charInfo()} ${str.getOrNull(charIndex + 3)?.charInfo()}")
extraWidth += 1
}
if (isHangul(thisChar) && !isHangulChoseong(thisChar) && !isHangulCompat(thisChar)) { var alignmentOffset = when (thisProp.alignWhere) {
posXbuffer[charIndex] = posXbuffer[nonDiacriticCounter] GlyphProps.ALIGN_LEFT -> 0
} GlyphProps.ALIGN_RIGHT -> thisProp.width - W_VAR_INIT
else if (thisProp.writeOnTop < 0) { GlyphProps.ALIGN_CENTRE -> Math.ceil((thisProp.width - W_VAR_INIT) / 2.0).toInt()
posXbuffer[charIndex] = -thisProp.nudgeX + else -> 0 // implies "diacriticsBeforeGlyph = true"
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
}
nonDiacriticCounter = charIndex
stackUpwardCounter = 0
stackDownwardCounter = 0
extraWidth = thisProp.nudgeX // NOTE: sign is flipped!
}
// FIXME HACK: using 0th diacritics' X-anchor pos as a type selector
/*else if (thisProp.writeOnTop && thisProp.diacriticsAnchors[0].x == GlyphProps.DIA_JOINER) {
posXbuffer[charIndex] = when (itsProp.alignWhere) {
GlyphProps.ALIGN_RIGHT ->
posXbuffer[nonDiacriticCounter] + W_VAR_INIT + alignmentOffset
//GlyphProps.ALIGN_CENTRE ->
// posXbuffer[nonDiacriticCounter] + HALF_VAR_INIT + itsProp.width + alignmentOffset
else ->
posXbuffer[nonDiacriticCounter] + itsProp.width + alignmentOffset
}
}*/
else {
// set X pos according to alignment information
posXbuffer[charIndex] = when (thisProp.alignWhere) {
GlyphProps.ALIGN_LEFT, GlyphProps.ALIGN_BEFORE -> posXbuffer[nonDiacriticCounter]
GlyphProps.ALIGN_RIGHT -> {
posXbuffer[nonDiacriticCounter] - (W_VAR_INIT - itsProp.width)
}
GlyphProps.ALIGN_CENTRE -> {
val alignXPos = if (itsProp.diacriticsAnchors[0].x == 0) itsProp.width.div(2) else itsProp.diacriticsAnchors[0].x
if (itsProp.alignWhere == GlyphProps.ALIGN_RIGHT) {
posXbuffer[nonDiacriticCounter] + alignXPos + (itsProp.width + 1).div(2)
}
else {
posXbuffer[nonDiacriticCounter] + alignXPos - HALF_VAR_INIT
}
}
else -> throw InternalError("Unsupported alignment: ${thisProp.alignWhere}")
} }
// set Y pos according to diacritics position // shoehorn the wider-hangul-width thingamajig
if (thisProp.alignWhere == GlyphProps.ALIGN_CENTRE) { // widen only when the next hangul char is not "jungseongWide"
when (thisProp.stackWhere) { // (애 in "애슬론" should not be widened)
GlyphProps.STACK_DOWN -> { val thisHangulJungseongIndex = toHangulJungseongIndex(thisChar)
posYbuffer[charIndex] = H_DIACRITICS * stackDownwardCounter val nextHangulJungseong1 = toHangulJungseongIndex(str.getOrNull(charIndex + 2) ?: 0) ?: -1
stackDownwardCounter++ val nextHangulJungseong2 = toHangulJungseongIndex(str.getOrNull(charIndex + 3) ?: 0) ?: -1
} if (isHangulJungseong(thisChar) && thisHangulJungseongIndex in hangulPeaksWithExtraWidth && (
GlyphProps.STACK_UP -> { nextHangulJungseong1 !in jungseongWide ||
posYbuffer[charIndex] = -H_DIACRITICS * stackUpwardCounter nextHangulJungseong2 !in jungseongWide
)) {
//dbgprn("char: ${thisChar.charInfo()}\nproperties: $thisProp")
//dbgprn("${thisChar.charInfo()} ${str.getOrNull(charIndex + 2)?.charInfo()} ${str.getOrNull(charIndex + 3)?.charInfo()}")
extraWidth += 1
}
// shift down on lowercase if applicable
if (getSheetType(thisChar) in autoShiftDownOnLowercase && if (isHangul(thisChar) && !isHangulChoseong(thisChar) && !isHangulCompat(thisChar)) {
lastNonDiacriticChar.isLowHeight()) { posXbuffer[charIndex] = posXbuffer[nonDiacriticCounter]
//dbgprn("AAARRRRHHHH for character ${thisChar.toHex()}") }
//dbgprn("lastNonDiacriticChar: ${lastNonDiacriticChar.toHex()}") else if (thisProp.writeOnTop < 0) {
//dbgprn("cond: ${thisProp.alignXPos == GlyphProps.DIA_OVERLAY}, charIndex: $charIndex") posXbuffer[charIndex] = -thisProp.nudgeX +
if (thisProp.diacriticsAnchors[0].x == GlyphProps.DIA_OVERLAY) when (itsProp.alignWhere) {
posYbuffer[charIndex] -= H_OVERLAY_LOWERCASE_SHIFTDOWN * (!flipY).toSign() // if minus-assign doesn't work, try plus-assign GlyphProps.ALIGN_RIGHT ->
else posXbuffer[nonDiacriticCounter] + W_VAR_INIT + alignmentOffset + interchar + kerning + extraWidth
posYbuffer[charIndex] -= H_STACKUP_LOWERCASE_SHIFTDOWN * (!flipY).toSign() // if minus-assign doesn't work, try plus-assign GlyphProps.ALIGN_CENTRE ->
posXbuffer[nonDiacriticCounter] + HALF_VAR_INIT + itsProp.width + alignmentOffset + interchar + kerning + extraWidth
else ->
posXbuffer[nonDiacriticCounter] + itsProp.width + alignmentOffset + interchar + kerning + extraWidth
} }
stackUpwardCounter++ nonDiacriticCounter = charIndex
stackUpwardCounter = 0
stackDownwardCounter = 0
extraWidth = thisProp.nudgeX // NOTE: sign is flipped!
}
// FIXME HACK: using 0th diacritics' X-anchor pos as a type selector
/*else if (thisProp.writeOnTop && thisProp.diacriticsAnchors[0].x == GlyphProps.DIA_JOINER) {
posXbuffer[charIndex] = when (itsProp.alignWhere) {
GlyphProps.ALIGN_RIGHT ->
posXbuffer[nonDiacriticCounter] + W_VAR_INIT + alignmentOffset
//GlyphProps.ALIGN_CENTRE ->
// posXbuffer[nonDiacriticCounter] + HALF_VAR_INIT + itsProp.width + alignmentOffset
else ->
posXbuffer[nonDiacriticCounter] + itsProp.width + alignmentOffset
}
}*/
else {
// set X pos according to alignment information
posXbuffer[charIndex] = when (thisProp.alignWhere) {
GlyphProps.ALIGN_LEFT, GlyphProps.ALIGN_BEFORE -> posXbuffer[nonDiacriticCounter]
GlyphProps.ALIGN_RIGHT -> {
posXbuffer[nonDiacriticCounter] - (W_VAR_INIT - itsProp.width)
} }
GlyphProps.STACK_UP_N_DOWN -> { GlyphProps.ALIGN_CENTRE -> {
posYbuffer[charIndex] = H_DIACRITICS * stackDownwardCounter val alignXPos = if (itsProp.diacriticsAnchors[0].x == 0) itsProp.width.div(2) else itsProp.diacriticsAnchors[0].x
stackDownwardCounter++
posYbuffer[charIndex] = -H_DIACRITICS * stackUpwardCounter if (itsProp.alignWhere == GlyphProps.ALIGN_RIGHT) {
stackUpwardCounter++ posXbuffer[nonDiacriticCounter] + alignXPos + (itsProp.width + 1).div(2)
}
else {
posXbuffer[nonDiacriticCounter] + alignXPos - HALF_VAR_INIT
}
}
else -> throw InternalError("Unsupported alignment: ${thisProp.alignWhere}")
}
// set Y pos according to diacritics position
if (thisProp.alignWhere == GlyphProps.ALIGN_CENTRE) {
when (thisProp.stackWhere) {
GlyphProps.STACK_DOWN -> {
posYbuffer[charIndex] = H_DIACRITICS * stackDownwardCounter
stackDownwardCounter++
}
GlyphProps.STACK_UP -> {
posYbuffer[charIndex] = -H_DIACRITICS * stackUpwardCounter
// 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 (thisProp.diacriticsAnchors[0].x == 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++
}
GlyphProps.STACK_UP_N_DOWN -> {
posYbuffer[charIndex] = H_DIACRITICS * stackDownwardCounter
stackDownwardCounter++
posYbuffer[charIndex] = -H_DIACRITICS * stackUpwardCounter
stackUpwardCounter++
}
// for BEFORE_N_AFTER, do nothing in here
} }
// for BEFORE_N_AFTER, do nothing in here
} }
} }
} }
} }
}
// fill the last of the posXbuffer // fill the last of the posXbuffer
if (str.isNotEmpty()) { if (str.isNotEmpty()) {
val lastCharProp = glyphProps[str.last()] val lastCharProp = glyphProps[str.last()]
val penultCharProp = glyphProps[str[nonDiacriticCounter]] ?: val penultCharProp = glyphProps[str[nonDiacriticCounter]] ?:
(if (errorOnUnknownChar) throw throw InternalError("No GlyphProps for char '${str[nonDiacriticCounter]}' " + (if (errorOnUnknownChar) throw throw InternalError("No GlyphProps for char '${str[nonDiacriticCounter]}' " +
"(${str[nonDiacriticCounter].charInfo()})") else nullProp) "(${str[nonDiacriticCounter].charInfo()})") else nullProp)
posXbuffer[posXbuffer.lastIndex] = 1 + posXbuffer[posXbuffer.lastIndex - 1] + // adding 1 to house the shadow posXbuffer[posXbuffer.lastIndex] = 1 + posXbuffer[posXbuffer.lastIndex - 1] + // adding 1 to house the shadow
if (lastCharProp != null && lastCharProp.writeOnTop >= 0) { if (lastCharProp != null && lastCharProp.writeOnTop >= 0) {
val realDiacriticWidth = if (lastCharProp.alignWhere == GlyphProps.ALIGN_CENTRE) { val realDiacriticWidth = if (lastCharProp.alignWhere == GlyphProps.ALIGN_CENTRE) {
(lastCharProp.width).div(2) + penultCharProp.diacriticsAnchors[0].x (lastCharProp.width).div(2) + penultCharProp.diacriticsAnchors[0].x
} }
else if (lastCharProp.alignWhere == GlyphProps.ALIGN_RIGHT) { else if (lastCharProp.alignWhere == GlyphProps.ALIGN_RIGHT) {
(lastCharProp.width) + penultCharProp.diacriticsAnchors[0].x (lastCharProp.width) + penultCharProp.diacriticsAnchors[0].x
} }
else 0 else 0
maxOf(penultCharProp.width, realDiacriticWidth) maxOf(penultCharProp.width, realDiacriticWidth)
} }
else { else {
(lastCharProp?.width ?: 0) (lastCharProp?.width ?: 0)
} }
} }
else { else {
posXbuffer[0] = 0 posXbuffer[0] = 0
}
} }
catch (e: NullPointerException) {}
return posXbuffer to posYbuffer return posXbuffer to posYbuffer
} }
@@ -1345,9 +1355,15 @@ class TerrarumSansBitmap(
val hashPrime = 1099511628211L val hashPrime = 1099511628211L
var hashAccumulator = hashBasis var hashAccumulator = hashBasis
this.forEach { try {
hashAccumulator = hashAccumulator xor it.toLong() this.forEach {
hashAccumulator *= hashPrime hashAccumulator = hashAccumulator xor it.toLong()
hashAccumulator *= hashPrime
}
}
catch (e: NullPointerException) {
System.err.println("CodepointSequence is null?!")
e.printStackTrace()
} }
return hashAccumulator return hashAccumulator

View File

@@ -278,8 +278,8 @@ class TerrarumTypewriterBitmap(
private val pixmapOffsetY = 10 private val pixmapOffsetY = 10
private val linotypePad = 16 private val linotypePad = 16
private var flagFirstRun = true private var flagFirstRun = true
private var textBuffer = CodepointSequence(256) private @Volatile var textBuffer = CodepointSequence(256)
private lateinit var tempLinotype: Texture private @Volatile lateinit var tempLinotype: Texture
private var nullProp = GlyphProps(15) private var nullProp = GlyphProps(15)
@@ -333,38 +333,42 @@ class TerrarumTypewriterBitmap(
var index = 0 var index = 0
while (index <= textBuffer.lastIndex) { while (index <= textBuffer.lastIndex) {
val c = textBuffer[index] try {
val sheetID = getSheetType(c) val c = textBuffer[index]
val (sheetX, sheetY) = val sheetID = getSheetType(c)
if (index == 0) getSheetwisePosition(0, c) val (sheetX, sheetY) =
else getSheetwisePosition(textBuffer[index - 1], c) if (index == 0) getSheetwisePosition(0, c)
val hash = getHash(c) // to be used to simulate printing irregularity else getSheetwisePosition(textBuffer[index - 1], c)
val hash = getHash(c) // to be used to simulate printing irregularity
if (TerrarumSansBitmap.isColourCode(c)) { if (TerrarumSansBitmap.isColourCode(c)) {
if (c == 0x100000) { if (c == 0x100000) {
renderCol = -1 renderCol = -1
} } else {
else { renderCol = getColour(c)
renderCol = getColour(c)
}
}
else {
try {
val posY = posYbuffer[index].flipY()
val posX = posXbuffer[index]
val texture = sheets[sheetID]?.get(sheetX, sheetY)
texture?.let {
linotypePixmap.drawPixmap(it, posX + linotypePad, posY + pixmapOffsetY, renderCol)
} }
} else {
try {
val posY = posYbuffer[index].flipY()
val posX = posXbuffer[index]
val texture = sheets[sheetID]?.get(sheetX, sheetY)
texture?.let {
linotypePixmap.drawPixmap(it, posX + linotypePad, posY + pixmapOffsetY, renderCol)
}
} catch (noSuchGlyph: ArrayIndexOutOfBoundsException) {
}
} }
catch (noSuchGlyph: ArrayIndexOutOfBoundsException) {
}
index++
}
catch (e: NullPointerException) {
System.err.println("Shit hit the multithreaded fan")
e.printStackTrace()
break
} }
index++
} }
tempLinotype = Texture(linotypePixmap) tempLinotype = Texture(linotypePixmap)
@@ -417,144 +421,147 @@ class TerrarumTypewriterBitmap(
// persisting value. the value is set a few characters before the actual usage // persisting value. the value is set a few characters before the actual usage
var extraWidth = 0 var extraWidth = 0
for (charIndex in 0 until posXbuffer.size - 1) { try {
if (charIndex > 0) { for (charIndex in 0 until posXbuffer.size - 1) {
// nonDiacriticCounter allows multiple diacritics if (charIndex > 0) {
// nonDiacriticCounter allows multiple diacritics
val thisChar = str[charIndex] val thisChar = str[charIndex]
if (glyphProps[thisChar] == null && errorOnUnknownChar) { if (glyphProps[thisChar] == null && errorOnUnknownChar) {
val errorGlyphSB = StringBuilder() val errorGlyphSB = StringBuilder()
Character.toChars(thisChar).forEach { errorGlyphSB.append(it) } Character.toChars(thisChar).forEach { errorGlyphSB.append(it) }
throw InternalError("No GlyphProps for char '$errorGlyphSB' " +
"(${thisChar.charInfo()})")
}
val thisProp = glyphProps[thisChar] ?: nullProp
val lastNonDiacriticChar = str[nonDiacriticCounter]
val itsProp = glyphProps[lastNonDiacriticChar] ?: nullProp
val kerning = 0
//println("char: ${thisChar.charInfo()}\nproperties: $thisProp")
var alignmentOffset = when (thisProp.alignWhere) {
GlyphProps.ALIGN_LEFT -> 0
GlyphProps.ALIGN_RIGHT -> thisProp.width - TerrarumSansBitmap.W_VAR_INIT
GlyphProps.ALIGN_CENTRE -> Math.ceil((thisProp.width - TerrarumSansBitmap.W_VAR_INIT) / 2.0).toInt()
else -> 0 // implies "diacriticsBeforeGlyph = true"
}
if (thisProp.writeOnTop < 0) {
posXbuffer[charIndex] = -thisProp.nudgeX +
when (itsProp.alignWhere) {
GlyphProps.ALIGN_RIGHT ->
posXbuffer[nonDiacriticCounter] + TerrarumSansBitmap.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
stackUpwardCounter = 0
stackDownwardCounter = 0
extraWidth = thisProp.nudgeX // NOTE: sign is flipped!
}
/*else if (thisProp.writeOnTop >= 0 && thisProp.diacriticsAnchors[0].x == GlyphProps.DIA_JOINER) {
posXbuffer[charIndex] = when (itsProp.alignWhere) {
GlyphProps.ALIGN_RIGHT ->
posXbuffer[nonDiacriticCounter] + TerrarumSansBitmap.W_VAR_INIT + alignmentOffset
//GlyphProps.ALIGN_CENTRE ->
// posXbuffer[nonDiacriticCounter] + HALF_VAR_INIT + itsProp.width + alignmentOffset
else ->
posXbuffer[nonDiacriticCounter] + itsProp.width + alignmentOffset
throw InternalError("No GlyphProps for char '$errorGlyphSB' " +
"(${thisChar.charInfo()})")
} }
}*/ val thisProp = glyphProps[thisChar] ?: nullProp
else { val lastNonDiacriticChar = str[nonDiacriticCounter]
// set X pos according to alignment information val itsProp = glyphProps[lastNonDiacriticChar] ?: nullProp
posXbuffer[charIndex] = when (thisProp.alignWhere) { val kerning = 0
GlyphProps.ALIGN_LEFT, GlyphProps.ALIGN_BEFORE -> posXbuffer[nonDiacriticCounter]
GlyphProps.ALIGN_RIGHT -> {
posXbuffer[nonDiacriticCounter] - (TerrarumSansBitmap.W_VAR_INIT - itsProp.width)
}
GlyphProps.ALIGN_CENTRE -> {
val alignXPos = if (itsProp.diacriticsAnchors[0].x == 0) itsProp.width.div(2) else itsProp.diacriticsAnchors[0].x
if (itsProp.alignWhere == GlyphProps.ALIGN_RIGHT) {
posXbuffer[nonDiacriticCounter] + alignXPos + (itsProp.width + 1).div(2) //println("char: ${thisChar.charInfo()}\nproperties: $thisProp")
}
else {
posXbuffer[nonDiacriticCounter] + alignXPos - HALF_VAR_INIT var alignmentOffset = when (thisProp.alignWhere) {
} GlyphProps.ALIGN_LEFT -> 0
} GlyphProps.ALIGN_RIGHT -> thisProp.width - TerrarumSansBitmap.W_VAR_INIT
else -> throw InternalError("Unsupported alignment: ${thisProp.alignWhere}") GlyphProps.ALIGN_CENTRE -> Math.ceil((thisProp.width - TerrarumSansBitmap.W_VAR_INIT) / 2.0).toInt()
else -> 0 // implies "diacriticsBeforeGlyph = true"
} }
// set Y pos according to diacritics position if (thisProp.writeOnTop < 0) {
if (thisProp.alignWhere == GlyphProps.ALIGN_CENTRE) { posXbuffer[charIndex] = -thisProp.nudgeX +
when (thisProp.stackWhere) { when (itsProp.alignWhere) {
GlyphProps.STACK_DOWN -> { GlyphProps.ALIGN_RIGHT ->
posYbuffer[charIndex] = TerrarumSansBitmap.H_DIACRITICS * stackDownwardCounter posXbuffer[nonDiacriticCounter] + TerrarumSansBitmap.W_VAR_INIT + alignmentOffset + interchar + kerning + extraWidth
stackDownwardCounter++ GlyphProps.ALIGN_CENTRE ->
} posXbuffer[nonDiacriticCounter] + HALF_VAR_INIT + itsProp.width + alignmentOffset + interchar + kerning + extraWidth
GlyphProps.STACK_UP -> { else ->
posYbuffer[charIndex] = -TerrarumSansBitmap.H_DIACRITICS * stackUpwardCounter posXbuffer[nonDiacriticCounter] + itsProp.width + alignmentOffset + interchar + kerning + extraWidth
}
// shift down on lowercase if applicable nonDiacriticCounter = charIndex
/*if (getSheetType(thisChar) in TerrarumSansBitmap.autoShiftDownOnLowercase &&
lastNonDiacriticChar.isLowHeight()) {
//println("AAARRRRHHHH for character ${thisChar.toHex()}")
//println("lastNonDiacriticChar: ${lastNonDiacriticChar.toHex()}")
//println("cond: ${thisProp.alignXPos == GlyphProps.DIA_OVERLAY}, charIndex: $charIndex")
if (thisProp.alignXPos == GlyphProps.DIA_OVERLAY)
posYbuffer[charIndex] -= TerrarumSansBitmap.H_OVERLAY_LOWERCASE_SHIFTDOWN // if minus-assign doesn't work, try plus-assign
else
posYbuffer[charIndex] -= TerrarumSansBitmap.H_STACKUP_LOWERCASE_SHIFTDOWN // if minus-assign doesn't work, try plus-assign
}*/
stackUpwardCounter++ stackUpwardCounter = 0
stackDownwardCounter = 0
extraWidth = thisProp.nudgeX // NOTE: sign is flipped!
}
/*else if (thisProp.writeOnTop >= 0 && thisProp.diacriticsAnchors[0].x == GlyphProps.DIA_JOINER) {
posXbuffer[charIndex] = when (itsProp.alignWhere) {
GlyphProps.ALIGN_RIGHT ->
posXbuffer[nonDiacriticCounter] + TerrarumSansBitmap.W_VAR_INIT + alignmentOffset
//GlyphProps.ALIGN_CENTRE ->
// posXbuffer[nonDiacriticCounter] + HALF_VAR_INIT + itsProp.width + alignmentOffset
else ->
posXbuffer[nonDiacriticCounter] + itsProp.width + alignmentOffset
}
}*/
else {
// set X pos according to alignment information
posXbuffer[charIndex] = when (thisProp.alignWhere) {
GlyphProps.ALIGN_LEFT, GlyphProps.ALIGN_BEFORE -> posXbuffer[nonDiacriticCounter]
GlyphProps.ALIGN_RIGHT -> {
posXbuffer[nonDiacriticCounter] - (TerrarumSansBitmap.W_VAR_INIT - itsProp.width)
} }
GlyphProps.STACK_UP_N_DOWN -> { GlyphProps.ALIGN_CENTRE -> {
posYbuffer[charIndex] = TerrarumSansBitmap.H_DIACRITICS * stackDownwardCounter val alignXPos = if (itsProp.diacriticsAnchors[0].x == 0) itsProp.width.div(2) else itsProp.diacriticsAnchors[0].x
stackDownwardCounter++
posYbuffer[charIndex] = -TerrarumSansBitmap.H_DIACRITICS * stackUpwardCounter if (itsProp.alignWhere == GlyphProps.ALIGN_RIGHT) {
stackUpwardCounter++ posXbuffer[nonDiacriticCounter] + alignXPos + (itsProp.width + 1).div(2)
}
else {
posXbuffer[nonDiacriticCounter] + alignXPos - HALF_VAR_INIT
}
}
else -> throw InternalError("Unsupported alignment: ${thisProp.alignWhere}")
}
// set Y pos according to diacritics position
if (thisProp.alignWhere == GlyphProps.ALIGN_CENTRE) {
when (thisProp.stackWhere) {
GlyphProps.STACK_DOWN -> {
posYbuffer[charIndex] = TerrarumSansBitmap.H_DIACRITICS * stackDownwardCounter
stackDownwardCounter++
}
GlyphProps.STACK_UP -> {
posYbuffer[charIndex] = -TerrarumSansBitmap.H_DIACRITICS * stackUpwardCounter
// shift down on lowercase if applicable
/*if (getSheetType(thisChar) in TerrarumSansBitmap.autoShiftDownOnLowercase &&
lastNonDiacriticChar.isLowHeight()) {
//println("AAARRRRHHHH for character ${thisChar.toHex()}")
//println("lastNonDiacriticChar: ${lastNonDiacriticChar.toHex()}")
//println("cond: ${thisProp.alignXPos == GlyphProps.DIA_OVERLAY}, charIndex: $charIndex")
if (thisProp.alignXPos == GlyphProps.DIA_OVERLAY)
posYbuffer[charIndex] -= TerrarumSansBitmap.H_OVERLAY_LOWERCASE_SHIFTDOWN // if minus-assign doesn't work, try plus-assign
else
posYbuffer[charIndex] -= TerrarumSansBitmap.H_STACKUP_LOWERCASE_SHIFTDOWN // if minus-assign doesn't work, try plus-assign
}*/
stackUpwardCounter++
}
GlyphProps.STACK_UP_N_DOWN -> {
posYbuffer[charIndex] = TerrarumSansBitmap.H_DIACRITICS * stackDownwardCounter
stackDownwardCounter++
posYbuffer[charIndex] = -TerrarumSansBitmap.H_DIACRITICS * stackUpwardCounter
stackUpwardCounter++
}
// for BEFORE_N_AFTER, do nothing in here
} }
// for BEFORE_N_AFTER, do nothing in here
} }
} }
} }
} }
}
// fill the last of the posXbuffer // fill the last of the posXbuffer
if (str.isNotEmpty()) { if (str.isNotEmpty()) {
val lastCharProp = glyphProps[str.last()] val lastCharProp = glyphProps[str.last()]
val penultCharProp = glyphProps[str[nonDiacriticCounter]]!! val penultCharProp = glyphProps[str[nonDiacriticCounter]]!!
posXbuffer[posXbuffer.lastIndex] = 1 + posXbuffer[posXbuffer.lastIndex - 1] + // adding 1 to house the shadow posXbuffer[posXbuffer.lastIndex] = 1 + posXbuffer[posXbuffer.lastIndex - 1] + // adding 1 to house the shadow
if (lastCharProp != null && lastCharProp.writeOnTop >= 0) { if (lastCharProp != null && lastCharProp.writeOnTop >= 0) {
val realDiacriticWidth = if (lastCharProp.alignWhere == GlyphProps.ALIGN_CENTRE) { val realDiacriticWidth = if (lastCharProp.alignWhere == GlyphProps.ALIGN_CENTRE) {
(lastCharProp.width).div(2) + penultCharProp.diacriticsAnchors[0].x (lastCharProp.width).div(2) + penultCharProp.diacriticsAnchors[0].x
} }
else if (lastCharProp.alignWhere == GlyphProps.ALIGN_RIGHT) { else if (lastCharProp.alignWhere == GlyphProps.ALIGN_RIGHT) {
(lastCharProp.width) + penultCharProp.diacriticsAnchors[0].x (lastCharProp.width) + penultCharProp.diacriticsAnchors[0].x
} }
else 0 else 0
maxOf(penultCharProp.width, realDiacriticWidth) maxOf(penultCharProp.width, realDiacriticWidth)
} }
else { else {
(lastCharProp?.width ?: 0) (lastCharProp?.width ?: 0)
} }
} }
else { else {
posXbuffer[0] = 0 posXbuffer[0] = 0
}
} }
catch (e: NullPointerException) {}
return posXbuffer to posYbuffer return posXbuffer to posYbuffer
} }
@@ -609,14 +616,15 @@ class TerrarumTypewriterBitmap(
val hashPrime = 1099511628211L val hashPrime = 1099511628211L
var hashAccumulator = hashBasis var hashAccumulator = hashBasis
if (this != null) { try {
this.forEach { this.forEach {
hashAccumulator = hashAccumulator xor it.toLong() hashAccumulator = hashAccumulator xor it.toLong()
hashAccumulator *= hashPrime hashAccumulator *= hashPrime
} }
} }
else { catch (e: NullPointerException) {
System.err.println("CodepointSequence is null?!") System.err.println("CodepointSequence is null?!")
e.printStackTrace()
} }
return hashAccumulator return hashAccumulator