Skip to content

Commit bafdd41

Browse files
committed
Change the handling of out-of-bounds canvas
1 parent 49cfda2 commit bafdd41

File tree

2 files changed

+353
-79
lines changed
  • mosaic-runtime/src

2 files changed

+353
-79
lines changed

mosaic-runtime/src/commonMain/kotlin/com/jakewharton/mosaic/canvas.kt

+28-6
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ internal interface TextCanvas {
2323
operator fun get(row: Int, column: Int): TextPixel
2424
}
2525

26-
private val blankPixel = TextPixel(' ')
27-
2826
internal class TextSurface(
2927
override val width: Int,
3028
override val height: Int,
@@ -33,16 +31,35 @@ internal class TextSurface(
3331
override var translationX = 0
3432
override var translationY = 0
3533

36-
private val rows = Array(height) { Array(width) { TextPixel(' ') } }
37-
38-
override operator fun get(row: Int, column: Int) = rows[translationY + row][translationX + column]
34+
/**
35+
* It is used in places where the [TextPixel] state is not important
36+
* and it can change.
37+
*/
38+
private val reusableDirtyPixel: TextPixel = newBlankPixel
39+
40+
/**
41+
* It is used in places where it is important that the [TextPixel]
42+
* has its original state and **will not change**.
43+
*/
44+
private val reusableBlankPixel: TextPixel = newBlankPixel
45+
46+
private val rows = Array(height) { Array(width) { newBlankPixel } }
47+
48+
override operator fun get(row: Int, column: Int): TextPixel {
49+
val x = translationX + column
50+
val y = translationY + row
51+
if (x >= width || y >= height || x < 0 || y < 0) {
52+
return reusableDirtyPixel
53+
}
54+
return rows[y][x]
55+
}
3956

4057
fun appendRowTo(appendable: Appendable, row: Int) {
4158
// Reused heap allocation for building ANSI attributes inside the loop.
4259
val attributes = mutableListOf<Int>()
4360

4461
val rowPixels = rows[row]
45-
var lastPixel = blankPixel
62+
var lastPixel = reusableBlankPixel
4663
for (columnIndex in 0 until width) {
4764
val pixel = rowPixels[columnIndex]
4865

@@ -153,6 +170,11 @@ internal class TextSurface(
153170
}
154171
}
155172

173+
/**
174+
* Returns always a new blank [TextPixel].
175+
*/
176+
private inline val newBlankPixel: TextPixel get() = TextPixel(' ')
177+
156178
internal class TextPixel(var codePoint: Int) {
157179
var background: Color = Color.Unspecified
158180
var foreground: Color = Color.Unspecified

0 commit comments

Comments
 (0)