Skip to content

Commit 3be531a

Browse files
committed
Change the handling of out-of-bounds canvas
1 parent cdc86fe commit 3be531a

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
@@ -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,23 @@ internal class TextSurface(
3331
override var translationX = 0
3432
override var translationY = 0
3533

36-
private val rows = Array(height) { Array(width) { TextPixel(' ') } }
34+
private val rows = Array(height) { Array(width) { newBlankPixel } }
3735

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

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

4449
val rowPixels = rows[row]
45-
var lastPixel = blankPixel
50+
var lastPixel = reusableBlankPixel
4651
for (columnIndex in 0 until width) {
4752
val pixel = rowPixels[columnIndex]
4853

@@ -153,6 +158,23 @@ internal class TextSurface(
153158
}
154159
}
155160

161+
/**
162+
* Returns always a new blank [TextPixel].
163+
*/
164+
private val newBlankPixel: TextPixel get() = TextPixel(' ')
165+
166+
/**
167+
* It is used in places where it is important that the [TextPixel]
168+
* has its original state and **will not change**.
169+
*/
170+
private val reusableBlankPixel: TextPixel = newBlankPixel
171+
172+
/**
173+
* It is used in places where the [TextPixel] state is not important
174+
* and it can change.
175+
*/
176+
private val reusableDirtyPixel: TextPixel = newBlankPixel
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)