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
79e5d248
Unverified
Commit
79e5d248
authored
Nov 11, 2021
by
Aleksandr Veselov
Committed by
GitHub
Nov 11, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement Picture for native (#361)
parent
e76e4a31
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
457 additions
and
104 deletions
+457
-104
Expects.kt
skiko/src/commonMain/kotlin/org/jetbrains/skia/Expects.kt
+0
-9
Picture.kt
skiko/src/commonMain/kotlin/org/jetbrains/skia/Picture.kt
+26
-10
Native.kt
...o/src/commonMain/kotlin/org/jetbrains/skia/impl/Native.kt
+1
-0
PictureTest.kt
...o/src/commonTest/kotlin/org/jetbrains/skia/PictureTest.kt
+56
-0
Native.js.kt
skiko/src/jsMain/kotlin/org/jetbrains/skia/impl/Native.js.kt
+33
-0
setup.js
skiko/src/jsMain/resources/setup.js
+69
-0
Picture.cc
skiko/src/jvmMain/cpp/common/Picture.cc
+19
-16
Library.cc
skiko/src/jvmMain/cpp/common/impl/Library.cc
+2
-0
interop.cc
skiko/src/jvmMain/cpp/common/interop.cc
+50
-19
interop.hh
skiko/src/jvmMain/cpp/common/interop.hh
+75
-9
Native.jvm.kt
.../src/jvmMain/kotlin/org/jetbrains/skia/impl/Native.jvm.kt
+1
-0
Picture.cc
skiko/src/nativeJsMain/cpp/Picture.cc
+31
-36
common.h
skiko/src/nativeJsMain/cpp/common.h
+28
-0
common_interop.cc
skiko/src/nativeJsMain/cpp/common_interop.cc
+38
-2
Native.native.kt
...ativeMain/kotlin/org/jetbrains/skia/impl/Native.native.kt
+28
-3
No files found.
skiko/src/commonMain/kotlin/org/jetbrains/skia/Expects.kt
View file @
79e5d248
...
...
@@ -21,15 +21,6 @@ expect class Matcher {
expect
fun
compilePattern
(
regex
:
String
):
Pattern
interface
BooleanSupplier
{
/**
* Gets a result.
*
* @return a result
*/
val
asBoolean
:
Boolean
}
@OptIn
(
ExperimentalMultiplatform
::
class
)
@OptionalExpectation
expect
annotation
class
ExternalSymbolName
(
val
name
:
String
)
skiko/src/commonMain/kotlin/org/jetbrains/skia/Picture.kt
View file @
79e5d248
...
...
@@ -73,10 +73,12 @@ class Picture internal constructor(ptr: NativePointer) : RefCnt(ptr) {
*
* @see [https://fiddle.skia.org/c/@Picture_playback](https://fiddle.skia.org/c/@Picture_playback)
*/
fun
playback
(
canvas
:
Canvas
?,
abort
:
BooleanSupplier
?
=
null
):
Picture
{
fun
playback
(
canvas
:
Canvas
?,
abort
:
(()
->
Boolean
)
?
=
null
):
Picture
{
return
try
{
Stats
.
onNativeCall
()
_nPlayback
(
_ptr
,
getPtr
(
canvas
),
abort
)
interopScope
{
_nPlayback
(
_ptr
,
getPtr
(
canvas
),
toInterop
(
abort
))
}
this
}
finally
{
reachabilityBarrier
(
canvas
)
...
...
@@ -99,7 +101,7 @@ class Picture internal constructor(ptr: NativePointer) : RefCnt(ptr) {
val
cullRect
:
Rect
get
()
=
try
{
Stats
.
onNativeCall
()
_nGetCullRect
(
_ptr
)
Rect
.
fromInteropPointer
{
_nGetCullRect
(
_ptr
,
it
)
}
}
finally
{
reachabilityBarrier
(
this
)
}
...
...
@@ -209,7 +211,18 @@ class Picture internal constructor(ptr: NativePointer) : RefCnt(ptr) {
val
arr
=
localMatrix
?.
mat
Shader
(
interopScope
{
_nMakeShader
(
_ptr
,
tmx
.
ordinal
,
tmy
.
ordinal
,
mode
.
ordinal
,
toInterop
(
arr
),
tileRect
)
_nMakeShader
(
_ptr
,
tmx
.
ordinal
,
tmy
.
ordinal
,
mode
.
ordinal
,
toInterop
(
arr
),
tileRect
!=
null
,
tileRect
?.
left
?:
0f
,
tileRect
?.
top
?:
0f
,
tileRect
?.
right
?:
0f
,
tileRect
?.
bottom
?:
0f
)
}
)
}
finally
{
...
...
@@ -218,15 +231,11 @@ class Picture internal constructor(ptr: NativePointer) : RefCnt(ptr) {
}
}
@ExternalSymbolName
(
"org_jetbrains_skia_Picture__1nMakeFromData"
)
private
external
fun
Picture_nMakeFromData
(
dataPtr
:
NativePointer
/*, SkDeserialProcs */
):
NativePointer
@ExternalSymbolName
(
"org_jetbrains_skia_Picture__1nPlayback"
)
private
external
fun
_nPlayback
(
ptr
:
NativePointer
,
canvasPtr
:
NativePointer
,
abort
:
BooleanSupplier
?)
@ExternalSymbolName
(
"org_jetbrains_skia_Picture__1nGetCullRect"
)
private
external
fun
_nGetCullRect
(
ptr
:
NativePointer
):
Rect
private
external
fun
_nGetCullRect
(
ptr
:
NativePointer
,
ltrb
:
InteropPointer
)
@ExternalSymbolName
(
"org_jetbrains_skia_Picture__1nGetUniqueId"
)
private
external
fun
_nGetUniqueId
(
ptr
:
NativePointer
):
Int
...
...
@@ -250,5 +259,12 @@ private external fun _nMakeShader(
tmy
:
Int
,
filterMode
:
Int
,
localMatrix
:
InteropPointer
,
tileRect
:
Rect
?
hasTile
:
Boolean
,
tileL
:
Float
,
tileT
:
Float
,
tileR
:
Float
,
tileB
:
Float
,
):
NativePointer
@ExternalSymbolName
(
"org_jetbrains_skia_Picture__1nPlayback"
)
private
external
fun
_nPlayback
(
ptr
:
NativePointer
,
canvasPtr
:
NativePointer
,
data
:
InteropPointer
)
\ No newline at end of file
skiko/src/commonMain/kotlin/org/jetbrains/skia/impl/Native.kt
View file @
79e5d248
...
...
@@ -42,6 +42,7 @@ expect class InteropScope() {
fun
InteropPointer
.
fromInteropNativePointerArray
():
NativePointerArray
inline
fun
<
reified
T
>
InteropPointer
.
fromInterop
(
decoder
:
ArrayInteropDecoder
<
T
>):
Array
<
T
>
fun
toInteropForArraysOfPointers
(
interopPointers
:
Array
<
InteropPointer
>):
InteropPointer
fun
toInterop
(
callback
:
(()
->
Boolean
)?):
InteropPointer
fun
release
()
}
...
...
skiko/src/commonTest/kotlin/org/jetbrains/skia/PictureTest.kt
0 → 100644
View file @
79e5d248
package
org.jetbrains.skia
import
org.jetbrains.skia.tests.assertCloseEnough
import
kotlin.test.Test
import
kotlin.test.assertEquals
class
PictureTest
{
@Test
fun
canMakeShader
()
{
val
pic
=
Picture
.
makePlaceholder
(
Rect
(
0.0f
,
0.0f
,
32.0f
,
32.0f
))
val
localMatrix
=
Matrix33
(
1.0f
,
0.0f
,
0.0f
,
0.0f
,
1.0f
,
0.0f
,
0.0f
,
0.0f
,
1.0f
)
val
tile
=
Rect
(
0.0f
,
0.0f
,
16.0f
,
16.0f
)
pic
.
makeShader
(
FilterTileMode
.
MIRROR
,
FilterTileMode
.
MIRROR
,
FilterMode
.
LINEAR
)
pic
.
makeShader
(
FilterTileMode
.
MIRROR
,
FilterTileMode
.
MIRROR
,
FilterMode
.
LINEAR
,
localMatrix
)
pic
.
makeShader
(
FilterTileMode
.
MIRROR
,
FilterTileMode
.
MIRROR
,
FilterMode
.
LINEAR
,
localMatrix
,
tile
)
}
@Test
fun
canGetCullRect
()
{
val
size
=
Rect
(
0.0f
,
0.0f
,
32.0f
,
32.0f
)
val
pic
=
Picture
.
makePlaceholder
(
size
)
val
cullRect
=
pic
.
cullRect
assertCloseEnough
(
size
,
cullRect
)
}
@Test
fun
canReplay
()
{
val
size
=
Rect
(
0.0f
,
0.0f
,
32.0f
,
32.0f
)
val
recorder
=
PictureRecorder
()
val
canvas
=
recorder
.
beginRecording
(
size
)
canvas
.
drawRect
(
Rect
(
10.0f
,
10.0f
,
20.0f
,
20.0f
),
Paint
().
apply
{
color
=
Color
.
RED
})
val
pic
=
recorder
.
finishRecordingAsPicture
()
val
surface
=
Surface
.
makeRasterN32Premul
(
32
,
32
)
pic
.
playback
(
surface
.
canvas
)
assertEquals
(
Color
.
RED
,
Bitmap
.
makeFromImage
(
surface
.
makeImageSnapshot
()).
getColor
(
15
,
15
))
}
@Test
fun
canReplayWithCallback
()
{
val
size
=
Rect
(
0.0f
,
0.0f
,
32.0f
,
32.0f
)
val
recorder
=
PictureRecorder
()
val
canvas
=
recorder
.
beginRecording
(
size
)
canvas
.
drawRect
(
Rect
(
10.0f
,
10.0f
,
20.0f
,
20.0f
),
Paint
().
apply
{
color
=
Color
.
RED
})
canvas
.
drawRect
(
Rect
(
12.0f
,
12.0f
,
18.0f
,
18.0f
),
Paint
().
apply
{
color
=
Color
.
WHITE
})
val
pic
=
recorder
.
finishRecordingAsPicture
()
val
surface
=
Surface
.
makeRasterN32Premul
(
32
,
32
)
var
drawCount
=
0
pic
.
playback
(
surface
.
canvas
)
{
drawCount
+=
1
;
drawCount
>
1
}
// Draw only once
assertEquals
(
2
,
drawCount
)
assertEquals
(
Color
.
RED
,
Bitmap
.
makeFromImage
(
surface
.
makeImageSnapshot
()).
getColor
(
15
,
15
))
}
}
skiko/src/jsMain/kotlin/org/jetbrains/skia/impl/Native.js.kt
View file @
79e5d248
...
...
@@ -51,6 +51,7 @@ actual inline fun <T> interopScope(block: InteropScope.() -> T): T {
actual
class
InteropScope
actual
constructor
()
{
private
val
elements
=
mutableListOf
<
NativePointer
>()
private
var
callbacksInitialized
=
false
actual
fun
toInterop
(
string
:
String
?):
InteropPointer
{
return
if
(
string
!=
null
)
{
...
...
@@ -194,13 +195,45 @@ actual class InteropScope actual constructor() {
return
toInterop
(
interopPointers
.
toIntArray
())
}
actual
fun
toInterop
(
callback
:
(()
->
Boolean
)?):
InteropPointer
{
if
(
callback
==
null
)
{
return
0
}
initCallbacks
()
val
data
=
CallbackData
<
Boolean
>(
null
)
return
_registerCallback
({
data
.
value
=
callback
()
},
data
)
}
actual
fun
release
()
{
elements
.
forEach
{
_free
(
it
)
}
releaseCallbacks
()
}
private
inline
fun
initCallbacks
()
{
if
(!
callbacksInitialized
)
{
_createLocalCallbackScope
()
callbacksInitialized
=
true
}
}
private
inline
fun
releaseCallbacks
()
{
if
(
callbacksInitialized
)
{
_releaseLocalCallbackScope
()
callbacksInitialized
=
false
}
}
}
// Callbacks
private
class
CallbackData
<
T
>(
@JsName
(
"value"
)
var
value
:
T
?)
// See `setup.js`
private
external
fun
_registerCallback
(
cb
:
()
->
Unit
,
data
:
Any
?):
Int
private
external
fun
_createLocalCallbackScope
()
private
external
fun
_releaseLocalCallbackScope
()
// Those functions are defined by Emscripten.
private
external
fun
_malloc
(
size
:
Int
):
NativePointer
...
...
skiko/src/jsMain/resources/setup.js
View file @
79e5d248
var
{
_callCallback
,
_registerCallback
,
_releaseCallback
,
_createLocalCallbackScope
,
_releaseLocalCallbackScope
}
=
(()
=>
{
const
CB_NULL
=
{
callback
:
()
=>
{
throw
new
RangeError
(
"attempted to call a callback at NULL"
)
},
data
:
null
};
const
CB_UNDEFINED
=
{
callback
:
()
=>
{
throw
new
RangeError
(
"attempted to call an uninitialized callback"
)
},
data
:
null
};
class
Scope
{
constructor
()
{
this
.
callbackMap
=
[
CB_NULL
];
}
addCallback
(
callback
,
data
)
{
this
.
callbackMap
.
push
({
callback
,
data
});
return
this
.
callbackMap
.
length
-
1
;
}
getCallback
(
id
)
{
return
this
.
callbackMap
[
id
]
||
CB_UNDEFINED
}
deleteCallback
(
id
)
{
this
.
callbackMap
[
id
]
=
CB_UNDEFINED
}
release
()
{
this
.
callbackMap
=
null
;
}
}
const
GLOBAL_SCOPE
=
new
Scope
();
let
scope
=
GLOBAL_SCOPE
;
return
{
_callCallback
(
callbackId
)
{
let
callback
=
scope
.
getCallback
(
callbackId
);
try
{
callback
.
callback
();
return
callback
.
data
;
}
catch
(
e
)
{
console
.
error
(
e
)
}
},
_registerCallback
(
callback
,
data
=
null
)
{
return
scope
.
addCallback
(
callback
,
data
);
},
_releaseCallback
(
callbackId
)
{
scope
.
deleteCallback
(
callbackId
);
},
_createLocalCallbackScope
()
{
if
(
scope
!==
GLOBAL_SCOPE
)
{
throw
new
Error
(
"attempted to overwrite local scope"
)
}
scope
=
new
Scope
()
},
_releaseLocalCallbackScope
()
{
if
(
scope
===
GLOBAL_SCOPE
)
{
throw
new
Error
(
"attempted to release global scope"
)
}
scope
.
release
()
scope
=
GLOBAL_SCOPE
},
}
})();
var
wasmSetup
=
new
Promise
(
function
(
resolve
,
reject
)
{
Module
[
'onRuntimeInitialized'
]
=
_
=>
{
resolve
(
Module
);
...
...
skiko/src/jvmMain/cpp/common/Picture.cc
View file @
79e5d248
...
...
@@ -12,21 +12,18 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_PictureKt_Picture_1nM
return
reinterpret_cast
<
jlong
>
(
instance
);
}
class
BooleanSupplierAbort
:
public
SkPicture
::
AbortCallback
{
class
JAbortCallback
:
public
SkPicture
::
AbortCallback
{
public
:
BooleanSupplierAbort
(
JNIEnv
*
env
,
jobject
supplier
)
{
this
->
env
=
env
;
this
->
supplier
=
supplier
;
}
JAbortCallback
(
JNIEnv
*
env
,
jobject
supplier
)
:
callback
(
env
,
supplier
)
{}
bool
abort
()
override
{
bool
res
=
env
->
CallBooleanMethod
(
supplier
,
java
::
util
::
function
::
BooleanSupplier
::
apply
);
if
(
java
::
lang
::
Throwable
::
exceptionThrown
(
env
))
bool
res
=
static_cast
<
bool
>
(
callback
()
);
if
(
callback
.
isExceptionThrown
(
))
return
false
;
return
res
;
}
private
:
JNIEnv
*
env
;
jobject
supplier
;
JBooleanCallback
callback
;
};
extern
"C"
JNIEXPORT
void
JNICALL
Java_org_jetbrains_skia_PictureKt__1nPlayback
...
...
@@ -36,15 +33,16 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_PictureKt__1nPlayback
if
(
abort
==
nullptr
)
{
instance
->
playback
(
canvas
,
nullptr
);
}
else
{
BooleanSupplierAbort
callback
(
env
,
abort
);
JAbortCallback
callback
(
env
,
abort
);
instance
->
playback
(
canvas
,
&
callback
);
}
}
extern
"C"
JNIEXPORT
jobject
JNICALL
Java_org_jetbrains_skia_PictureKt__1nGetCullRect
(
JNIEnv
*
env
,
jclass
jclass
,
jlong
ptr
)
{
extern
"C"
JNIEXPORT
void
JNICALL
Java_org_jetbrains_skia_PictureKt__1nGetCullRect
(
JNIEnv
*
env
,
jclass
jclass
,
jlong
ptr
,
jfloatArray
ltrbArray
)
{
SkPicture
*
instance
=
reinterpret_cast
<
SkPicture
*>
(
static_cast
<
uintptr_t
>
(
ptr
));
return
skija
::
Rect
::
fromSkRect
(
env
,
instance
->
cullRect
());
SkRect
cullRect
=
instance
->
cullRect
();
env
->
SetFloatArrayRegion
(
ltrbArray
,
0
,
4
,
reinterpret_cast
<
const
jfloat
*>
(
cullRect
.
asScalars
()));
}
extern
"C"
JNIEXPORT
jint
JNICALL
Java_org_jetbrains_skia_PictureKt__1nGetUniqueId
...
...
@@ -80,13 +78,18 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skia_PictureKt__1nGetAppro
}
extern
"C"
JNIEXPORT
jlong
JNICALL
Java_org_jetbrains_skia_PictureKt__1nMakeShader
(
JNIEnv
*
env
,
jclass
jclass
,
jlong
ptr
,
jint
tmxValue
,
jint
tmyValue
,
jint
filterModeValue
,
jfloatArray
localMatrixArr
,
j
object
tileRectObj
)
{
(
JNIEnv
*
env
,
jclass
jclass
,
jlong
ptr
,
jint
tmxValue
,
jint
tmyValue
,
jint
filterModeValue
,
jfloatArray
localMatrixArr
,
j
boolean
hasTile
,
jfloat
tileLeft
,
jfloat
tileTop
,
jfloat
tileRight
,
jfloat
tileBottom
)
{
SkPicture
*
instance
=
reinterpret_cast
<
SkPicture
*>
(
static_cast
<
uintptr_t
>
(
ptr
));
SkTileMode
tmx
=
static_cast
<
SkTileMode
>
(
tmxValue
);
SkTileMode
tmy
=
static_cast
<
SkTileMode
>
(
tmyValue
);
SkFilterMode
filterMode
=
static_cast
<
SkFilterMode
>
(
filterModeValue
);
std
::
unique_ptr
<
SkMatrix
>
localMatrix
=
skMatrix
(
env
,
localMatrixArr
);
std
::
unique_ptr
<
SkRect
>
tileRect
=
skija
::
Rect
::
toSkRect
(
env
,
tileRectObj
);
SkShader
*
shader
=
instance
->
makeShader
(
tmx
,
tmy
,
filterMode
,
localMatrix
.
get
(),
tileRect
.
get
()).
release
();
SkShader
*
shader
;
if
(
hasTile
)
{
SkRect
tileRect
=
SkRect
::
MakeLTRB
(
tileLeft
,
tileRight
,
tileBottom
,
tileTop
);
shader
=
instance
->
makeShader
(
tmx
,
tmy
,
filterMode
,
localMatrix
.
get
(),
&
tileRect
).
release
();
}
else
{
shader
=
instance
->
makeShader
(
tmx
,
tmy
,
filterMode
,
localMatrix
.
get
(),
nullptr
).
release
();
}
return
reinterpret_cast
<
jlong
>
(
shader
);
}
\ No newline at end of file
skiko/src/jvmMain/cpp/common/impl/Library.cc
View file @
79e5d248
...
...
@@ -17,6 +17,7 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_impl_Library__1nAfterL
(
JNIEnv
*
env
,
jclass
jclass
)
{
env
->
EnsureLocalCapacity
(
64
);
java
::
onLoad
(
env
);
kotlin
::
onLoad
(
env
);
skija
::
onLoad
(
env
);
skija
::
shaper
::
onLoad
(
env
);
skija
::
skottie
::
onLoad
(
env
);
...
...
@@ -34,5 +35,6 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {
skija
::
skottie
::
onUnload
(
env
);
skija
::
shaper
::
onUnload
(
env
);
skija
::
onUnload
(
env
);
kotlin
::
onUnload
(
env
);
java
::
onUnload
(
env
);
}
skiko/src/jvmMain/cpp/common/interop.cc
View file @
79e5d248
...
...
@@ -25,6 +25,21 @@ namespace java {
}
namespace
lang
{
namespace
Boolean
{
jclass
cls
;
jmethodID
booleanValue
;
void
onLoad
(
JNIEnv
*
env
)
{
jclass
local
=
env
->
FindClass
(
"java/lang/Boolean"
);
cls
=
static_cast
<
jclass
>
(
env
->
NewGlobalRef
(
local
));
booleanValue
=
env
->
GetMethodID
(
cls
,
"booleanValue"
,
"()Z"
);
}
void
onUnload
(
JNIEnv
*
env
)
{
env
->
DeleteGlobalRef
(
cls
);
}
}
namespace
Float
{
jclass
cls
;
jmethodID
ctor
;
...
...
@@ -103,41 +118,24 @@ namespace java {
env
->
DeleteGlobalRef
(
cls
);
}
}
namespace
function
{
namespace
BooleanSupplier
{
jclass
cls
;
jmethodID
apply
;
void
onLoad
(
JNIEnv
*
env
)
{
jclass
local
=
env
->
FindClass
(
"java/util/function/BooleanSupplier"
);
cls
=
static_cast
<
jclass
>
(
env
->
NewGlobalRef
(
local
));
apply
=
env
->
GetMethodID
(
cls
,
"getAsBoolean"
,
"()Z"
);
}
void
onUnload
(
JNIEnv
*
env
)
{
env
->
DeleteGlobalRef
(
cls
);
}
}
}
}
void
onLoad
(
JNIEnv
*
env
)
{
io
::
OutputStream
::
onLoad
(
env
);
lang
::
Boolean
::
onLoad
(
env
);
lang
::
Float
::
onLoad
(
env
);
lang
::
RuntimeException
::
onLoad
(
env
);
lang
::
String
::
onLoad
(
env
);
lang
::
Throwable
::
onLoad
(
env
);
util
::
Iterator
::
onLoad
(
env
);
util
::
function
::
BooleanSupplier
::
onLoad
(
env
);
}
void
onUnload
(
JNIEnv
*
env
)
{
util
::
function
::
BooleanSupplier
::
onUnload
(
env
);
util
::
Iterator
::
onUnload
(
env
);
lang
::
String
::
onUnload
(
env
);
lang
::
RuntimeException
::
onUnload
(
env
);
lang
::
Float
::
onUnload
(
env
);
lang
::
Boolean
::
onUnload
(
env
);
}
}
...
...
@@ -1202,3 +1200,36 @@ namespace skija {
}
}
}
namespace
kotlin
{
namespace
jvm
{
namespace
functions
{
namespace
Function0
{
jclass
cls
;
jmethodID
invoke
;
void
onLoad
(
JNIEnv
*
env
)
{
jclass
local
=
env
->
FindClass
(
"kotlin/jvm/functions/Function0"
);
cls
=
static_cast
<
jclass
>
(
env
->
NewGlobalRef
(
local
));
invoke
=
env
->
GetMethodID
(
cls
,
"invoke"
,
"()Ljava/lang/Object;"
);
}
void
onUnload
(
JNIEnv
*
env
)
{
env
->
DeleteGlobalRef
(
cls
);
}
}
}
}
void
onLoad
(
JNIEnv
*
env
)
{
jvm
::
functions
::
Function0
::
onLoad
(
env
);
}
void
onUnload
(
JNIEnv
*
env
)
{
jvm
::
functions
::
Function0
::
onUnload
(
env
);
}
}
template
<>
jboolean
jObjectConvert
(
JNIEnv
*
env
,
jobject
obj
)
{
return
env
->
CallBooleanMethod
(
obj
,
java
::
lang
::
Boolean
::
booleanValue
);
}
skiko/src/jvmMain/cpp/common/interop.hh
View file @
79e5d248
...
...
@@ -30,6 +30,13 @@ namespace java {
}
namespace
lang
{
namespace
Boolean
{
extern
jclass
cls
;
extern
jmethodID
booleanValue
;
void
onLoad
(
JNIEnv
*
env
);
void
onUnload
(
JNIEnv
*
env
);
}
namespace
Float
{
extern
jclass
cls
;
extern
jmethodID
ctor
;
...
...
@@ -64,15 +71,6 @@ namespace java {
void
onLoad
(
JNIEnv
*
env
);
void
onUnload
(
JNIEnv
*
env
);
}
namespace
function
{
namespace
BooleanSupplier
{
extern
jclass
cls
;
extern
jmethodID
apply
;
void
onLoad
(
JNIEnv
*
env
);
void
onUnload
(
JNIEnv
*
env
);
}
}
}
void
onLoad
(
JNIEnv
*
env
);
...
...
@@ -335,6 +333,22 @@ namespace skija {
void
onUnload
(
JNIEnv
*
env
);
}
namespace
kotlin
{
namespace
jvm
{
namespace
functions
{
namespace
Function0
{
extern
jclass
cls
;
extern
jmethodID
invoke
;
void
onLoad
(
JNIEnv
*
env
);
void
onUnload
(
JNIEnv
*
env
);
}
}
}
void
onLoad
(
JNIEnv
*
env
);
void
onUnload
(
JNIEnv
*
env
);
}
std
::
unique_ptr
<
SkMatrix
>
skMatrix
(
JNIEnv
*
env
,
jfloatArray
arr
);
std
::
unique_ptr
<
SkM44
>
skM44
(
JNIEnv
*
env
,
jfloatArray
arr
);
...
...
@@ -394,3 +408,55 @@ static inline jfloat fromBits(jint i) {
u
.
i
=
i
;
return
u
.
f
;
}
template
<
typename
T
>
T
jObjectConvert
(
JNIEnv
*
env
,
jobject
obj
);
// Callback support
template
<
typename
T
>
class
JCallback
{
public
:
JCallback
(
JNIEnv
*
env
,
jobject
callback
)
:
env
(
env
),
callback
(
env
->
NewGlobalRef
(
callback
))
{
env
->
GetJavaVM
(
&
javaVM
);
}
~
JCallback
()
{
if
(
callback
!=
nullptr
)
{
JNIEnv
*
localEnv
;
if
(
javaVM
->
GetEnv
(
AS_JNI_ENV_PTR
(
&
localEnv
),
SKIKO_JNI_VERSION
)
==
JNI_OK
)
{
localEnv
->
DeleteGlobalRef
(
callback
);
}
}
}
JCallback
(
const
JCallback
&
)
=
delete
;
JCallback
&
operator
=
(
const
JCallback
&
)
=
delete
;
JCallback
(
JCallback
&&
other
)
noexcept
{
std
::
swap
(
env
,
other
.
env
);
std
::
swap
(
javaVM
,
other
.
javaVM
);
std
::
swap
(
callback
,
other
.
callback
);
}
JCallback
&
operator
=
(
JCallback
&&
other
)
{
std
::
swap
(
env
,
other
.
env
);
std
::
swap
(
javaVM
,
other
.
javaVM
);
std
::
swap
(
callback
,
other
.
callback
);
return
this
;
}
T
operator
()()
{
jobject
res
=
env
->
CallObjectMethod
(
callback
,
kotlin
::
jvm
::
functions
::
Function0
::
invoke
);
return
jObjectConvert
<
T
>
(
env
,
res
);
}
bool
isExceptionThrown
()
{
return
java
::
lang
::
Throwable
::
exceptionThrown
(
env
);
}
private
:
JNIEnv
*
env
;
JavaVM
*
javaVM
;
jobject
callback
;
};
typedef
JCallback
<
jboolean
>
JBooleanCallback
;
\ No newline at end of file
skiko/src/jvmMain/kotlin/org/jetbrains/skia/impl/Native.jvm.kt
View file @
79e5d248
...
...
@@ -78,6 +78,7 @@ actual open class InteropScope actual constructor() {
actual
inline
fun
<
reified
T
>
InteropPointer
.
fromInterop
(
decoder
:
ArrayInteropDecoder
<
T
>):
Array
<
T
>
=
this
@fromInterop
as
Array
<
T
>
actual
fun
toInteropForArraysOfPointers
(
interopPointers
:
Array
<
InteropPointer
>):
InteropPointer
=
interopPointers
actual
fun
toInterop
(
callback
:
(()
->
Boolean
)?)
=
callback
as
Any
?
actual
fun
release
()
{}
}
...
...
skiko/src/nativeJsMain/cpp/Picture.cc
View file @
79e5d248
...
...
@@ -7,6 +7,16 @@
#include "SkShader.h"
#include "common.h"
class
KotlinAbortCallback
:
public
SkPicture
::
AbortCallback
{
public
:
KotlinAbortCallback
(
KInteropPointer
data
)
:
callback
(
data
)
{}
bool
abort
()
override
{
return
static_cast
<
bool
>
(
callback
());
}
private
:
KBooleanCallback
callback
;
};
SKIKO_EXPORT
KNativePointer
org_jetbrains_skia_Picture__1nMakeFromData
(
KNativePointer
dataPtr
)
{
SkData
*
data
=
reinterpret_cast
<
SkData
*>
((
dataPtr
));
...
...
@@ -14,41 +24,28 @@ SKIKO_EXPORT KNativePointer org_jetbrains_skia_Picture__1nMakeFromData
return
reinterpret_cast
<
KNativePointer
>
(
instance
);
}
SKIKO_EXPORT
void
org_jetbrains_skia_Picture__1nPlayback
(
KNativePointer
ptr
,
KNativePointer
canvasPtr
,
KInteropPointer
abort
)
{
TODO
(
"implement org_jetbrains_skia_Picture__1nPlayback"
);
}
#if 0
SKIKO_EXPORT
void
org_jetbrains_skia_Picture__1nPlayback
(
KNativePointer
ptr
,
KNativePointer
canvasPtr
,
KInteropPointer
abort
)
{
SkPicture
*
instance
=
reinterpret_cast
<
SkPicture
*>
((
ptr
));
SkCanvas
*
canvas
=
reinterpret_cast
<
SkCanvas
*>
((
canvasPtr
));
if (abort == nullptr) {
instance->playback(canvas, nullptr);
if
(
abort
)
{
KotlinAbortCallback
abortCallback
(
abort
);
instance
->
playback
(
canvas
,
&
abortCallback
);
}
else
{
BooleanSupplierAbort callback(env, abort);
instance->playback(canvas, &callback);
instance
->
playback
(
canvas
,
nullptr
);
}
}
#endif
SKIKO_EXPORT
KInteropPointer
org_jetbrains_skia_Picture__1nGetCullRect
(
KNativePointer
ptr
)
{
TODO
(
"implement org_jetbrains_skia_Picture__1nGetCullRect"
);
}
#if 0
SKIKO_EXPORT KInteropPointer org_jetbrains_skia_Picture__1nGetCullRect
(KNativePointer ptr) {
SKIKO_EXPORT
void
org_jetbrains_skia_Picture__1nGetCullRect
(
KNativePointer
ptr
,
KInteropPointer
ltrbArray
)
{
SkPicture
*
instance
=
reinterpret_cast
<
SkPicture
*>
((
ptr
));
return skija::Rect::fromSkRect(env, instance->cullRect());
SkRect
cullRect
=
instance
->
cullRect
();
float
*
ltrb
=
reinterpret_cast
<
float
*>
(
ltrbArray
);
ltrb
[
0
]
=
cullRect
.
left
();
ltrb
[
1
]
=
cullRect
.
top
();
ltrb
[
2
]
=
cullRect
.
right
();
ltrb
[
3
]
=
cullRect
.
bottom
();
}
#endif
SKIKO_EXPORT
KInt
org_jetbrains_skia_Picture__1nGetUniqueId
(
KNativePointer
ptr
)
{
...
...
@@ -84,21 +81,19 @@ SKIKO_EXPORT KLong org_jetbrains_skia_Picture__1nGetApproximateBytesUsed
SKIKO_EXPORT
KNativePointer
org_jetbrains_skia_Picture__1nMakeShader
(
KNativePointer
ptr
,
KInt
tmxValue
,
KInt
tmyValue
,
KInt
filterModeValue
,
KFloat
*
localMatrixArr
,
KInteropPointer
tileRectObj
)
{
TODO
(
"implement org_jetbrains_skia_Picture__1nMakeShader"
);
}
#if 0
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Picture__1nMakeShader
(KNativePointer ptr, KInt tmxValue, KInt tmyValue, KInt filterModeValue, KFloat* localMatrixArr, KInteropPointer tileRectObj) {
(
KNativePointer
ptr
,
KInt
tmxValue
,
KInt
tmyValue
,
KInt
filterModeValue
,
KFloat
*
localMatrixArr
,
KBoolean
hasTile
,
KFloat
tileLeft
,
KFloat
tileTop
,
KFloat
tileRight
,
KFloat
tileBottom
)
{
SkPicture
*
instance
=
reinterpret_cast
<
SkPicture
*>
((
ptr
));
SkTileMode
tmx
=
static_cast
<
SkTileMode
>
(
tmxValue
);
SkTileMode
tmy
=
static_cast
<
SkTileMode
>
(
tmyValue
);
SkFilterMode
filterMode
=
static_cast
<
SkFilterMode
>
(
filterModeValue
);
std::unique_ptr<SkMatrix> localMatrix = skMatrix(env, localMatrixArr);
std::unique_ptr<SkRect> tileRect = skija::Rect::toSkRect(env, tileRectObj);
SkShader* shader = instance->makeShader(tmx, tmy, filterMode, localMatrix.get(), tileRect.get()).release();
std
::
unique_ptr
<
SkMatrix
>
localMatrix
=
skMatrix
(
localMatrixArr
);
SkShader
*
shader
;
if
(
hasTile
)
{
SkRect
tileRect
=
SkRect
::
MakeLTRB
(
tileLeft
,
tileRight
,
tileBottom
,
tileTop
);
shader
=
instance
->
makeShader
(
tmx
,
tmy
,
filterMode
,
localMatrix
.
get
(),
&
tileRect
).
release
();
}
else
{
shader
=
instance
->
makeShader
(
tmx
,
tmy
,
filterMode
,
localMatrix
.
get
(),
nullptr
).
release
();
}
return
reinterpret_cast
<
KNativePointer
>
(
shader
);
}
#endif
skiko/src/nativeJsMain/cpp/common.h
View file @
79e5d248
...
...
@@ -157,5 +157,33 @@ static inline KFloat fromBits(KInt i) {
u
.
i
=
i
;
return
u
.
f
;
}
// Callback support
typedef
void
(
*
SkikoDisposeCallback
)(
KInteropPointer
);
typedef
KBoolean
(
*
SkikoCallBooleanCallback
)(
KInteropPointer
);
typedef
void
*
KOpaquePointer
;
void
disposeCallback
(
KInteropPointer
cb
);
KBoolean
callBooleanCallback
(
KInteropPointer
cb
);
template
<
typename
T
,
T
(
*
Apply
)(
KInteropPointer
)
>
class
KCallback
{
public
:
explicit
KCallback
(
KInteropPointer
data
)
:
data
(
data
)
{}
virtual
~
KCallback
()
{
disposeCallback
(
data
);
}
KCallback
(
const
KCallback
&
)
=
delete
;
KCallback
(
KCallback
&&
)
=
delete
;
KCallback
&
operator
=
(
const
KCallback
&
)
=
delete
;
KCallback
&
operator
=
(
KCallback
&&
)
=
delete
;
T
operator
()()
const
{
return
Apply
(
data
);
}
private
:
KInteropPointer
data
;
};
typedef
KCallback
<
KBoolean
,
callBooleanCallback
>
KBooleanCallback
;
#endif
/* SKIKO_COMMON_H */
skiko/src/nativeJsMain/cpp/common_interop.cc
View file @
79e5d248
...
...
@@ -127,9 +127,9 @@ std::unique_ptr<SkMatrix> skMatrix(KFloat* matrixArray) {
return
std
::
unique_ptr
<
SkMatrix
>
(
nullptr
);
else
{
KFloat
*
m
=
matrixArray
;
SkMatrix
*
ptr
=
new
SkMatrix
();
std
::
unique_ptr
<
SkMatrix
>
ptr
=
std
::
make_unique
<
SkMatrix
>
();
ptr
->
setAll
(
m
[
0
],
m
[
1
],
m
[
2
],
m
[
3
],
m
[
4
],
m
[
5
],
m
[
6
],
m
[
7
],
m
[
8
]);
return
std
::
unique_ptr
<
SkMatrix
>
(
ptr
)
;
return
ptr
;
}
}
...
...
@@ -326,3 +326,39 @@ namespace skija {
}
}
}
// Callback support
#ifdef __EMSCRIPTEN__
void
disposeCallback
(
KInteropPointer
cb
)
{
EM_ASM
({
_releaseCallback
(
$
0
)
},
cb
);
}
KBoolean
callBooleanCallback
(
KInteropPointer
cb
)
{
int
value
=
EM_ASM_INT
({
return
_callCallback
(
$
0
).
value
?
1
:
0
;
},
cb
);
return
static_cast
<
KBoolean
>
(
value
);
}
#else // __EMSCRIPTEN__
static
SkikoDisposeCallback
disposeCallbackImpl
=
nullptr
;
static
SkikoCallBooleanCallback
callBooleanCallbackImpl
=
nullptr
;
SKIKO_EXPORT
void
skiko_initCallbacks
(
KOpaquePointer
callBoolean
,
KOpaquePointer
dispose
)
{
callBooleanCallbackImpl
=
reinterpret_cast
<
SkikoCallBooleanCallback
>
(
callBoolean
);
disposeCallbackImpl
=
reinterpret_cast
<
SkikoDisposeCallback
>
(
dispose
);
}
void
disposeCallback
(
KInteropPointer
cb
)
{
disposeCallbackImpl
(
cb
);
}
KBoolean
callBooleanCallback
(
KInteropPointer
cb
)
{
return
callBooleanCallbackImpl
(
cb
);
}
#endif // __EMSCRIPTEN__
skiko/src/nativeMain/kotlin/org/jetbrains/skia/impl/Native.native.kt
View file @
79e5d248
package
org.jetbrains.skia.impl
import
kotlinx.cinterop.Pinned
import
kotlinx.cinterop.addressOf
import
kotlinx.cinterop.pin
import
kotlinx.cinterop.*
import
org.jetbrains.skia.ExternalSymbolName
import
kotlin.native.internal.NativePtr
actual
abstract
class
Native
actual
constructor
(
ptr
:
NativePointer
)
{
...
...
@@ -24,6 +23,13 @@ actual abstract class Native actual constructor(ptr: NativePointer) {
}
actual
companion
object
{
init
{
initCallbacks
(
staticCFunction
(
::
callBooleanCallback
),
staticCFunction
(
::
disposeCallback
),
)
}
actual
val
NullPointer
:
NativePointer
get
()
=
NativePtr
.
NULL
}
...
...
@@ -194,6 +200,12 @@ actual class InteropScope actual constructor() {
return
toInterop
(
interopPointers
.
map
{
it
.
toLong
()
}.
toLongArray
())
}
actual
fun
toInterop
(
callback
:
(()
->
Boolean
)?):
InteropPointer
=
callback
?.
let
{
val
ptr
=
StableRef
.
create
(
it
).
asCPointer
()
NativePtr
.
NULL
.
plus
(
ptr
.
toLong
())
}
?:
NativePtr
.
NULL
actual
fun
release
()
{
elements
.
forEach
{
it
.
unpin
()
...
...
@@ -217,3 +229,16 @@ actual class NativePointerArray actual constructor(size: Int) {
actual
val
size
:
Int
get
()
=
backing
.
size
}
// Callbacks support
private
fun
callBooleanCallback
(
ptr
:
COpaquePointer
):
Boolean
{
return
ptr
.
asStableRef
<()
->
Boolean
>().
get
().
invoke
()
}
private
fun
disposeCallback
(
ptr
:
COpaquePointer
)
{
ptr
.
asStableRef
<
Any
>().
dispose
()
}
@ExternalSymbolName
(
"skiko_initCallbacks"
)
private
external
fun
initCallbacks
(
callBoolean
:
COpaquePointer
,
dispose
:
COpaquePointer
)
\ No newline at end of file
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