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
ef910e66
Commit
ef910e66
authored
Jan 15, 2021
by
Igor Demin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
SkiaWindow tests
parent
093421cf
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
592 additions
and
8 deletions
+592
-8
SkiaPanel.kt
...jectSample/src/main/kotlin/SkijaInjectSample/SkiaPanel.kt
+3
-1
SwingSkia.kt
...jectSample/src/main/kotlin/SkijaInjectSample/SwingSkia.kt
+1
-5
SkiaWindowPerformanceTest.kt
...t/kotlin/org/jetbrains/skiko/SkiaWindowPerformanceTest.kt
+288
-0
SkiaWindowTest.kt
...ple/src/test/kotlin/org/jetbrains/skiko/SkiaWindowTest.kt
+295
-0
org_jetbrains_skiko_SkiaWindowTest_render_single_window_frame1.png
...ains_skiko_SkiaWindowTest_render_single_window_frame1.png
+0
-0
org_jetbrains_skiko_SkiaWindowTest_render_single_window_frame2.png
...ains_skiko_SkiaWindowTest_render_single_window_frame2.png
+0
-0
org_jetbrains_skiko_SkiaWindowTest_render_text_Linux.png
.../org_jetbrains_skiko_SkiaWindowTest_render_text_Linux.png
+0
-0
org_jetbrains_skiko_SkiaWindowTest_render_text_MacOS.png
.../org_jetbrains_skiko_SkiaWindowTest_render_text_MacOS.png
+0
-0
org_jetbrains_skiko_SkiaWindowTest_render_text_Windows.png
...rg_jetbrains_skiko_SkiaWindowTest_render_text_Windows.png
+0
-0
org_jetbrains_skiko_SkiaWindowTest_render_three_windows_window1.png
...ins_skiko_SkiaWindowTest_render_three_windows_window1.png
+0
-0
org_jetbrains_skiko_SkiaWindowTest_render_three_windows_window2.png
...ins_skiko_SkiaWindowTest_render_three_windows_window2.png
+0
-0
org_jetbrains_skiko_SkiaWindowTest_render_three_windows_window3.png
...ins_skiko_SkiaWindowTest_render_three_windows_window3.png
+0
-0
org_jetbrains_skiko_SkiaWindowTest_resize_window.png
...hots/org_jetbrains_skiko_SkiaWindowTest_resize_window.png
+0
-0
SkiaWindow.kt
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/SkiaWindow.kt
+5
-2
No files found.
s
kiko/src/jvmMain/kotlin/org/jetbrains/skiko
/SkiaPanel.kt
→
s
amples/SkijaInjectSample/src/main/kotlin/SkijaInjectSample
/SkiaPanel.kt
View file @
ef910e66
package
org.jetbrains.skiko
package
SkijaInjectSample
import
org.jetbrains.skiko.ClipComponent
import
org.jetbrains.skiko.SkiaLayer
import
java.awt.Color
import
java.awt.Color
import
java.awt.Component
import
java.awt.Component
import
java.awt.event.ComponentAdapter
import
java.awt.event.ComponentAdapter
...
...
samples/SkijaInjectSample/src/main/kotlin/SkijaInjectSample/SwingSkia.kt
View file @
ef910e66
...
@@ -5,16 +5,12 @@ import java.awt.Color
...
@@ -5,16 +5,12 @@ import java.awt.Color
import
java.awt.Dimension
import
java.awt.Dimension
import
java.awt.event.ComponentAdapter
import
java.awt.event.ComponentAdapter
import
java.awt.event.ComponentEvent
import
java.awt.event.ComponentEvent
import
java.awt.event.KeyEvent
import
java.awt.event.MouseEvent
import
java.awt.event.MouseEvent
import
java.awt.event.MouseMotionAdapter
import
java.awt.event.MouseMotionAdapter
import
javax.swing.JFrame
import
javax.swing.JButton
import
javax.swing.JButton
import
javax.swing.J
LayeredPan
e
import
javax.swing.J
Fram
e
import
javax.swing.JPanel
import
javax.swing.JPanel
import
javax.swing.event.MouseInputAdapter
import
javax.swing.WindowConstants
import
javax.swing.WindowConstants
import
org.jetbrains.skiko.SkiaPanel
fun
Button
(
text
:
String
):
JButton
{
fun
Button
(
text
:
String
):
JButton
{
...
...
samples/SkijaInjectSample/src/test/kotlin/org/jetbrains/skiko/SkiaWindowPerformanceTest.kt
0 → 100644
View file @
ef910e66
package
org.jetbrains.skiko
import
kotlinx.coroutines.*
import
kotlinx.coroutines.swing.Swing
import
org.jetbrains.skija.*
import
org.junit.Test
import
java.awt.event.WindowEvent
import
java.util.*
import
javax.swing.JFrame
import
javax.swing.WindowConstants
import
kotlin.math.abs
import
kotlin.math.log2
import
kotlin.math.roundToInt
import
kotlin.math.sqrt
import
kotlin.random.Random
@Suppress
(
"BlockingMethodInNonBlockingContext"
,
"SameParameterValue"
)
class
SkiaWindowPerfomanceTest
{
// TODO uncomment fontManager and fix native crash (Windows)
/*
J 1680 org.jetbrains.skija.impl.Managed._nInvokeFinalizer(JJ)V (0 bytes) @ 0x0000027907c261f4 [0x0000027907c261a0+0x0000000000000054]
J 1674 c1 org.jetbrains.skija.impl.Managed$CleanerThunk.run()V (31 bytes) @ 0x0000027900aac2cc [0x0000027900aabbe0+0x00000000000006ec]
J 724 c1 jdk.internal.ref.CleanerImpl$PhantomCleanableRef.performCleanup()V java.base@14.0.2 (10 bytes) @ 0x000002790088b3ec [0x000002790088b2c0+0x000000000000012c]
J 723 c1 jdk.internal.ref.PhantomCleanable.clean()V java.base@14.0.2 (16 bytes) @ 0x000002790088b91c [0x000002790088b740+0x00000000000001dc]
j jdk.internal.ref.CleanerImpl.run()V+77 java.base@14.0.2
j java.lang.Thread.run()V+11 java.base@14.0.2
j jdk.internal.misc.InnocuousThread.run()V+20 java.base@14.0.2
v ~StubRoutines::call_stub
native crash in SkiaWindowTest "render single window"
*/
// private val fontManager = FontMgr.getDefault()
// private val fontCollection = FontCollection()
// .setDefaultFontManager(fontManager)
//
// private fun paragraph(size: Float, text: String) =
// ParagraphBuilder(ParagraphStyle(), fontCollection)
// .pushStyle(
// TextStyle()
// .setColor(Color.RED.rgb)
// .setFontSize(size)
// )
// .addText(text)
// .popStyle()
// .build()
@Test
fun
`
FPS
is
near
display
refresh
rate
(
multiple
windows
)
`
()
=
swingTest
{
class
TestWindow
(
width
:
Int
,
height
:
Int
,
private
val
frameCount
:
Int
,
private
val
deviatedTerminalCount
:
Int
)
:
SkiaWindow
()
{
private
val
expectedDeviatePercent1
=
0.05
private
val
expectedDeviatePercent2
=
0.15
private
val
expectedDeviatePercent3
=
0.30
private
val
expectedDeviatePercentTerminal
=
0.50
private
val
expectedFrameNanos
=
1
E9
/
graphicsConfiguration
.
device
.
displayMode
.
refreshRate
private
val
frameTimes
=
mutableListOf
<
Long
>()
private
var
canCollect
=
false
val
frameTimeDeltas
get
()
=
frameTimes
.
zipWithNext
{
a
,
b
->
b
-
a
}
val
isCollected
get
()
=
frameTimes
.
size
>=
frameCount
private
fun
deviated
(
deviatePercent
:
Double
)
=
frameTimeDeltas
.
filter
{
abs
(
log2
(
it
/
expectedFrameNanos
))
>
log2
(
1
+
deviatePercent
)
}
init
{
setSize
(
width
,
height
)
defaultCloseOperation
=
WindowConstants
.
DISPOSE_ON_CLOSE
layer
.
renderer
=
object
:
SkiaRenderer
{
override
suspend
fun
onRender
(
canvas
:
Canvas
,
width
:
Int
,
height
:
Int
,
nanoTime
:
Long
)
{
if
(
canCollect
&&
frameTimes
.
size
<
frameCount
)
{
frameTimes
.
add
(
System
.
nanoTime
())
// we check the real time, not the time provided by the argument
}
layer
.
needRedraw
()
}
}
isUndecorated
=
true
isVisible
=
true
}
fun
startCollect
()
{
canCollect
=
true
}
fun
printInfo
()
{
println
(
"[Window frame times ($frameCount frames)]"
)
val
millis
=
frameTimeDeltas
.
map
{
it
/
1
E6
}
println
(
"Deltas "
+
millis
.
map
{
String
.
format
(
"%.1f"
,
it
)
})
println
(
"Average %.2f"
.
format
(
millis
.
average
()))
println
(
"Standard deviation %.2f"
.
format
(
millis
.
stddev
()))
fun
deviateMessage
(
percent
:
Double
,
deviated
:
List
<
Long
>):
String
{
val
deviatedStr
=
deviated
.
map
{
String
.
format
(
"%.1f"
,
it
/
1
E6
)
}
val
percentTStr
=
(
percent
*
100
).
roundToInt
()
return
"$deviatedStr deviate by $percentTStr%"
}
val
deviated1
=
deviated
(
expectedDeviatePercent1
)
val
deviated2
=
deviated
(
expectedDeviatePercent2
)
val
deviated3
=
deviated
(
expectedDeviatePercent3
)
val
deviatedTerminal
=
deviated
(
expectedDeviatePercentTerminal
)
println
(
deviateMessage
(
expectedDeviatePercent1
,
deviated1
-
deviated2
-
deviated3
-
deviatedTerminal
))
println
(
deviateMessage
(
expectedDeviatePercent2
,
deviated2
-
deviated3
-
deviatedTerminal
))
println
(
deviateMessage
(
expectedDeviatePercent3
,
deviated3
-
deviatedTerminal
))
if
(
deviatedTerminal
.
size
>
deviatedTerminalCount
)
{
throw
AssertionError
(
deviateMessage
(
expectedDeviatePercentTerminal
,
deviatedTerminal
))
}
else
{
println
(
deviateMessage
(
expectedDeviatePercentTerminal
,
deviatedTerminal
))
}
println
()
}
private
fun
List
<
Double
>.
stddev
():
Double
{
val
average
=
average
()
fun
f
(
x
:
Double
)
=
(
x
-
average
)
*
(
x
-
average
)
return
sqrt
(
map
(
::
f
).
average
())
}
}
suspend
fun
awaitFrameCollection
(
windows
:
List
<
TestWindow
>)
{
while
(!
windows
.
all
(
TestWindow
::
isCollected
))
{
delay
(
100
)
}
}
val
windows
=
(
1
..
3
).
map
{
TestWindow
(
width
=
40
,
height
=
20
,
frameCount
=
300
,
deviatedTerminalCount
=
10
)
}
delay
(
1000
)
windows
.
forEach
(
TestWindow
::
startCollect
)
awaitFrameCollection
(
windows
)
windows
.
forEach
(
TestWindow
::
printInfo
)
windows
.
forEach
(
TestWindow
::
close
)
}
// TODO fix native crash on macOs in previous test if this test is performed before it
/*
Stack: [0x00007ffee09ff000,0x00007ffee11ff000], sp=0x00007ffee11f9630, free space=8169k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [libskiko-macos-x64.dylib+0xe999b] decltype(fp((SkRecords::NoOp)())) SkRecord::Record::visit<SkRecords::Draw&>(SkRecords::Draw&) const+0xb
C [libskiko-macos-x64.dylib+0xe940f] SkRecordDraw(SkRecord const&, SkCanvas*, SkPicture const* const*, SkDrawable* const*, int, SkBBoxHierarchy const*, SkPicture::AbortCallback*)+0x20f
C [libskiko-macos-x64.dylib+0x188783] SkBigPicture::playback(SkCanvas*, SkPicture::AbortCallback*) const+0xa3
C [libskiko-macos-x64.dylib+0x65b4b] SkCanvas::onDrawPicture(SkPicture const*, SkMatrix const*, SkPaint const*)+0x13b
C [libskiko-macos-x64.dylib+0x659d6] SkCanvas::drawPicture(SkPicture const*, SkMatrix const*, SkPaint const*)+0x146
C [libskiko-macos-x64.dylib+0x169c4] Java_org_jetbrains_skija_Canvas__1nDrawPicture+0x34
j org.jetbrains.skija.Canvas._nDrawPicture(JJ[FJ)V+0
j org.jetbrains.skija.Canvas.drawPicture(Lorg/jetbrains/skija/Picture;Lorg/jetbrains/skija/Matrix33;Lorg/jetbrains/skija/Paint;)Lorg/jetbrains/skija/Canvas;+27
j org.jetbrains.skija.Canvas.drawPicture(Lorg/jetbrains/skija/Picture;)Lorg/jetbrains/skija/Canvas;+4
j org.jetbrains.skiko.SkiaLayer.draw$skiko()V+229
j org.jetbrains.skiko.redrawer.MacOsRedrawer$drawLayer$1.draw()V+7
*/
//@Test
fun
`
check
FPS
(
elementary
picture
)
`
()
=
swingTest
{
// we don't count FPS straightforward because in window mode there is always vsync (we can get rid of it only in exclusive fullscreen mode)
// FPS will be capped by display's refresh rate.
//
// So we want to reach the point when the FPS is much below refresh rate drawing very big amount of pictures avery frame.
// When we reach that point, we can approximate FPS: FPS = 1000.0 / calculatedFrameTime * picturesPerFrame
val
frameCheckCount
=
10
val
refreshRatePercent
=
0.02
// We need to reach FPS = refreshRatePercent * refreshRate
var
picturesPerFrame
=
1000
val
smoothFPSCounter
=
FPSCounter
(
count
=
frameCheckCount
)
val
onComplete
=
CompletableDeferred
<
Unit
>()
fun
renderer
(
window
:
SkiaWindow
)
=
object
:
SkiaRenderer
{
var
t1
=
Long
.
MAX_VALUE
val
refreshRate
=
window
.
graphicsConfiguration
.
device
.
displayMode
.
refreshRate
override
suspend
fun
onRender
(
canvas
:
Canvas
,
width
:
Int
,
height
:
Int
,
nanoTime
:
Long
)
{
val
t2
=
System
.
nanoTime
()
val
frameTime
=
(
t2
-
t1
).
coerceAtLeast
(
0
)
t1
=
t2
val
currentFPS
=
1
E9
/
frameTime
val
targetFPS
=
refreshRate
*
refreshRatePercent
val
smoothFPS
=
smoothFPSCounter
.
tick
()
if
(
currentFPS
>
targetFPS
)
{
picturesPerFrame
*=
2
}
if
(
smoothFPS
<
targetFPS
&&
smoothFPSCounter
.
isCountReached
)
{
onComplete
.
complete
(
Unit
)
}
val
random
=
Random
(
123
)
repeat
(
picturesPerFrame
)
{
canvas
.
save
()
canvas
.
translate
(
width
*
random
.
nextFloat
(),
height
*
random
.
nextFloat
())
canvas
.
drawTestPicture
()
canvas
.
restore
()
}
window
.
layer
.
needRedraw
()
}
}
val
window
=
SkiaWindow
()
try
{
window
.
setSize
(
400
,
400
)
window
.
defaultCloseOperation
=
WindowConstants
.
DISPOSE_ON_CLOSE
window
.
isUndecorated
=
true
window
.
isVisible
=
true
delay
(
1000
)
window
.
layer
.
renderer
=
renderer
(
window
)
window
.
layer
.
needRedraw
()
onComplete
.
await
()
val
fps
=
(
smoothFPSCounter
.
fps
*
picturesPerFrame
).
roundToInt
()
println
(
"FPS is $fps"
)
println
(
"We draw $picturesPerFrame pictures per frame to avoid VSYNC lag"
)
}
finally
{
window
.
close
()
}
}
//private val paragraph by lazy { paragraph(10f, "Text") }
fun
Canvas
.
drawTestPicture
()
{
save
()
clipRect
(
Rect
(
2f
,
2f
,
18f
,
18f
))
drawRect
(
Rect
(
0f
,
0f
,
20f
,
20f
),
Paint
().
apply
{
color
=
0
x88FF0000
.
toInt
()
})
drawRRect
(
RRect
.
makeLTRB
(
0f
,
0f
,
20f
,
20f
,
4f
),
Paint
().
apply
{
mode
=
PaintMode
.
STROKE
strokeWidth
=
2f
color
=
0
x8800FF00
.
toInt
()
})
drawLine
(
0f
,
0f
,
10f
,
10f
,
Paint
().
apply
{
color
=
0
x880000FF
.
toInt
()
isAntiAlias
=
true
})
//paragraph.layout(Float.POSITIVE_INFINITY) // TODO fix native crash on Linux (free(): invalid pointer)
//paragraph.paint(this, 0f, 0f)
restore
()
}
private
fun
swingTest
(
block
:
suspend
CoroutineScope
.()
->
Unit
)
{
runBlocking
(
Dispatchers
.
Swing
)
{
block
()
}
}
private
class
FPSCounter
(
private
val
count
:
Int
)
{
private
val
times
=
LinkedList
<
Long
>()
private
var
t1
=
System
.
nanoTime
()
val
isCountReached
get
()
=
times
.
size
==
count
val
fps
get
()
=
1
E9
/
times
.
average
()
fun
tick
():
Double
{
val
t2
=
System
.
nanoTime
()
val
frameTime
=
t2
-
t1
t1
=
t2
times
.
add
(
frameTime
)
if
(
times
.
size
>
count
)
{
times
.
removeFirst
()
}
return
fps
}
}
}
private
fun
JFrame
.
close
()
=
dispatchEvent
(
WindowEvent
(
this
,
WindowEvent
.
WINDOW_CLOSING
))
\ No newline at end of file
samples/SkijaInjectSample/src/test/kotlin/org/jetbrains/skiko/SkiaWindowTest.kt
0 → 100644
View file @
ef910e66
package
org.jetbrains.skiko
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.delay
import
kotlinx.coroutines.runBlocking
import
kotlinx.coroutines.swing.Swing
import
org.jetbrains.skija.Canvas
import
org.jetbrains.skija.FontMgr
import
org.jetbrains.skija.Paint
import
org.jetbrains.skija.Rect
import
org.jetbrains.skija.paragraph.FontCollection
import
org.jetbrains.skija.paragraph.ParagraphBuilder
import
org.jetbrains.skija.paragraph.ParagraphStyle
import
org.jetbrains.skija.paragraph.TextStyle
import
org.junit.Assume.assumeTrue
import
org.junit.Rule
import
org.junit.Test
import
java.awt.Color
import
java.awt.Robot
import
java.awt.event.WindowEvent
import
javax.swing.JFrame
import
javax.swing.WindowConstants
import
kotlin.random.Random
import
kotlin.test.assertEquals
import
kotlin.test.assertTrue
@Suppress
(
"BlockingMethodInNonBlockingContext"
,
"SameParameterValue"
)
class
SkiaWindowTest
{
private
val
robot
=
Robot
()
private
val
fontManager
=
FontMgr
.
getDefault
()
private
val
fontCollection
=
FontCollection
()
.
setDefaultFontManager
(
fontManager
)
private
fun
paragraph
(
size
:
Float
,
text
:
String
)
=
ParagraphBuilder
(
ParagraphStyle
(),
fontCollection
)
.
pushStyle
(
TextStyle
()
.
setColor
(
Color
.
RED
.
rgb
)
.
setFontSize
(
size
)
)
.
addText
(
text
)
.
popStyle
()
.
build
()
@get
:
Rule
val
screenshots
=
ScreenshotTestRule
(
robot
)
@Test
fun
`
render
single
window
`
()
=
swingTest
{
val
window
=
SkiaWindow
()
try
{
window
.
setSize
(
400
,
200
)
window
.
defaultCloseOperation
=
WindowConstants
.
DISPOSE_ON_CLOSE
val
renderer
=
RectRenderer
(
window
.
layer
,
200
,
100
,
Color
.
RED
)
window
.
layer
.
renderer
=
renderer
window
.
isUndecorated
=
true
window
.
isVisible
=
true
delay
(
1000
)
screenshots
.
assert
(
window
.
bounds
,
"frame1"
)
renderer
.
rectWidth
=
100
window
.
layer
.
needRedraw
()
delay
(
1000
)
screenshots
.
assert
(
window
.
bounds
,
"frame2"
)
}
finally
{
window
.
close
()
}
}
@Test
fun
`
resize
window
`
()
=
swingTest
{
val
window
=
SkiaWindow
()
try
{
window
.
setSize
(
40
,
20
)
window
.
defaultCloseOperation
=
WindowConstants
.
DISPOSE_ON_CLOSE
window
.
layer
.
renderer
=
RectRenderer
(
window
.
layer
,
20
,
10
,
Color
.
RED
)
window
.
isUndecorated
=
true
window
.
isVisible
=
true
delay
(
1000
)
window
.
setSize
(
80
,
40
)
delay
(
1000
)
screenshots
.
assert
(
window
.
bounds
)
}
finally
{
window
.
close
()
}
}
@Test
fun
`
render
three
windows
`
()
=
swingTest
{
fun
window
(
color
:
Color
)
=
SkiaWindow
().
apply
{
setSize
(
400
,
200
)
defaultCloseOperation
=
WindowConstants
.
DISPOSE_ON_CLOSE
layer
.
renderer
=
RectRenderer
(
layer
,
200
,
100
,
color
)
isUndecorated
=
true
isVisible
=
true
}
val
window1
=
window
(
Color
.
RED
)
val
window2
=
window
(
Color
.
GREEN
)
val
window3
=
window
(
Color
.
BLACK
)
try
{
delay
(
1000
)
window1
.
toFront
()
delay
(
1000
)
screenshots
.
assert
(
window1
.
bounds
,
"window1"
)
window2
.
toFront
()
delay
(
1000
)
screenshots
.
assert
(
window2
.
bounds
,
"window2"
)
window3
.
toFront
()
delay
(
1000
)
screenshots
.
assert
(
window3
.
bounds
,
"window3"
)
}
finally
{
window1
.
close
()
window2
.
close
()
window3
.
close
()
}
}
@Test
fun
`
should
call
onRender
after
init
,
after
resize
,
and
only
once
after
needRedraw
`
()
=
swingTest
{
var
renderCount
=
0
val
window
=
SkiaWindow
()
try
{
window
.
setSize
(
40
,
20
)
window
.
defaultCloseOperation
=
WindowConstants
.
DISPOSE_ON_CLOSE
window
.
layer
.
renderer
=
object
:
SkiaRenderer
{
override
suspend
fun
onRender
(
canvas
:
Canvas
,
width
:
Int
,
height
:
Int
,
nanoTime
:
Long
)
{
renderCount
++
}
}
window
.
isUndecorated
=
true
window
.
isVisible
=
true
delay
(
1000
)
assertTrue
(
renderCount
>
0
)
renderCount
=
0
window
.
setSize
(
50
,
20
)
delay
(
1000
)
assertTrue
(
renderCount
>
0
)
renderCount
=
0
window
.
layer
.
needRedraw
()
delay
(
1000
)
assertEquals
(
1
,
renderCount
)
}
finally
{
window
.
close
()
}
}
@Test
fun
`
open
windows
stress
test
`
()
=
swingTest
{
fun
window
(
isAnimated
:
Boolean
)
=
SkiaWindow
().
apply
{
setSize
(
40
,
20
)
defaultCloseOperation
=
WindowConstants
.
DISPOSE_ON_CLOSE
layer
.
renderer
=
if
(
isAnimated
)
{
AnimatedBoxRenderer
(
layer
,
pixelsPerSecond
=
20.0
,
size
=
2.0
)
}
else
{
RectRenderer
(
layer
,
20
,
10
,
Color
.
RED
)
}
isUndecorated
=
true
isVisible
=
true
}
val
random
=
Random
(
31415926
)
val
openedWindows
=
mutableListOf
<
SkiaWindow
>()
repeat
(
10
)
{
val
needOpen
=
random
.
nextDouble
()
>
0.5f
repeat
(
10
)
{
if
(
needOpen
)
{
val
window
=
window
(
isAnimated
=
random
.
nextDouble
()
>
0.5f
)
openedWindows
.
add
(
window
)
}
else
if
(
openedWindows
.
size
>
0
)
{
val
index
=
(
random
.
nextDouble
()
*
(
openedWindows
.
size
-
1
)).
toInt
()
openedWindows
.
removeAt
(
index
).
close
()
}
}
val
delayCount
=
random
.
nextLong
(
5
)
if
(
delayCount
>
0
)
{
delay
(
delayCount
*
10
)
}
}
openedWindows
.
forEach
(
JFrame
::
close
)
delay
(
5000
)
}
@Test
fun
`
render
text
(
Windows
)
`
()
{
testRenderText
(
OS
.
Windows
)
}
@Test
fun
`
render
text
(
Linux
)
`
()
{
testRenderText
(
OS
.
Linux
)
}
@Test
fun
`
render
text
(
MacOS
)
`
()
{
testRenderText
(
OS
.
MacOS
)
}
private
fun
testRenderText
(
os
:
OS
)
=
swingTest
{
assumeTrue
(
hostOs
==
os
)
val
window
=
SkiaWindow
()
try
{
window
.
setSize
(
400
,
200
)
window
.
defaultCloseOperation
=
WindowConstants
.
DISPOSE_ON_CLOSE
val
paragraph
by
lazy
{
paragraph
(
window
.
layer
.
contentScale
*
40
,
"=-+Нп"
)
}
window
.
layer
.
renderer
=
object
:
SkiaRenderer
{
override
suspend
fun
onRender
(
canvas
:
Canvas
,
width
:
Int
,
height
:
Int
,
nanoTime
:
Long
)
{
paragraph
.
layout
(
Float
.
POSITIVE_INFINITY
)
paragraph
.
paint
(
canvas
,
0f
,
0f
)
}
}
window
.
isUndecorated
=
true
window
.
isVisible
=
true
delay
(
1000
)
screenshots
.
assert
(
window
.
bounds
)
}
finally
{
window
.
close
()
}
}
private
fun
swingTest
(
block
:
suspend
CoroutineScope
.()
->
Unit
)
{
runBlocking
(
Dispatchers
.
Swing
)
{
block
()
}
}
private
class
RectRenderer
(
private
val
layer
:
SkiaLayer
,
var
rectWidth
:
Int
,
var
rectHeight
:
Int
,
private
val
rectColor
:
Color
)
:
SkiaRenderer
{
override
suspend
fun
onRender
(
canvas
:
Canvas
,
width
:
Int
,
height
:
Int
,
nanoTime
:
Long
)
{
val
dpi
=
layer
.
contentScale
canvas
.
drawRect
(
Rect
(
0f
,
0f
,
width
.
toFloat
(),
height
.
toFloat
()),
Paint
().
apply
{
color
=
Color
.
WHITE
.
rgb
})
canvas
.
drawRect
(
Rect
(
0f
,
0f
,
rectWidth
*
dpi
,
rectHeight
*
dpi
),
Paint
().
apply
{
color
=
rectColor
.
rgb
})
}
}
private
class
AnimatedBoxRenderer
(
private
val
layer
:
SkiaLayer
,
private
val
pixelsPerSecond
:
Double
,
private
val
size
:
Double
)
:
SkiaRenderer
{
private
var
oldNanoTime
=
Long
.
MAX_VALUE
private
var
x
=
0.0
override
suspend
fun
onRender
(
canvas
:
Canvas
,
width
:
Int
,
height
:
Int
,
nanoTime
:
Long
)
{
canvas
.
clear
(
Color
.
WHITE
.
rgb
)
val
dt
=
(
nanoTime
-
oldNanoTime
).
coerceAtLeast
(
0
)
/
1
E9
oldNanoTime
=
nanoTime
x
+=
dt
*
pixelsPerSecond
if
(
x
-
size
>
width
)
{
x
=
0.0
}
canvas
.
drawRect
(
Rect
(
x
.
toFloat
(),
0f
,
x
.
toFloat
()
+
size
.
toFloat
(),
size
.
toFloat
()),
Paint
().
apply
{
color
=
Color
.
RED
.
rgb
})
layer
.
needRedraw
()
}
}
}
private
fun
JFrame
.
close
()
=
dispatchEvent
(
WindowEvent
(
this
,
WindowEvent
.
WINDOW_CLOSING
))
\ No newline at end of file
samples/SkijaInjectSample/src/test/screenshots/org_jetbrains_skiko_SkiaWindowTest_render_single_window_frame1.png
0 → 100644
View file @
ef910e66
974 Bytes
samples/SkijaInjectSample/src/test/screenshots/org_jetbrains_skiko_SkiaWindowTest_render_single_window_frame2.png
0 → 100644
View file @
ef910e66
937 Bytes
samples/SkijaInjectSample/src/test/screenshots/org_jetbrains_skiko_SkiaWindowTest_render_text_Linux.png
0 → 100644
View file @
ef910e66
1010 Bytes
samples/SkijaInjectSample/src/test/screenshots/org_jetbrains_skiko_SkiaWindowTest_render_text_MacOS.png
0 → 100644
View file @
ef910e66
1.19 KB
samples/SkijaInjectSample/src/test/screenshots/org_jetbrains_skiko_SkiaWindowTest_render_text_Windows.png
0 → 100644
View file @
ef910e66
984 Bytes
samples/SkijaInjectSample/src/test/screenshots/org_jetbrains_skiko_SkiaWindowTest_render_three_windows_window1.png
0 → 100644
View file @
ef910e66
974 Bytes
samples/SkijaInjectSample/src/test/screenshots/org_jetbrains_skiko_SkiaWindowTest_render_three_windows_window2.png
0 → 100644
View file @
ef910e66
1.11 KB
samples/SkijaInjectSample/src/test/screenshots/org_jetbrains_skiko_SkiaWindowTest_render_three_windows_window3.png
0 → 100644
View file @
ef910e66
1.03 KB
samples/SkijaInjectSample/src/test/screenshots/org_jetbrains_skiko_SkiaWindowTest_resize_window.png
0 → 100644
View file @
ef910e66
161 Bytes
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/SkiaWindow.kt
View file @
ef910e66
package
org.jetbrains.skiko
package
org.jetbrains.skiko
import
java.awt.event.ComponentAdapter
import
java.awt.event.ComponentEvent
import
javax.swing.JFrame
import
javax.swing.JFrame
open
class
SkiaWindow
:
JFrame
()
{
open
class
SkiaWindow
:
JFrame
()
{
...
@@ -10,4 +8,9 @@ open class SkiaWindow : JFrame() {
...
@@ -10,4 +8,9 @@ open class SkiaWindow : JFrame() {
init
{
init
{
contentPane
.
add
(
layer
)
contentPane
.
add
(
layer
)
}
}
override
fun
dispose
()
{
layer
.
dispose
()
super
.
dispose
()
}
}
}
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