Skip to content

Commit 8dc2d82

Browse files
committed
Avoid calling SkiaLayer.revalidate() when the window itself is moved.
1 parent 79f1d43 commit 8dc2d82

File tree

2 files changed

+60
-13
lines changed

2 files changed

+60
-13
lines changed

skiko/src/awtMain/kotlin/org/jetbrains/skiko/SkiaLayer.awt.kt

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import org.jetbrains.skiko.redrawer.Redrawer
88
import org.jetbrains.skiko.redrawer.RedrawerManager
99
import java.awt.Color
1010
import java.awt.Component
11+
import java.awt.Point
1112
import java.awt.event.*
1213
import java.awt.geom.AffineTransform
1314
import java.awt.im.InputMethodRequests
@@ -20,7 +21,6 @@ import javax.swing.SwingUtilities.isEventDispatchThread
2021
import javax.swing.UIManager
2122
import javax.swing.event.AncestorEvent
2223
import javax.swing.event.AncestorListener
23-
import kotlin.math.ceil
2424
import kotlin.math.floor
2525

2626
actual open class SkiaLayer internal constructor(
@@ -138,12 +138,34 @@ actual open class SkiaLayer internal constructor(
138138
add(backedLayer)
139139

140140
addAncestorListener(object : AncestorListener {
141-
override fun ancestorAdded(event: AncestorEvent?) = Unit
142141

143-
override fun ancestorRemoved(event: AncestorEvent?) = Unit
142+
private var positionInWindow: Point? = null
143+
144+
private val zeroPoint = Point(0, 0)
145+
146+
private fun computePositionInWindow(): Point? {
147+
val window = SwingUtilities.getWindowAncestor(this@SkiaLayer)
148+
return if (window == null) {
149+
null
150+
} else {
151+
SwingUtilities.convertPoint(this@SkiaLayer, zeroPoint, window)
152+
}
153+
}
154+
155+
override fun ancestorAdded(event: AncestorEvent?) {
156+
positionInWindow = computePositionInWindow()
157+
}
158+
159+
override fun ancestorRemoved(event: AncestorEvent?) {
160+
positionInWindow = null
161+
}
144162

145163
override fun ancestorMoved(event: AncestorEvent?) {
146-
revalidate()
164+
val newPosition = computePositionInWindow()
165+
if ((positionInWindow != null) && (positionInWindow != newPosition)) {
166+
revalidate()
167+
}
168+
positionInWindow = newPosition
147169
}
148170
})
149171

@@ -190,7 +212,6 @@ actual open class SkiaLayer internal constructor(
190212
init(isInited)
191213
}
192214

193-
194215
actual fun detach() {
195216
dispose()
196217
}

skiko/src/awtTest/kotlin/org/jetbrains/skiko/SkiaLayerTest.kt

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
package org.jetbrains.skiko
22

3-
import kotlinx.coroutines.CompletableDeferred
4-
import kotlinx.coroutines.delay
5-
import kotlinx.coroutines.launch
6-
import kotlinx.coroutines.yield
3+
import kotlinx.coroutines.*
4+
import org.jetbrains.skia.*
75
import org.jetbrains.skia.Canvas
8-
import org.jetbrains.skia.FontMgr
96
import org.jetbrains.skia.Paint
10-
import org.jetbrains.skia.Rect
117
import org.jetbrains.skia.paragraph.FontCollection
128
import org.jetbrains.skia.paragraph.ParagraphBuilder
139
import org.jetbrains.skia.paragraph.ParagraphStyle
@@ -24,9 +20,8 @@ import org.junit.Assume.assumeTrue
2420
import org.junit.Ignore
2521
import org.junit.Rule
2622
import org.junit.Test
27-
import java.awt.BorderLayout
23+
import java.awt.*
2824
import java.awt.Color
29-
import java.awt.Dimension
3025
import java.awt.event.*
3126
import javax.swing.Box
3227
import javax.swing.JFrame
@@ -941,6 +936,37 @@ class SkiaLayerTest {
941936
}
942937
}
943938

939+
@Test
940+
fun `content not relaid out on window move`() = uiTest {
941+
var layoutCount = 0
942+
943+
val window = UiTestWindow {
944+
contentPane.layout = object: BorderLayout() {
945+
override fun layoutContainer(parent: Container?) {
946+
super.layoutContainer(parent)
947+
layoutCount++
948+
}
949+
}
950+
contentPane.add(layer)
951+
}
952+
window.size = Dimension(400, 400)
953+
window.isVisible = true
954+
955+
repeat(20) {
956+
window.location = window.location.let {
957+
java.awt.Point(it.x + 10, it.y + 10)
958+
}
959+
delay(50)
960+
}
961+
962+
// Ideally, layoutCount would be just 1, but Swing appears to call layout one extra time, so it ends up being 2.
963+
// Compare to 3 just to avoid a false-failure if there's another layout for whatever reason.
964+
// What we're interested to validate is that there's no layout occurring on every window move.
965+
assert(layoutCount <= 3) {
966+
"Layout count: $layoutCount"
967+
}
968+
}
969+
944970
private class RectRenderer(
945971
private val layer: SkiaLayer,
946972
var rectWidth: Int,

0 commit comments

Comments
 (0)