Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
skiko
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
liuqiang
skiko
Commits
4462fe46
Unverified
Commit
4462fe46
authored
Mar 10, 2025
by
Alexander Maryanovsky
Committed by
GitHub
Mar 10, 2025
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Call the listeners of PropertyKind.Renderer on render API fallback (#1033)
parent
ea19091b
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
109 additions
and
103 deletions
+109
-103
Actuals.awt.kt
skiko/src/awtMain/kotlin/org/jetbrains/skiko/Actuals.awt.kt
+2
-8
SkiaLayer.awt.kt
...o/src/awtMain/kotlin/org/jetbrains/skiko/SkiaLayer.awt.kt
+18
-18
RedrawerManager.kt
...in/kotlin/org/jetbrains/skiko/redrawer/RedrawerManager.kt
+13
-15
SkiaSwingLayer.kt
...wtMain/kotlin/org/jetbrains/skiko/swing/SkiaSwingLayer.kt
+9
-6
SkiaLayerTest.kt
...o/src/awtTest/kotlin/org/jetbrains/skiko/SkiaLayerTest.kt
+66
-55
RenderFactory.kt
...o/src/jvmMain/kotlin/org/jetbrains/skiko/RenderFactory.kt
+1
-1
No files found.
skiko/src/awtMain/kotlin/org/jetbrains/skiko/Actuals.awt.kt
View file @
4462fe46
...
...
@@ -8,7 +8,6 @@ import java.awt.datatransfer.DataFlavor
import
java.awt.datatransfer.StringSelection
import
java.awt.datatransfer.UnsupportedFlavorException
import
java.io.IOException
import
java.net.MalformedURLException
import
java.net.URI
import
java.net.URL
import
javax.swing.UIManager
...
...
@@ -16,13 +15,8 @@ import javax.swing.UIManager
actual
fun
setSystemLookAndFeel
()
=
UIManager
.
setLookAndFeel
(
UIManager
.
getSystemLookAndFeelClassName
())
internal
actual
fun
makeDefaultRenderFactory
():
RenderFactory
=
object
:
RenderFactory
{
override
fun
createRedrawer
(
layer
:
SkiaLayer
,
renderApi
:
GraphicsApi
,
analytics
:
SkiaLayerAnalytics
,
properties
:
SkiaLayerProperties
):
Redrawer
=
when
(
hostOs
)
{
RenderFactory
{
layer
,
renderApi
,
analytics
,
properties
->
when
(
hostOs
)
{
OS
.
MacOS
->
when
(
renderApi
)
{
GraphicsApi
.
SOFTWARE_COMPAT
,
GraphicsApi
.
SOFTWARE_FAST
->
SoftwareRedrawer
(
layer
,
analytics
,
properties
)
else
->
MetalRedrawer
(
layer
,
analytics
,
properties
)
...
...
skiko/src/awtMain/kotlin/org/jetbrains/skiko/SkiaLayer.awt.kt
View file @
4462fe46
...
...
@@ -284,22 +284,22 @@ actual open class SkiaLayer internal constructor(
@Volatile
private
var
isDisposed
=
false
private
val
redrawerManager
=
RedrawerManager
<
Redrawer
>(
properties
.
renderApi
)
{
renderApi
,
oldRedrawer
->
private
val
redrawerManager
=
RedrawerManager
<
Redrawer
>(
defaultRenderApi
=
properties
.
renderApi
,
redrawerFactory
=
{
renderApi
,
oldRedrawer
->
oldRedrawer
?.
dispose
()
val
newRedrawer
=
renderFactory
.
createRedrawer
(
this
,
renderApi
,
analytics
,
properties
)
newRedrawer
.
syncBounds
()
newRedrawer
renderFactory
.
createRedrawer
(
this
,
renderApi
,
analytics
,
properties
).
also
{
it
.
syncBounds
()
}
internal
val
redrawer
:
Redrawer
?
get
()
=
redrawerManager
.
redrawer
actual
var
renderApi
:
GraphicsApi
get
()
=
redrawerManager
.
renderApi
set
(
value
)
{
redrawerManager
.
forceRenderApi
(
value
)
},
onRenderApiChanged
=
{
notifyChange
(
PropertyKind
.
Renderer
)
}
)
internal
val
redrawer
:
Redrawer
?
by
redrawerManager
::
redrawer
actual
var
renderApi
:
GraphicsApi
by
redrawerManager
::
renderApi
val
renderInfo
:
String
get
()
=
if
(
redrawer
==
null
)
...
...
@@ -320,15 +320,15 @@ actual open class SkiaLayer internal constructor(
isInited
=
true
}
private
val
state
Handl
ers
=
private
val
state
ChangeListen
ers
=
mutableMapOf
<
PropertyKind
,
MutableList
<(
SkiaLayer
)
->
Unit
>>()
fun
onStateChanged
(
kind
:
PropertyKind
,
handler
:
(
SkiaLayer
)
->
Unit
)
{
state
Handlers
.
getOrPut
(
kind
,
{
mutableListOf
()
}
)
+=
handler
state
ChangeListeners
.
getOrPut
(
kind
,
::
mutableListOf
)
+=
handler
}
private
fun
notifyChange
(
kind
:
PropertyKind
)
{
state
Handlers
.
get
(
kind
)
?.
let
{
handlers
->
state
ChangeListeners
[
kind
]
?.
let
{
handlers
->
handlers
.
forEach
{
it
(
this
)
}
}
}
...
...
@@ -583,7 +583,7 @@ actual open class SkiaLayer internal constructor(
}
}
actual
intern
al
fun
draw
(
canvas
:
Canvas
)
{
internal
actu
al
fun
draw
(
canvas
:
Canvas
)
{
check
(!
isDisposed
)
{
"SkiaLayer is disposed"
}
lockPicture
{
canvas
.
drawPicture
(
it
.
instance
)
...
...
skiko/src/awtMain/kotlin/org/jetbrains/skiko/redrawer/RedrawerManager.kt
View file @
4462fe46
...
...
@@ -7,17 +7,19 @@ import org.jetbrains.skiko.SkikoProperties
internal
class
RedrawerManager
<
R
>(
defaultRenderApi
:
GraphicsApi
,
private
val
redrawerFactory
:
(
renderApi
:
GraphicsApi
,
oldRedrawer
:
R
?)
->
R
private
val
redrawerFactory
:
(
renderApi
:
GraphicsApi
,
oldRedrawer
:
R
?)
->
R
,
private
val
onRenderApiChanged
:
((
GraphicsApi
)
->
Unit
)?
=
null
)
{
private
var
_redrawer
:
R
?
=
null
private
val
fallbackRenderApiQueue
=
SkikoProperties
.
fallbackRenderApiQueue
(
defaultRenderApi
).
toMutableList
()
private
var
_renderApi
=
fallbackRenderApiQueue
[
0
]
va
l
redrawer
:
R
?
get
()
=
_redrawer
va
r
redrawer
:
R
?
=
null
private
set
val
renderApi
:
GraphicsApi
get
()
=
_renderApi
var
renderApi
:
GraphicsApi
=
fallbackRenderApiQueue
[
0
]
set
(
value
)
{
field
=
value
onRenderApiChanged
?.
invoke
(
value
)
}
fun
findNextWorkingRenderApi
(
recreation
:
Boolean
=
false
)
{
if
(
recreation
)
{
...
...
@@ -27,10 +29,10 @@ internal class RedrawerManager<R>(
do
{
thrown
=
false
try
{
_
renderApi
=
fallbackRenderApiQueue
.
removeAt
(
0
)
_redrawer
=
redrawerFactory
(
_
renderApi
,
redrawer
)
renderApi
=
fallbackRenderApiQueue
.
removeAt
(
0
)
redrawer
=
redrawerFactory
(
renderApi
,
redrawer
)
}
catch
(
e
:
RenderException
)
{
_
redrawer
=
null
redrawer
=
null
Logger
.
warn
(
e
)
{
"Fallback to next API"
}
thrown
=
true
}
...
...
@@ -41,11 +43,7 @@ internal class RedrawerManager<R>(
}
}
fun
forceRenderApi
(
renderApi
:
GraphicsApi
)
{
_renderApi
=
renderApi
}
fun
dispose
()
{
_
redrawer
=
null
redrawer
=
null
}
}
\ No newline at end of file
skiko/src/awtMain/kotlin/org/jetbrains/skiko/swing/SkiaSwingLayer.kt
View file @
4462fe46
...
...
@@ -4,11 +4,11 @@ import org.jetbrains.skia.Canvas
import
org.jetbrains.skiko.*
import
org.jetbrains.skiko.redrawer.RedrawerManager
import
java.awt.Component
import
java.awt.Graphics
import
java.awt.Graphics2D
import
java.awt.GraphicsConfiguration
import
javax.accessibility.Accessible
import
javax.accessibility.AccessibleContext
import
javax.swing.JComponent
import
javax.swing.JPanel
import
javax.swing.SwingUtilities.isEventDispatchThread
...
...
@@ -65,10 +65,13 @@ open class SkiaSwingLayer(
get
()
=
this
@SkiaSwingLayer
.
properties
.
adapterPriority
}
private
val
redrawerManager
=
RedrawerManager
<
SwingRedrawer
>(
properties
.
renderApi
)
{
renderApi
,
oldRedrawer
->
private
val
redrawerManager
=
RedrawerManager
<
SwingRedrawer
>(
properties
.
renderApi
,
redrawerFactory
=
{
renderApi
,
oldRedrawer
->
oldRedrawer
?.
dispose
()
createSwingRedrawer
(
swingLayerProperties
,
renderDelegateWithClipping
,
renderApi
,
analytics
)
}
)
private
val
redrawer
:
SwingRedrawer
?
get
()
=
redrawerManager
.
redrawer
...
...
@@ -109,7 +112,7 @@ open class SkiaSwingLayer(
}
}
override
fun
paint
(
g
:
java
.
awt
.
Graphics
)
{
override
fun
paint
(
g
:
Graphics
)
{
try
{
redrawer
?.
redraw
(
g
as
Graphics2D
)
}
catch
(
e
:
RenderException
)
{
...
...
skiko/src/awtTest/kotlin/org/jetbrains/skiko/SkiaLayerTest.kt
View file @
4462fe46
...
...
@@ -541,63 +541,41 @@ class SkiaLayerTest {
}
}
private
abstract
class
BaseTestRedrawer
:
Redrawer
{
override
fun
dispose
()
=
Unit
override
fun
needRedraw
()
=
Unit
override
fun
redrawImmediately
()
=
Unit
override
val
renderInfo
:
String
get
()
=
""
}
@Test
(
timeout
=
60000
)
fun
`
fallback
to
software
renderer
,
fail
on
init
context
`
()
=
uiTest
{
testFallbackToSoftware
(
object
:
RenderFactory
{
override
fun
createRedrawer
(
layer
:
SkiaLayer
,
renderApi
:
GraphicsApi
,
analytics
:
SkiaLayerAnalytics
,
properties
:
SkiaLayerProperties
)
=
object
:
Redrawer
{
testFallbackToSoftware
{
layer
,
_
,
_
,
_
->
object
:
BaseTestRedrawer
()
{
private
val
contextHandler
=
object
:
JvmContextHandler
(
layer
)
{
override
fun
initContext
()
=
false
override
fun
initCanvas
()
=
Unit
}
override
fun
dispose
()
=
Unit
override
fun
needRedraw
()
=
Unit
override
fun
redrawImmediately
()
=
layer
.
inDrawScope
(
contextHandler
::
draw
)
override
val
renderInfo
=
""
}
}
)
}
@Test
(
timeout
=
60000
)
fun
`
fallback
to
software
renderer
,
fail
on
create
redrawer
`
()
=
uiTest
{
testFallbackToSoftware
(
object
:
RenderFactory
{
override
fun
createRedrawer
(
layer
:
SkiaLayer
,
renderApi
:
GraphicsApi
,
analytics
:
SkiaLayerAnalytics
,
properties
:
SkiaLayerProperties
)
=
throw
RenderException
()
}
)
testFallbackToSoftware
{
_
,
_
,
_
,
_
->
throw
RenderException
()
}
}
@Test
(
timeout
=
60000
)
fun
`
fallback
to
software
renderer
,
fail
on
draw
`
()
=
uiTest
{
testFallbackToSoftware
(
object
:
RenderFactory
{
override
fun
createRedrawer
(
layer
:
SkiaLayer
,
renderApi
:
GraphicsApi
,
analytics
:
SkiaLayerAnalytics
,
properties
:
SkiaLayerProperties
)
=
object
:
Redrawer
{
override
fun
dispose
()
=
Unit
override
fun
needRedraw
()
=
Unit
testFallbackToSoftware
{
layer
,
_
,
_
,
_
->
object
:
BaseTestRedrawer
()
{
override
fun
redrawImmediately
()
=
layer
.
inDrawScope
{
throw
RenderException
()
}
override
val
renderInfo
=
""
}
}
)
}
private
suspend
fun
UiTestScope
.
testFallbackToSoftware
(
nonSoftwareRenderFactory
:
RenderFactory
)
{
...
...
@@ -644,6 +622,35 @@ class SkiaLayerTest {
}
}
@Test
(
timeout
=
60000
)
fun
`
renderApi
change
callback
is
invoked
on
fallback
`
()
=
uiTest
{
val
window
=
UiTestWindow
(
renderFactory
=
OverrideNonSoftwareRenderFactory
{
layer
,
_
,
_
,
_
->
object
:
BaseTestRedrawer
()
{
override
fun
redrawImmediately
()
=
layer
.
inDrawScope
{
throw
RenderException
()
}
}
}
)
try
{
var
rendererChangedCallbackInvoked
=
false
window
.
layer
.
onStateChanged
(
SkiaLayer
.
PropertyKind
.
Renderer
)
{
rendererChangedCallbackInvoked
=
true
}
window
.
setLocation
(
200
,
200
)
window
.
setSize
(
400
,
200
)
window
.
isVisible
=
true
delay
(
1000
)
assertEquals
(
GraphicsApi
.
SOFTWARE_COMPAT
,
window
.
layer
.
renderApi
)
assertTrue
(
rendererChangedCallbackInvoked
)
}
finally
{
window
.
close
()
}
}
@Test
(
timeout
=
20000
)
fun
`
render
continuously
empty
content
without
vsync
`
()
=
uiTest
{
val
targetDrawCount
=
500
...
...
@@ -981,6 +988,7 @@ class SkiaLayerTest {
}
contentPane
.
add
(
layer
)
}
try
{
window
.
size
=
Dimension
(
400
,
400
)
window
.
isVisible
=
true
...
...
@@ -997,6 +1005,9 @@ class SkiaLayerTest {
assert
(
layoutCount
<=
3
)
{
"Layout count: $layoutCount"
}
}
finally
{
window
.
dispose
()
}
}
private
class
RectRenderer
(
...
...
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/RenderFactory.kt
View file @
4462fe46
...
...
@@ -2,7 +2,7 @@ package org.jetbrains.skiko
import
org.jetbrains.skiko.redrawer.*
internal
interface
RenderFactory
{
internal
fun
interface
RenderFactory
{
fun
createRedrawer
(
layer
:
SkiaLayer
,
renderApi
:
GraphicsApi
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment