@@ -19,25 +19,58 @@ internal interface TextCanvas {
19
19
operator fun get (row : Int , column : Int ): TextPixel
20
20
}
21
21
22
- private val blankPixel = TextPixel (' ' )
23
-
24
22
internal class TextSurface (
25
- override val width : Int ,
26
- override val height : Int ,
23
+ initialWidth : Int ,
24
+ initialHeight : Int ,
27
25
) : TextCanvas {
26
+ private var realWidth: Int = initialWidth
27
+ private var realHeight: Int = initialHeight
28
+
29
+ override val width: Int get() = realWidth
30
+ override val height: Int get() = realHeight
31
+
28
32
override var translationX = 0
29
33
override var translationY = 0
30
34
31
- private val rows = Array (height) { Array (width) { TextPixel (' ' ) } }
35
+ private val rows = MutableList (height) { createBlankRow(width) }
36
+
37
+ override operator fun get (row : Int , column : Int ): TextPixel {
38
+ val x = translationX + column
39
+ val y = translationY + row
40
+ if (x < 0 || y < 0 ) {
41
+ return reusableDirtyPixel
42
+ }
43
+ val widthDiff = x - width + 1
44
+ if (widthDiff > 0 ) {
45
+ if (widthDiff == 1 ) {
46
+ rows.forEach { it.add(newBlankPixel) }
47
+ } else {
48
+ rows.forEach { it.addAll(createBlankRow(widthDiff)) }
49
+ }
50
+ realWidth + = widthDiff
51
+ }
52
+ val heightDiff = y - height + 1
53
+ if (heightDiff > 0 ) {
54
+ if (heightDiff == 1 ) {
55
+ rows.add(createBlankRow(width))
56
+ } else {
57
+ rows.addAll(MutableList (heightDiff) { createBlankRow(width) })
58
+ }
59
+ realHeight + = heightDiff
60
+ }
61
+ return rows[y][x]
62
+ }
32
63
33
- override operator fun get (row : Int , column : Int ) = rows[translationY + row][translationX + column]
64
+ private inline fun createBlankRow (size : Int ): MutableList <TextPixel > {
65
+ return MutableList (size) { newBlankPixel }
66
+ }
34
67
35
68
fun appendRowTo (appendable : Appendable , row : Int ) {
36
69
// Reused heap allocation for building ANSI attributes inside the loop.
37
70
val attributes = mutableListOf<Int >()
38
71
39
72
val rowPixels = rows[row]
40
- var lastPixel = blankPixel
73
+ var lastPixel = reusableBlankPixel
41
74
for (columnIndex in 0 until width) {
42
75
val pixel = rowPixels[columnIndex]
43
76
if (pixel.foreground != lastPixel.foreground) {
@@ -91,6 +124,23 @@ internal class TextSurface(
91
124
}
92
125
}
93
126
127
+ /* *
128
+ * Returns always a new blank [TextPixel].
129
+ */
130
+ private val newBlankPixel: TextPixel get() = TextPixel (' ' )
131
+
132
+ /* *
133
+ * It is used in places where it is important that the [TextPixel]
134
+ * has its original state and **will not change**.
135
+ */
136
+ private val reusableBlankPixel: TextPixel = newBlankPixel
137
+
138
+ /* *
139
+ * It is used in places where the [TextPixel] state is not important
140
+ * and it can change.
141
+ */
142
+ private val reusableDirtyPixel: TextPixel = newBlankPixel
143
+
94
144
internal class TextPixel (var value : String ) {
95
145
var background: Color ? = null
96
146
var foreground: Color ? = null
0 commit comments