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
54fb2034
Unverified
Commit
54fb2034
authored
Nov 12, 2021
by
Aleksandr Veselov
Committed by
GitHub
Nov 12, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement Drawable for native (#373)
parent
82342b34
Changes
17
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
284 additions
and
116 deletions
+284
-116
build.gradle.kts
skiko/build.gradle.kts
+3
-1
Drawable.kt
skiko/src/commonMain/kotlin/org/jetbrains/skia/Drawable.kt
+39
-14
Picture.kt
skiko/src/commonMain/kotlin/org/jetbrains/skia/Picture.kt
+1
-1
Native.kt
...o/src/commonMain/kotlin/org/jetbrains/skia/impl/Native.kt
+9
-1
DrawableTest.kt
.../src/commonTest/kotlin/org/jetbrains/skia/DrawableTest.kt
+28
-0
Native.js.kt
skiko/src/jsMain/kotlin/org/jetbrains/skia/impl/Native.js.kt
+19
-3
setup.js
skiko/src/jsMain/resources/setup.js
+14
-11
Drawable.cc
skiko/src/jvmMain/cpp/common/Drawable.cc
+18
-4
interop.hh
skiko/src/jvmMain/cpp/common/interop.hh
+2
-2
Drawable.jvm.kt
skiko/src/jvmMain/kotlin/org/jetbrains/skia/Drawable.jvm.kt
+11
-0
Native.jvm.kt
.../src/jvmMain/kotlin/org/jetbrains/skia/impl/Native.jvm.kt
+7
-1
Canvas.cc
skiko/src/nativeJsMain/cpp/Canvas.cc
+1
-11
Drawable.cc
skiko/src/nativeJsMain/cpp/Drawable.cc
+62
-60
common.h
skiko/src/nativeJsMain/cpp/common.h
+22
-4
common_interop.cc
skiko/src/nativeJsMain/cpp/common_interop.cc
+13
-1
Drawable.nativejs.kt
...tiveJsMain/kotlin/org/jetbrains/skia/Drawable.nativejs.kt
+19
-0
Native.native.kt
...ativeMain/kotlin/org/jetbrains/skia/impl/Native.native.kt
+16
-2
No files found.
skiko/build.gradle.kts
View file @
54fb2034
...
@@ -81,7 +81,9 @@ val compileWasm = tasks.register<CompileSkikoCppTask>("compileWasm") {
...
@@ -81,7 +81,9 @@ val compileWasm = tasks.register<CompileSkikoCppTask>("compileWasm") {
flags
.
set
(
listOf
(
flags
.
set
(
listOf
(
*
skiaPreprocessorFlags
(),
*
skiaPreprocessorFlags
(),
"-DSKIKO_WASM"
"-DSKIKO_WASM"
,
"-fno-rtti"
,
"-fno-exceptions"
))
))
}
}
...
...
skiko/src/commonMain/kotlin/org/jetbrains/skia/Drawable.kt
View file @
54fb2034
...
@@ -2,6 +2,7 @@ package org.jetbrains.skia
...
@@ -2,6 +2,7 @@ package org.jetbrains.skia
import
org.jetbrains.skia.impl.*
import
org.jetbrains.skia.impl.*
import
org.jetbrains.skia.impl.Library.Companion.staticLoad
import
org.jetbrains.skia.impl.Library.Companion.staticLoad
import
org.jetbrains.skiko.maybeSynchronized
/**
/**
*
*
...
@@ -12,14 +13,15 @@ import org.jetbrains.skia.impl.Library.Companion.staticLoad
...
@@ -12,14 +13,15 @@ import org.jetbrains.skia.impl.Library.Companion.staticLoad
* allow for clients of the drawable that may want to cache the results, the drawable must
* allow for clients of the drawable that may want to cache the results, the drawable must
* change its generation id whenever its internal state changes such that it will draw differently.
* change its generation id whenever its internal state changes such that it will draw differently.
*/
*/
abstract
class
Drawable
:
RefCnt
(
Drawable_nMake
()
)
{
abstract
class
Drawable
:
Managed
(
Drawable_nMake
(),
_FinalizerHolder
.
PTR
)
{
companion
object
{
companion
object
{
init
{
init
{
staticLoad
()
staticLoad
()
}
}
}
}
internal
var
_bounds
:
Rect
?
=
null
private
var
_bounds
:
Rect
?
=
null
private
val
boundsLock
=
Unit
/**
/**
* Draws into the specified content. The drawing sequence will be balanced upon return
* Draws into the specified content. The drawing sequence will be balanced upon return
...
@@ -93,9 +95,11 @@ abstract class Drawable : RefCnt(Drawable_nMake()) {
...
@@ -93,9 +95,11 @@ abstract class Drawable : RefCnt(Drawable_nMake()) {
*/
*/
val
bounds
:
Rect
val
bounds
:
Rect
get
()
{
get
()
{
if
(
_bounds
==
null
)
_bounds
=
onGetBounds
()
maybeSynchronized
(
boundsLock
)
{
if
(
_bounds
==
null
)
_bounds
=
Rect
.
fromInteropPointer
{
Drawable_nGetBounds
(
_ptr
,
it
)
}
return
_bounds
!!
return
_bounds
!!
}
}
}
/**
/**
* Calling this invalidates the previous generation ID, and causes a new one to be computed
* Calling this invalidates the previous generation ID, and causes a new one to be computed
...
@@ -103,27 +107,34 @@ abstract class Drawable : RefCnt(Drawable_nMake()) {
...
@@ -103,27 +107,34 @@ abstract class Drawable : RefCnt(Drawable_nMake()) {
* in response to its internal state changing.
* in response to its internal state changing.
*/
*/
fun
notifyDrawingChanged
():
Drawable
{
fun
notifyDrawingChanged
():
Drawable
{
maybeSynchronized
(
boundsLock
)
{
Stats
.
onNativeCall
()
Stats
.
onNativeCall
()
_nNotifyDrawingChanged
(
_ptr
)
_nNotifyDrawingChanged
(
_ptr
)
_bounds
=
null
_bounds
=
null
}
return
this
return
this
}
}
abstract
fun
onDraw
(
canvas
:
Canvas
?)
abstract
fun
onDraw
(
canvas
:
Canvas
?)
abstract
fun
onGetBounds
():
Rect
abstract
fun
onGetBounds
():
Rect
fun
_onDraw
(
canvasPtr
:
NativePointer
)
{
private
fun
_onDraw
(
canvasPtr
:
NativePointer
)
{
onDraw
(
Canvas
(
canvasPtr
,
false
,
this
))
onDraw
(
Canvas
(
canvasPtr
,
false
,
this
))
}
}
private
object
_FinalizerHolder
{
val
PTR
=
Drawable_nGetFinalizer
()
}
init
{
init
{
Stats
.
onNativeCall
()
doInit
(
_ptr
)
Stats
.
onNativeCall
()
Drawable_nInit
(
this
,
_ptr
)
}
}
}
}
@ExternalSymbolName
(
"org_jetbrains_skia_Drawable__1nInit"
)
internal
expect
fun
Drawable
.
doInit
(
ptr
:
NativePointer
)
private
external
fun
Drawable_nInit
(
drawable
:
Drawable
,
ptr
:
NativePointer
)
@ExternalSymbolName
(
"org_jetbrains_skia_Drawable__1nGetFinalizer"
)
private
external
fun
Drawable_nGetFinalizer
():
NativePointer
@ExternalSymbolName
(
"org_jetbrains_skia_Drawable__1nMake"
)
@ExternalSymbolName
(
"org_jetbrains_skia_Drawable__1nMake"
)
private
external
fun
Drawable_nMake
():
NativePointer
private
external
fun
Drawable_nMake
():
NativePointer
...
@@ -139,3 +150,17 @@ private external fun _nMakePictureSnapshot(ptr: NativePointer): NativePointer
...
@@ -139,3 +150,17 @@ private external fun _nMakePictureSnapshot(ptr: NativePointer): NativePointer
@ExternalSymbolName
(
"org_jetbrains_skia_Drawable__1nNotifyDrawingChanged"
)
@ExternalSymbolName
(
"org_jetbrains_skia_Drawable__1nNotifyDrawingChanged"
)
private
external
fun
_nNotifyDrawingChanged
(
ptr
:
NativePointer
)
private
external
fun
_nNotifyDrawingChanged
(
ptr
:
NativePointer
)
@ExternalSymbolName
(
"org_jetbrains_skia_Drawable__1nGetBounds"
)
private
external
fun
Drawable_nGetBounds
(
ptr
:
NativePointer
,
result
:
InteropPointer
)
// For Native/JS usage only
@ExternalSymbolName
(
"org_jetbrains_skia_Drawable__1nInit"
)
internal
external
fun
Drawable_nInit
(
ptr
:
NativePointer
,
onGetBounds
:
InteropPointer
,
onDraw
:
InteropPointer
)
@ExternalSymbolName
(
"org_jetbrains_skia_Drawable__1nGetOnDrawCanvas"
)
internal
external
fun
_nGetOnDrawCanvas
(
ptr
:
NativePointer
):
NativePointer
@ExternalSymbolName
(
"org_jetbrains_skia_Drawable__1nSetBounds"
)
internal
external
fun
_nSetBounds
(
ptr
:
NativePointer
,
left
:
Float
,
top
:
Float
,
right
:
Float
,
bottom
:
Float
)
\ No newline at end of file
skiko/src/commonMain/kotlin/org/jetbrains/skia/Picture.kt
View file @
54fb2034
...
@@ -77,7 +77,7 @@ class Picture internal constructor(ptr: NativePointer) : RefCnt(ptr) {
...
@@ -77,7 +77,7 @@ class Picture internal constructor(ptr: NativePointer) : RefCnt(ptr) {
return
try
{
return
try
{
Stats
.
onNativeCall
()
Stats
.
onNativeCall
()
interopScope
{
interopScope
{
_nPlayback
(
_ptr
,
getPtr
(
canvas
),
toInterop
(
abort
))
_nPlayback
(
_ptr
,
getPtr
(
canvas
),
booleanCallback
(
abort
))
}
}
this
this
}
finally
{
}
finally
{
...
...
skiko/src/commonMain/kotlin/org/jetbrains/skia/impl/Native.kt
View file @
54fb2034
...
@@ -42,7 +42,15 @@ expect class InteropScope() {
...
@@ -42,7 +42,15 @@ expect class InteropScope() {
fun
InteropPointer
.
fromInteropNativePointerArray
():
NativePointerArray
fun
InteropPointer
.
fromInteropNativePointerArray
():
NativePointerArray
inline
fun
<
reified
T
>
InteropPointer
.
fromInterop
(
decoder
:
ArrayInteropDecoder
<
T
>):
Array
<
T
>
inline
fun
<
reified
T
>
InteropPointer
.
fromInterop
(
decoder
:
ArrayInteropDecoder
<
T
>):
Array
<
T
>
fun
toInteropForArraysOfPointers
(
interopPointers
:
Array
<
InteropPointer
>):
InteropPointer
fun
toInteropForArraysOfPointers
(
interopPointers
:
Array
<
InteropPointer
>):
InteropPointer
fun
toInterop
(
callback
:
(()
->
Boolean
)?):
InteropPointer
// Callbacks
fun
callback
(
callback
:
(()
->
Unit
)?):
InteropPointer
fun
booleanCallback
(
callback
:
(()
->
Boolean
)?):
InteropPointer
// Virtual methods
fun
virtual
(
method
:
()
->
Unit
):
InteropPointer
fun
virtualBoolean
(
method
:
()
->
Boolean
):
InteropPointer
fun
release
()
fun
release
()
}
}
...
...
skiko/src/commonTest/kotlin/org/jetbrains/skia/DrawableTest.kt
0 → 100644
View file @
54fb2034
package
org.jetbrains.skia
import
org.jetbrains.skia.tests.assertCloseEnough
import
kotlin.test.Test
import
kotlin.test.assertEquals
class
DrawableTest
{
@Test
fun
canDrawDrawable
()
{
val
cross
=
object
:
Drawable
()
{
override
fun
onDraw
(
canvas
:
Canvas
?)
{
val
paint
=
Paint
().
apply
{
color
=
Color
.
RED
}
canvas
!!
.
drawRect
(
Rect
(
4f
,
0f
,
12f
,
16f
),
paint
)
canvas
.
drawRect
(
Rect
(
0f
,
4f
,
16f
,
12f
),
paint
)
}
override
fun
onGetBounds
()
=
Rect
(
0f
,
0f
,
16f
,
16f
)
}
val
surface
=
Surface
.
makeRasterN32Premul
(
16
,
16
)
surface
.
canvas
.
drawDrawable
(
cross
)
val
pixels
=
Bitmap
.
makeFromImage
(
surface
.
makeImageSnapshot
())
assertEquals
(
Color
.
RED
,
pixels
.
getColor
(
8
,
8
))
assertEquals
(
Color
.
TRANSPARENT
,
pixels
.
getColor
(
2
,
2
))
assertCloseEnough
(
Rect
(
0f
,
0f
,
16f
,
16f
),
cross
.
bounds
)
}
}
\ No newline at end of file
skiko/src/jsMain/kotlin/org/jetbrains/skia/impl/Native.js.kt
View file @
54fb2034
...
@@ -195,12 +195,28 @@ actual class InteropScope actual constructor() {
...
@@ -195,12 +195,28 @@ actual class InteropScope actual constructor() {
return
toInterop
(
interopPointers
.
toIntArray
())
return
toInterop
(
interopPointers
.
toIntArray
())
}
}
actual
fun
toInterop
(
callback
:
(()
->
Boolean
)?):
InteropPointer
{
actual
fun
booleanCallback
(
callback
:
(()
->
Boolean
)?):
InteropPointer
{
if
(
callback
==
null
)
{
return
0
}
if
(
callback
==
null
)
{
return
0
}
initCallbacks
()
initCallbacks
()
val
data
=
CallbackData
<
Boolean
>(
null
)
val
data
=
CallbackData
<
Boolean
>(
null
)
return
_registerCallback
({
data
.
value
=
callback
()
},
data
)
return
_registerCallback
({
data
.
value
=
callback
()
},
data
,
global
=
false
)
}
actual
fun
callback
(
callback
:
(()
->
Unit
)?):
InteropPointer
{
if
(
callback
==
null
)
{
return
0
}
initCallbacks
()
return
_registerCallback
({
callback
()
},
null
,
global
=
false
)
}
actual
fun
virtual
(
method
:
()
->
Unit
):
InteropPointer
{
return
_registerCallback
({
method
()
},
null
,
global
=
true
)
}
actual
fun
virtualBoolean
(
method
:
()
->
Boolean
):
InteropPointer
{
val
data
=
CallbackData
<
Boolean
>(
null
)
return
_registerCallback
({
data
.
value
=
method
()
},
data
,
global
=
true
);
}
}
actual
fun
release
()
{
actual
fun
release
()
{
...
@@ -229,7 +245,7 @@ actual class InteropScope actual constructor() {
...
@@ -229,7 +245,7 @@ actual class InteropScope actual constructor() {
private
class
CallbackData
<
T
>(
@JsName
(
"value"
)
var
value
:
T
?)
private
class
CallbackData
<
T
>(
@JsName
(
"value"
)
var
value
:
T
?)
// See `setup.js`
// See `setup.js`
private
external
fun
_registerCallback
(
cb
:
()
->
Unit
,
data
:
Any
?):
Int
private
external
fun
_registerCallback
(
cb
:
()
->
Unit
,
data
:
Any
?
,
global
:
Boolean
):
Int
private
external
fun
_createLocalCallbackScope
()
private
external
fun
_createLocalCallbackScope
()
private
external
fun
_releaseLocalCallbackScope
()
private
external
fun
_releaseLocalCallbackScope
()
...
...
skiko/src/jsMain/resources/setup.js
View file @
54fb2034
...
@@ -11,20 +11,23 @@ var {_callCallback, _registerCallback, _releaseCallback, _createLocalCallbackSco
...
@@ -11,20 +11,23 @@ var {_callCallback, _registerCallback, _releaseCallback, _createLocalCallbackSco
class
Scope
{
class
Scope
{
constructor
()
{
constructor
()
{
this
.
callbackMap
=
[
CB_NULL
];
this
.
nextId
=
1
;
this
.
callbackMap
=
new
Map
();
this
.
callbackMap
.
set
(
0
,
CB_NULL
);
}
}
addCallback
(
callback
,
data
)
{
addCallback
(
callback
,
data
)
{
this
.
callbackMap
.
push
({
callback
,
data
});
let
id
=
this
.
nextId
++
;
return
this
.
callbackMap
.
length
-
1
;
this
.
callbackMap
.
set
(
id
,
{
callback
,
data
});
return
id
;
}
}
getCallback
(
id
)
{
getCallback
(
id
)
{
return
this
.
callbackMap
[
id
]
||
CB_UNDEFINED
return
this
.
callbackMap
.
get
(
id
)
||
CB_UNDEFINED
;
}
}
deleteCallback
(
id
)
{
deleteCallback
(
id
)
{
this
.
callbackMap
[
id
]
=
CB_UNDEFINED
this
.
callbackMap
.
delete
(
id
);
}
}
release
()
{
release
()
{
...
@@ -36,8 +39,8 @@ var {_callCallback, _registerCallback, _releaseCallback, _createLocalCallbackSco
...
@@ -36,8 +39,8 @@ var {_callCallback, _registerCallback, _releaseCallback, _createLocalCallbackSco
let
scope
=
GLOBAL_SCOPE
;
let
scope
=
GLOBAL_SCOPE
;
return
{
return
{
_callCallback
(
callbackId
)
{
_callCallback
(
callbackId
,
global
=
false
)
{
let
callback
=
scope
.
getCallback
(
callbackId
);
let
callback
=
(
global
?
GLOBAL_SCOPE
:
scope
)
.
getCallback
(
callbackId
);
try
{
try
{
callback
.
callback
();
callback
.
callback
();
return
callback
.
data
;
return
callback
.
data
;
...
@@ -45,11 +48,11 @@ var {_callCallback, _registerCallback, _releaseCallback, _createLocalCallbackSco
...
@@ -45,11 +48,11 @@ var {_callCallback, _registerCallback, _releaseCallback, _createLocalCallbackSco
console
.
error
(
e
)
console
.
error
(
e
)
}
}
},
},
_registerCallback
(
callback
,
data
=
null
)
{
_registerCallback
(
callback
,
data
=
null
,
global
=
false
)
{
return
scope
.
addCallback
(
callback
,
data
);
return
(
global
?
GLOBAL_SCOPE
:
scope
)
.
addCallback
(
callback
,
data
);
},
},
_releaseCallback
(
callbackId
)
{
_releaseCallback
(
callbackId
,
global
=
false
)
{
scope
.
deleteCallback
(
callbackId
);
(
global
?
GLOBAL_SCOPE
:
scope
)
.
deleteCallback
(
callbackId
);
},
},
_createLocalCallbackScope
()
{
_createLocalCallbackScope
()
{
if
(
scope
!==
GLOBAL_SCOPE
)
{
if
(
scope
!==
GLOBAL_SCOPE
)
{
...
...
skiko/src/jvmMain/cpp/common/Drawable.cc
View file @
54fb2034
...
@@ -10,14 +10,14 @@ public:
...
@@ -10,14 +10,14 @@ public:
~
SkijaDrawableImpl
()
{
~
SkijaDrawableImpl
()
{
JNIEnv
*
env
;
JNIEnv
*
env
;
if
(
fJavaVM
->
GetEnv
(
reinterpret_cast
<
void
**>
(
&
env
),
SKIKO_JNI_VERSION
)
==
JNI_OK
)
if
(
fJavaVM
->
GetEnv
(
AS_JNI_ENV_PTR
(
&
env
),
SKIKO_JNI_VERSION
)
==
JNI_OK
)
env
->
Delete
Weak
GlobalRef
(
fObject
);
env
->
DeleteGlobalRef
(
fObject
);
}
}
void
init
(
JNIEnv
*
e
,
jobject
o
)
{
void
init
(
JNIEnv
*
e
,
jobject
o
)
{
fEnv
=
e
;
fEnv
=
e
;
fEnv
->
GetJavaVM
(
&
fJavaVM
);
fEnv
->
GetJavaVM
(
&
fJavaVM
);
fObject
=
fEnv
->
New
Weak
GlobalRef
(
o
);
fObject
=
fEnv
->
NewGlobalRef
(
o
);
}
}
protected
:
protected
:
...
@@ -38,13 +38,21 @@ private:
...
@@ -38,13 +38,21 @@ private:
jobject
fObject
;
jobject
fObject
;
};
};
static
void
deleteDrawable
(
SkijaDrawableImpl
*
drawable
)
{
delete
drawable
;
}
extern
"C"
JNIEXPORT
jlong
JNICALL
Java_org_jetbrains_skia_DrawableKt_Drawable_1nGetFinalizer
()
{
return
reinterpret_cast
<
jlong
>
(
&
deleteDrawable
);
}
extern
"C"
JNIEXPORT
jlong
JNICALL
Java_org_jetbrains_skia_DrawableKt_Drawable_1nMake
extern
"C"
JNIEXPORT
jlong
JNICALL
Java_org_jetbrains_skia_DrawableKt_Drawable_1nMake
(
JNIEnv
*
env
,
jclass
jclass
)
{
(
JNIEnv
*
env
,
jclass
jclass
)
{
SkijaDrawableImpl
*
instance
=
new
SkijaDrawableImpl
();
SkijaDrawableImpl
*
instance
=
new
SkijaDrawableImpl
();
return
reinterpret_cast
<
jlong
>
(
instance
);
return
reinterpret_cast
<
jlong
>
(
instance
);
}
}
extern
"C"
JNIEXPORT
void
JNICALL
Java_org_jetbrains_skia_Drawable
Kt_Drawable_
_1nInit
extern
"C"
JNIEXPORT
void
JNICALL
Java_org_jetbrains_skia_Drawable
_1jvmKt_Drawable
_1nInit
(
JNIEnv
*
env
,
jclass
jclass
,
jobject
jthis
,
jlong
ptr
)
{
(
JNIEnv
*
env
,
jclass
jclass
,
jobject
jthis
,
jlong
ptr
)
{
SkijaDrawableImpl
*
instance
=
reinterpret_cast
<
SkijaDrawableImpl
*>
(
static_cast
<
uintptr_t
>
(
ptr
));
SkijaDrawableImpl
*
instance
=
reinterpret_cast
<
SkijaDrawableImpl
*>
(
static_cast
<
uintptr_t
>
(
ptr
));
instance
->
init
(
env
,
jthis
);
instance
->
init
(
env
,
jthis
);
...
@@ -75,3 +83,9 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_DrawableKt__1nNotifyDr
...
@@ -75,3 +83,9 @@ extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skia_DrawableKt__1nNotifyDr
SkijaDrawableImpl
*
instance
=
reinterpret_cast
<
SkijaDrawableImpl
*>
(
static_cast
<
uintptr_t
>
(
ptr
));
SkijaDrawableImpl
*
instance
=
reinterpret_cast
<
SkijaDrawableImpl
*>
(
static_cast
<
uintptr_t
>
(
ptr
));
return
instance
->
notifyDrawingChanged
();
return
instance
->
notifyDrawingChanged
();
}
}
extern
"C"
JNIEXPORT
void
JNICALL
Java_org_jetbrains_skia_DrawableKt_Drawable_1nGetBounds
(
JNIEnv
*
env
,
jclass
jclass
,
jlong
ptr
,
jfloatArray
result
)
{
SkijaDrawableImpl
*
instance
=
reinterpret_cast
<
SkijaDrawableImpl
*>
(
static_cast
<
uintptr_t
>
(
ptr
));
skija
::
Rect
::
copyToInterop
(
env
,
instance
->
getBounds
(),
result
);
}
skiko/src/jvmMain/cpp/common/interop.hh
View file @
54fb2034
...
@@ -446,8 +446,8 @@ public:
...
@@ -446,8 +446,8 @@ public:
}
}
T
operator
()()
{
T
operator
()()
{
jobject
res
=
env
->
CallObjectMethod
(
callback
,
kotlin
::
jvm
::
functions
::
Function0
::
invoke
);
skija
::
AutoLocal
<
jobject
>
res
(
env
,
env
->
CallObjectMethod
(
callback
,
kotlin
::
jvm
::
functions
::
Function0
::
invoke
)
);
return
jObjectConvert
<
T
>
(
env
,
res
);
return
jObjectConvert
<
T
>
(
env
,
res
.
get
()
);
}
}
bool
isExceptionThrown
()
{
bool
isExceptionThrown
()
{
...
...
skiko/src/jvmMain/kotlin/org/jetbrains/skia/Drawable.jvm.kt
0 → 100644
View file @
54fb2034
package
org.jetbrains.skia
import
org.jetbrains.skia.impl.NativePointer
import
org.jetbrains.skia.impl.Stats
internal
actual
fun
Drawable
.
doInit
(
ptr
:
NativePointer
)
{
Stats
.
onNativeCall
()
Drawable_nInit
(
this
,
ptr
)
}
private
external
fun
Drawable_nInit
(
thisPtr
:
Drawable
,
ptr
:
NativePointer
)
\ No newline at end of file
skiko/src/jvmMain/kotlin/org/jetbrains/skia/impl/Native.jvm.kt
View file @
54fb2034
...
@@ -78,7 +78,13 @@ actual open class InteropScope actual constructor() {
...
@@ -78,7 +78,13 @@ actual open class InteropScope actual constructor() {
actual
inline
fun
<
reified
T
>
InteropPointer
.
fromInterop
(
decoder
:
ArrayInteropDecoder
<
T
>):
Array
<
T
>
=
actual
inline
fun
<
reified
T
>
InteropPointer
.
fromInterop
(
decoder
:
ArrayInteropDecoder
<
T
>):
Array
<
T
>
=
this
@fromInterop
as
Array
<
T
>
this
@fromInterop
as
Array
<
T
>
actual
fun
toInteropForArraysOfPointers
(
interopPointers
:
Array
<
InteropPointer
>):
InteropPointer
=
interopPointers
actual
fun
toInteropForArraysOfPointers
(
interopPointers
:
Array
<
InteropPointer
>):
InteropPointer
=
interopPointers
actual
fun
toInterop
(
callback
:
(()
->
Boolean
)?)
=
callback
as
Any
?
actual
fun
callback
(
callback
:
(()
->
Unit
)?)
=
callback
as
Any
?
actual
fun
booleanCallback
(
callback
:
(()
->
Boolean
)?)
=
callback
as
Any
?
actual
fun
virtual
(
method
:
()
->
Unit
)
=
callback
(
method
)
actual
fun
virtualBoolean
(
method
:
()
->
Boolean
)
=
booleanCallback
(
method
)
actual
fun
release
()
{}
actual
fun
release
()
{}
}
}
...
...
skiko/src/nativeJsMain/cpp/Canvas.cc
View file @
54fb2034
...
@@ -188,23 +188,13 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawPatch
...
@@ -188,23 +188,13 @@ SKIKO_EXPORT void org_jetbrains_skia_Canvas__1nDrawPatch
);
);
}
}
SKIKO_EXPORT
void
org_jetbrains_skia_Canvas__1nDrawDrawable
(
KNativePointer
ptr
,
KNativePointer
drawablePtr
,
KFloat
*
matrixArr
)
{
TODO
(
"implement org_jetbrains_skia_Canvas__1nDrawDrawable"
);
}
#if 0
SKIKO_EXPORT
void
org_jetbrains_skia_Canvas__1nDrawDrawable
SKIKO_EXPORT
void
org_jetbrains_skia_Canvas__1nDrawDrawable
(
KNativePointer
ptr
,
KNativePointer
drawablePtr
,
KFloat
*
matrixArr
)
{
(
KNativePointer
ptr
,
KNativePointer
drawablePtr
,
KFloat
*
matrixArr
)
{
SkCanvas
*
canvas
=
reinterpret_cast
<
SkCanvas
*>
((
ptr
));
SkCanvas
*
canvas
=
reinterpret_cast
<
SkCanvas
*>
((
ptr
));
SkDrawable
*
drawable
=
reinterpret_cast
<
SkDrawable
*>
((
drawablePtr
));
SkDrawable
*
drawable
=
reinterpret_cast
<
SkDrawable
*>
((
drawablePtr
));
std::unique_ptr<SkMatrix> matrix = skMatrix(
env,
matrixArr);
std
::
unique_ptr
<
SkMatrix
>
matrix
=
skMatrix
(
matrixArr
);
canvas
->
drawDrawable
(
drawable
,
matrix
.
get
());
canvas
->
drawDrawable
(
drawable
,
matrix
.
get
());
}
}
#endif
SKIKO_EXPORT
void
org_jetbrains_skia_Canvas__1nClear
(
KNativePointer
ptr
,
KInt
color
)
{
SKIKO_EXPORT
void
org_jetbrains_skia_Canvas__1nClear
(
KNativePointer
ptr
,
KInt
color
)
{
SkCanvas
*
canvas
=
reinterpret_cast
<
SkCanvas
*>
((
ptr
));
SkCanvas
*
canvas
=
reinterpret_cast
<
SkCanvas
*>
((
ptr
));
...
...
skiko/src/nativeJsMain/cpp/Drawable.cc
View file @
54fb2034
...
@@ -5,94 +5,96 @@
...
@@ -5,94 +5,96 @@
#include "SkDrawable.h"
#include "SkDrawable.h"
#include "common.h"
#include "common.h"
class
SkikoDrawable
:
public
SkDrawable
{
SKIKO_EXPORT
KNativePointer
org_jetbrains_skia_Drawable__1nMake
public
:
(){
SkikoDrawable
(
KInteropPointer
onDraw
,
KInteropPointer
onGetBounds
)
:
_onDraw
(
onDraw
),
_onGetBounds
(
onGetBounds
)
{};
TODO
(
"implement org_jetbrains_skia_Drawable__1nMake"
);
void
init
(
KInteropPointer
onDraw
,
KInteropPointer
onGetBounds
)
{
_onDraw
=
KVoidCallback
(
onDraw
);
_onGetBounds
=
KVoidCallback
(
onGetBounds
);
}
SkRect
&
bounds
()
{
return
_bounds
;
}
SkCanvas
*
onDrawCanvas
()
{
return
_onDrawCanvas
;
}
protected
:
void
onDraw
(
SkCanvas
*
canvas
)
override
{
_onDrawCanvas
=
canvas
;
_onDraw
();
_onDrawCanvas
=
nullptr
;
};
SkRect
onGetBounds
()
override
{
_onGetBounds
();
return
_bounds
;
};
private
:
SkRect
_bounds
;
SkCanvas
*
_onDrawCanvas
;
KVoidCallback
_onDraw
;
KVoidCallback
_onGetBounds
;
};
static
void
deleteSkikoDrawable
(
SkikoDrawable
*
drawable
)
{
delete
drawable
;
}
}
#if 0
SKIKO_EXPORT
KNativePointer
org_jetbrains_skia_Drawable__1nGetFinalizer
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Drawable__1nMake
()
{
(){
return
reinterpret_cast
<
KNativePointer
>
(
&
deleteSkikoDrawable
);
SkijaDrawableImpl* instance = new SkijaDrawableImpl();
return reinterpret_cast<KNativePointer>(instance);
}
}
#endif
SKIKO_EXPORT
void
org_jetbrains_skia_Drawable__1nSetBounds
(
KNativePointer
ptr
,
KFloat
left
,
KFloat
top
,
KFloat
right
,
KFloat
bottom
)
{
SkikoDrawable
*
instance
=
reinterpret_cast
<
SkikoDrawable
*>
(
ptr
);
instance
->
bounds
().
setLTRB
(
left
,
top
,
right
,
bottom
);
}
SKIKO_EXPORT
void
org_jetbrains_skia_Drawable__1nInit
SKIKO_EXPORT
void
org_jetbrains_skia_Drawable__1nGetBounds
(
KInteropPointer
kthis
,
KNativePointer
ptr
)
{
(
KNativePointer
ptr
,
KInteropPointer
result
)
{
TODO
(
"implement org_jetbrains_skia_Drawable__1nInit"
);
SkikoDrawable
*
instance
=
reinterpret_cast
<
SkikoDrawable
*>
(
ptr
);
skija
::
Rect
::
copyToInterop
(
instance
->
getBounds
(),
result
);
}
}
#if 0
SKIKO_EXPORT
KInteropPointer
org_jetbrains_skia_Drawable__1nGetOnDrawCanvas
SKIKO_EXPORT void org_jetbrains_skia_Drawable__1nInit
(
KNativePointer
ptr
)
{
(
KNativePointer
ptr
)
{
Ski
jaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl*>((ptr)
);
Ski
koDrawable
*
instance
=
reinterpret_cast
<
SkikoDrawable
*>
(
ptr
);
instance->init(env, jthis
);
return
reinterpret_cast
<
KInteropPointer
>
(
instance
->
onDrawCanvas
()
);
}
}
#endif
SKIKO_EXPORT
KNativePointer
org_jetbrains_skia_Drawable__1nMake
(){
SkikoDrawable
*
instance
=
new
SkikoDrawable
(
nullptr
,
nullptr
);
return
reinterpret_cast
<
KNativePointer
>
(
instance
);
}
SKIKO_EXPORT
void
org_jetbrains_skia_Drawable__1nDraw
SKIKO_EXPORT
void
org_jetbrains_skia_Drawable__1nInit
(
KNativePointer
ptr
,
KNativePointer
canvasPtr
,
KFloat
*
matrixArr
)
{
(
KNativePointer
ptr
,
KInteropPointer
onGetBounds
,
KInteropPointer
onDraw
)
{
TODO
(
"implement org_jetbrains_skia_Drawable__1nDraw"
);
SkikoDrawable
*
instance
=
reinterpret_cast
<
SkikoDrawable
*>
((
ptr
));
instance
->
init
(
onDraw
,
onGetBounds
);
}
}
#if 0
SKIKO_EXPORT
void
org_jetbrains_skia_Drawable__1nDraw
SKIKO_EXPORT
void
org_jetbrains_skia_Drawable__1nDraw
(
KNativePointer
ptr
,
KNativePointer
canvasPtr
,
KFloat
*
matrixArr
)
{
(
KNativePointer
ptr
,
KNativePointer
canvasPtr
,
KFloat
*
matrixArr
)
{
Ski
jaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl
*>((ptr));
Ski
koDrawable
*
instance
=
reinterpret_cast
<
SkikoDrawable
*>
((
ptr
));
SkCanvas
*
canvas
=
reinterpret_cast
<
SkCanvas
*>
((
canvasPtr
));
SkCanvas
*
canvas
=
reinterpret_cast
<
SkCanvas
*>
((
canvasPtr
));
std::unique_ptr<SkMatrix> matrix = skMatrix(
env,
matrixArr);
std
::
unique_ptr
<
SkMatrix
>
matrix
=
skMatrix
(
matrixArr
);
instance
->
draw
(
canvas
,
matrix
.
get
());
instance
->
draw
(
canvas
,
matrix
.
get
());
}
}
#endif
SKIKO_EXPORT
KNativePointer
org_jetbrains_skia_Drawable__1nMakePictureSnapshot
SKIKO_EXPORT
KNativePointer
org_jetbrains_skia_Drawable__1nMakePictureSnapshot
(
KNativePointer
ptr
)
{
(
KNativePointer
ptr
)
{
TODO
(
"implement org_jetbrains_skia_Drawable__1nMakePictureSnapshot"
);
SkikoDrawable
*
instance
=
reinterpret_cast
<
SkikoDrawable
*>
((
ptr
));
}
#if 0
SKIKO_EXPORT KNativePointer org_jetbrains_skia_Drawable__1nMakePictureSnapshot
(KNativePointer ptr) {
SkijaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl*>((ptr));
return
reinterpret_cast
<
KNativePointer
>
(
instance
->
newPictureSnapshot
());
return
reinterpret_cast
<
KNativePointer
>
(
instance
->
newPictureSnapshot
());
}
}
#endif
SKIKO_EXPORT
KInt
org_jetbrains_skia_Drawable__1nGetGenerationId
(
KNativePointer
ptr
)
{
TODO
(
"implement org_jetbrains_skia_Drawable__1nGetGenerationId"
);
}
#if 0
SKIKO_EXPORT
KInt
org_jetbrains_skia_Drawable__1nGetGenerationId
SKIKO_EXPORT
KInt
org_jetbrains_skia_Drawable__1nGetGenerationId
(
KNativePointer
ptr
)
{
(
KNativePointer
ptr
)
{
Ski
jaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl
*>((ptr));
Ski
koDrawable
*
instance
=
reinterpret_cast
<
SkikoDrawable
*>
((
ptr
));
return
instance
->
getGenerationID
();
return
instance
->
getGenerationID
();
}
}
#endif
SKIKO_EXPORT
void
org_jetbrains_skia_Drawable__1nNotifyDrawingChanged
(
KNativePointer
ptr
)
{
TODO
(
"implement org_jetbrains_skia_Drawable__1nNotifyDrawingChanged"
);
}
#if 0
SKIKO_EXPORT
void
org_jetbrains_skia_Drawable__1nNotifyDrawingChanged
SKIKO_EXPORT
void
org_jetbrains_skia_Drawable__1nNotifyDrawingChanged
(
KNativePointer
ptr
)
{
(
KNativePointer
ptr
)
{
Ski
jaDrawableImpl* instance = reinterpret_cast<SkijaDrawableImpl
*>((ptr));
Ski
koDrawable
*
instance
=
reinterpret_cast
<
SkikoDrawable
*>
((
ptr
));
return
instance
->
notifyDrawingChanged
();
return
instance
->
notifyDrawingChanged
();
}
}
#endif
skiko/src/nativeJsMain/cpp/common.h
View file @
54fb2034
...
@@ -160,10 +160,12 @@ static inline KFloat fromBits(KInt i) {
...
@@ -160,10 +160,12 @@ static inline KFloat fromBits(KInt i) {
// Callback support
// Callback support
typedef
void
(
*
SkikoDisposeCallback
)(
KInteropPointer
);
typedef
void
(
*
SkikoDisposeCallback
)(
KInteropPointer
);
typedef
void
(
*
SkikoCallVoidCallback
)(
KInteropPointer
);
typedef
KBoolean
(
*
SkikoCallBooleanCallback
)(
KInteropPointer
);
typedef
KBoolean
(
*
SkikoCallBooleanCallback
)(
KInteropPointer
);
typedef
void
*
KOpaquePointer
;
typedef
void
*
KOpaquePointer
;
void
disposeCallback
(
KInteropPointer
cb
);
void
disposeCallback
(
KInteropPointer
cb
);
void
callVoidCallback
(
KInteropPointer
cb
);
KBoolean
callBooleanCallback
(
KInteropPointer
cb
);
KBoolean
callBooleanCallback
(
KInteropPointer
cb
);
template
<
typename
T
,
T
(
*
Apply
)(
KInteropPointer
)
>
template
<
typename
T
,
T
(
*
Apply
)(
KInteropPointer
)
>
...
@@ -171,19 +173,35 @@ class KCallback {
...
@@ -171,19 +173,35 @@ class KCallback {
public
:
public
:
explicit
KCallback
(
KInteropPointer
data
)
:
data
(
data
)
{}
explicit
KCallback
(
KInteropPointer
data
)
:
data
(
data
)
{}
virtual
~
KCallback
()
{
disposeCallback
(
data
);
}
virtual
~
KCallback
()
{
if
(
data
!=
nullptr
)
{
disposeCallback
(
data
);
}
}
KCallback
(
const
KCallback
&
)
=
delete
;
KCallback
(
const
KCallback
&
)
=
delete
;
KCallback
(
KCallback
&&
)
=
delete
;
KCallback
&
operator
=
(
const
KCallback
&
)
=
delete
;
KCallback
&
operator
=
(
const
KCallback
&
)
=
delete
;
KCallback
&
operator
=
(
KCallback
&&
)
=
delete
;
T
operator
()()
const
{
return
Apply
(
data
);
}
KCallback
(
KCallback
&&
other
)
noexcept
{
KInteropPointer
t
=
data
;
data
=
other
.
data
;
other
.
data
=
t
;
}
KCallback
&
operator
=
(
KCallback
&&
other
)
{
std
::
swap
(
data
,
other
.
data
);
return
*
this
;
}
T
operator
()()
const
{
return
Apply
(
data
);
}
private
:
private
:
KInteropPointer
data
;
KInteropPointer
data
;
};
};
typedef
KCallback
<
KBoolean
,
callBooleanCallback
>
KBooleanCallback
;
typedef
KCallback
<
KBoolean
,
callBooleanCallback
>
KBooleanCallback
;
typedef
KCallback
<
void
,
callVoidCallback
>
KVoidCallback
;
#endif
/* SKIKO_COMMON_H */
#endif
/* SKIKO_COMMON_H */
skiko/src/nativeJsMain/cpp/common_interop.cc
View file @
54fb2034
...
@@ -342,13 +342,21 @@ KBoolean callBooleanCallback(KInteropPointer cb) {
...
@@ -342,13 +342,21 @@ KBoolean callBooleanCallback(KInteropPointer cb) {
return
static_cast
<
KBoolean
>
(
value
);
return
static_cast
<
KBoolean
>
(
value
);
}
}
void
callVoidCallback
(
KInteropPointer
cb
)
{
EM_ASM
({
_callCallback
(
$
0
);
},
cb
);
}
#else // __EMSCRIPTEN__
#else // __EMSCRIPTEN__
static
SkikoDisposeCallback
disposeCallbackImpl
=
nullptr
;
static
SkikoDisposeCallback
disposeCallbackImpl
=
nullptr
;
static
SkikoCallBooleanCallback
callBooleanCallbackImpl
=
nullptr
;
static
SkikoCallBooleanCallback
callBooleanCallbackImpl
=
nullptr
;
static
SkikoCallVoidCallback
callVoidCallbackImpl
=
nullptr
;
SKIKO_EXPORT
void
skiko_initCallbacks
(
KOpaquePointer
callBoolean
,
KOpaquePointer
dispose
)
{
SKIKO_EXPORT
void
skiko_initCallbacks
(
KOpaquePointer
callBoolean
,
KOpaquePointer
callVoid
,
KOpaquePointer
dispose
)
{
callBooleanCallbackImpl
=
reinterpret_cast
<
SkikoCallBooleanCallback
>
(
callBoolean
);
callBooleanCallbackImpl
=
reinterpret_cast
<
SkikoCallBooleanCallback
>
(
callBoolean
);
callVoidCallbackImpl
=
reinterpret_cast
<
SkikoCallVoidCallback
>
(
callVoid
);
disposeCallbackImpl
=
reinterpret_cast
<
SkikoDisposeCallback
>
(
dispose
);
disposeCallbackImpl
=
reinterpret_cast
<
SkikoDisposeCallback
>
(
dispose
);
}
}
...
@@ -360,5 +368,9 @@ KBoolean callBooleanCallback(KInteropPointer cb) {
...
@@ -360,5 +368,9 @@ KBoolean callBooleanCallback(KInteropPointer cb) {
return
callBooleanCallbackImpl
(
cb
);
return
callBooleanCallbackImpl
(
cb
);
}
}
void
callVoidCallback
(
KInteropPointer
cb
)
{
return
callVoidCallbackImpl
(
cb
);
}
#endif // __EMSCRIPTEN__
#endif // __EMSCRIPTEN__
skiko/src/nativeJsMain/kotlin/org/jetbrains/skia/Drawable.nativejs.kt
0 → 100644
View file @
54fb2034
package
org.jetbrains.skia
import
org.jetbrains.skia.impl.NativePointer
import
org.jetbrains.skia.impl.Stats
import
org.jetbrains.skia.impl.interopScope
internal
actual
fun
Drawable
.
doInit
(
ptr
:
NativePointer
)
{
Stats
.
onNativeCall
()
interopScope
{
val
onDrawCallback
=
virtual
{
onDraw
(
Canvas
(
_nGetOnDrawCanvas
(
_ptr
),
false
,
this
))
}
val
onGetBoundsCallback
=
virtual
{
val
bounds
=
onGetBounds
()
_nSetBounds
(
_ptr
,
bounds
.
left
,
bounds
.
top
,
bounds
.
right
,
bounds
.
bottom
)
}
Drawable_nInit
(
_ptr
,
onGetBoundsCallback
,
onDrawCallback
)
}
}
skiko/src/nativeMain/kotlin/org/jetbrains/skia/impl/Native.native.kt
View file @
54fb2034
...
@@ -26,6 +26,7 @@ actual abstract class Native actual constructor(ptr: NativePointer) {
...
@@ -26,6 +26,7 @@ actual abstract class Native actual constructor(ptr: NativePointer) {
init
{
init
{
initCallbacks
(
initCallbacks
(
staticCFunction
(
::
callBooleanCallback
),
staticCFunction
(
::
callBooleanCallback
),
staticCFunction
(
::
callVoidCallback
),
staticCFunction
(
::
disposeCallback
),
staticCFunction
(
::
disposeCallback
),
)
)
}
}
...
@@ -200,12 +201,21 @@ actual class InteropScope actual constructor() {
...
@@ -200,12 +201,21 @@ actual class InteropScope actual constructor() {
return
toInterop
(
interopPointers
.
map
{
it
.
toLong
()
}.
toLongArray
())
return
toInterop
(
interopPointers
.
map
{
it
.
toLong
()
}.
toLongArray
())
}
}
actual
fun
toInterop
(
callback
:
(()
->
Boolean
)?):
InteropPointer
actual
fun
booleanCallback
(
callback
:
(()
->
Boolean
)?):
InteropPointer
=
callback
?.
let
{
=
callback
?.
let
{
val
ptr
=
StableRef
.
create
(
it
).
asCPointer
()
val
ptr
=
StableRef
.
create
(
it
).
asCPointer
()
NativePtr
.
NULL
.
plus
(
ptr
.
toLong
())
NativePtr
.
NULL
.
plus
(
ptr
.
toLong
())
}
?:
NativePtr
.
NULL
}
?:
NativePtr
.
NULL
actual
fun
callback
(
callback
:
(()
->
Unit
)?):
InteropPointer
=
callback
?.
let
{
val
ptr
=
StableRef
.
create
(
it
).
asCPointer
()
NativePtr
.
NULL
.
plus
(
ptr
.
toLong
())
}
?:
NativePtr
.
NULL
actual
fun
virtual
(
method
:
()
->
Unit
)
=
callback
(
method
)
actual
fun
virtualBoolean
(
method
:
()
->
Boolean
)
=
booleanCallback
(
method
)
actual
fun
release
()
{
actual
fun
release
()
{
elements
.
forEach
{
elements
.
forEach
{
it
.
unpin
()
it
.
unpin
()
...
@@ -232,6 +242,10 @@ actual class NativePointerArray actual constructor(size: Int) {
...
@@ -232,6 +242,10 @@ actual class NativePointerArray actual constructor(size: Int) {
// Callbacks support
// Callbacks support
private
fun
callVoidCallback
(
ptr
:
COpaquePointer
)
{
ptr
.
asStableRef
<()
->
Unit
>().
get
().
invoke
()
}
private
fun
callBooleanCallback
(
ptr
:
COpaquePointer
):
Boolean
{
private
fun
callBooleanCallback
(
ptr
:
COpaquePointer
):
Boolean
{
return
ptr
.
asStableRef
<()
->
Boolean
>().
get
().
invoke
()
return
ptr
.
asStableRef
<()
->
Boolean
>().
get
().
invoke
()
}
}
...
@@ -241,4 +255,4 @@ private fun disposeCallback(ptr: COpaquePointer) {
...
@@ -241,4 +255,4 @@ private fun disposeCallback(ptr: COpaquePointer) {
}
}
@ExternalSymbolName
(
"skiko_initCallbacks"
)
@ExternalSymbolName
(
"skiko_initCallbacks"
)
private
external
fun
initCallbacks
(
callBoolean
:
COpaquePointer
,
dispose
:
COpaquePointer
)
private
external
fun
initCallbacks
(
callBoolean
:
COpaquePointer
,
callVoid
:
COpaquePointer
,
dispose
:
COpaquePointer
)
\ No newline at end of file
\ 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