Skip to content

Commit 94800f1

Browse files
committed
Change the handling of out-of-bounds canvas
1 parent 6efdb15 commit 94800f1

File tree

2 files changed

+336
-66
lines changed
  • mosaic-runtime/src

2 files changed

+336
-66
lines changed

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

+27-5
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ internal interface TextCanvas {
2020
operator fun get(row: Int, column: Int): TextPixel
2121
}
2222

23-
private val blankPixel = TextPixel(' ')
24-
2523
internal class TextSurface(
2624
override val width: Int,
2725
override val height: Int,
@@ -30,16 +28,23 @@ internal class TextSurface(
3028
override var translationX = 0
3129
override var translationY = 0
3230

33-
private val rows = Array(height) { Array(width) { TextPixel(' ') } }
31+
private val rows = Array(height) { Array(width) { newBlankPixel } }
3432

35-
override operator fun get(row: Int, column: Int) = rows[translationY + row][translationX + column]
33+
override operator fun get(row: Int, column: Int): TextPixel {
34+
val x = translationX + column
35+
val y = translationY + row
36+
if (x >= width || y >= height || x < 0 || y < 0) {
37+
return reusableDirtyPixel
38+
}
39+
return rows[y][x]
40+
}
3641

3742
fun appendRowTo(appendable: Appendable, row: Int) {
3843
// Reused heap allocation for building ANSI attributes inside the loop.
3944
val attributes = mutableListOf<Int>()
4045

4146
val rowPixels = rows[row]
42-
var lastPixel = blankPixel
47+
var lastPixel = reusableBlankPixel
4348
for (columnIndex in 0 until width) {
4449
val pixel = rowPixels[columnIndex]
4550

@@ -150,6 +155,23 @@ internal class TextSurface(
150155
}
151156
}
152157

158+
/**
159+
* Returns always a new blank [TextPixel].
160+
*/
161+
private val newBlankPixel: TextPixel get() = TextPixel(' ')
162+
163+
/**
164+
* It is used in places where it is important that the [TextPixel]
165+
* has its original state and **will not change**.
166+
*/
167+
private val reusableBlankPixel: TextPixel = newBlankPixel
168+
169+
/**
170+
* It is used in places where the [TextPixel] state is not important
171+
* and it can change.
172+
*/
173+
private val reusableDirtyPixel: TextPixel = newBlankPixel
174+
153175
internal class TextPixel(var value: String) {
154176
var background: Color? = null
155177
var foreground: Color? = null

0 commit comments

Comments
 (0)