Unverified Commit 3af0752f authored by ApoloApps's avatar ApoloApps Committed by GitHub

Part 2 Extension functions non-allocate intermediate objects (#1140)

This is part 2 of [this
pr](https://github.com/JetBrains/skiko/pull/1137)

**What has changed?**
1. Added more extension functions that prevent intermediate object
allocations from a lot of the Skiko api surface
2. Migrated EnumClass.values() to entries in a lot of classes (maybe
some have been missed)

**Next**
Try (important keyword here :), cause if not wrong there are Skia and
Compose diffs on how they're treated) doing less copies of Matrix

## Release Notes
Added API that can accept primitive values instead of `Rect`, `RRect`, `Offset` to avoid additional object allocation
parent 548fed39
...@@ -33,8 +33,9 @@ internal fun autoCloseScope(body: CloseScope.() -> Unit) { ...@@ -33,8 +33,9 @@ internal fun autoCloseScope(body: CloseScope.() -> Unit) {
try { try {
scope.body() scope.body()
} finally { } finally {
resources.asReversed().forEach { for (index in resources.indices.reversed()) {
it.close() val item = resources[index]
item.close()
} }
} }
} }
\ No newline at end of file
...@@ -383,7 +383,9 @@ actual open class SkiaLayer internal constructor( ...@@ -383,7 +383,9 @@ actual open class SkiaLayer internal constructor(
private fun notifyChange(kind: PropertyKind) { private fun notifyChange(kind: PropertyKind) {
stateChangeListeners[kind]?.let { handlers -> stateChangeListeners[kind]?.let { handlers ->
handlers.forEach { it(this) } for (index in handlers.indices) {
handlers[index].invoke(this)
}
} }
} }
...@@ -598,21 +600,23 @@ actual open class SkiaLayer internal constructor( ...@@ -598,21 +600,23 @@ actual open class SkiaLayer internal constructor(
// If this approach will be changed, create an issue in https://youtrack.jetbrains.com/issues/CMP for changing it in // If this approach will be changed, create an issue in https://youtrack.jetbrains.com/issues/CMP for changing it in
// https://github.com/JetBrains/compose-multiplatform/blob/e4e2d329709cded91a09cc612d4defbce37aad96/benchmarks/multiplatform/benchmarks/src/commonMain/kotlin/MeasureComposable.kt#L151 as well // https://github.com/JetBrains/compose-multiplatform/blob/e4e2d329709cded91a09cc612d4defbce37aad96/benchmarks/multiplatform/benchmarks/src/commonMain/kotlin/MeasureComposable.kt#L151 as well
val pictureWidth = (backedLayer.width * contentScale).toInt().coerceAtLeast(0) val pictureWidth = (backedLayer.width * contentScale).coerceAtLeast(0f)
val pictureHeight = (backedLayer.height * contentScale).toInt().coerceAtLeast(0) val pictureHeight = (backedLayer.height * contentScale).coerceAtLeast(0f)
val intWidth = pictureWidth.toInt()
val intHeight = pictureHeight.toInt()
val bounds = Rect.makeWH(pictureWidth.toFloat(), pictureHeight.toFloat())
val pictureRecorder = pictureRecorder!! val pictureRecorder = pictureRecorder!!
val canvas = pictureRecorder.beginRecording(bounds) val canvas = pictureRecorder.beginRecording(0f, 0f, pictureWidth, pictureHeight)
// clipping // clipping
for (component in clipComponents) { for (index in clipComponents.indices) {
canvas.clipRectBy(component, contentScale) val item = clipComponents[index]
canvas.clipRectBy(item, contentScale)
} }
try { try {
isRendering = true isRendering = true
renderDelegate?.onRender(canvas, pictureWidth, pictureHeight, nanoTime) renderDelegate?.onRender(canvas, intWidth, intHeight, nanoTime)
} finally { } finally {
isRendering = false isRendering = false
} }
...@@ -623,7 +627,7 @@ actual open class SkiaLayer internal constructor( ...@@ -623,7 +627,7 @@ actual open class SkiaLayer internal constructor(
synchronized(pictureLock) { synchronized(pictureLock) {
picture?.instance?.close() picture?.instance?.close()
val picture = pictureRecorder.finishRecordingAsPicture() val picture = pictureRecorder.finishRecordingAsPicture()
this.picture = PictureHolder(picture, pictureWidth, pictureHeight) this.picture = PictureHolder(picture, intWidth, intHeight)
} }
} }
} }
...@@ -726,17 +730,15 @@ internal fun defaultFPSCounter( ...@@ -726,17 +730,15 @@ internal fun defaultFPSCounter(
logOnTick = true logOnTick = true
) )
} }
@Suppress("NOTHING_TO_INLINE")
internal fun Canvas.clipRectBy(rectangle: ClipRectangle, scale: Float) { internal inline fun Canvas.clipRectBy(rectangle: ClipRectangle, scale: Float) {
clipRect( clipRect(
Rect.makeLTRB( left = rectangle.x * scale,
rectangle.x * scale, top = rectangle.y * scale,
rectangle.y * scale, right = (rectangle.x + rectangle.width) * scale,
(rectangle.x + rectangle.width) * scale, bottom = (rectangle.y + rectangle.height) * scale,
(rectangle.y + rectangle.height) * scale mode = ClipMode.DIFFERENCE,
), antiAlias = true
ClipMode.DIFFERENCE,
true
) )
} }
......
...@@ -46,8 +46,9 @@ open class SkiaSwingLayer( ...@@ -46,8 +46,9 @@ open class SkiaSwingLayer(
override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) { override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
val scale = graphicsConfiguration.defaultTransform.scaleX.toFloat() val scale = graphicsConfiguration.defaultTransform.scaleX.toFloat()
// clipping // clipping
for (component in clipComponents) { for (index in clipComponents.indices) {
canvas.clipRectBy(component, scale) val item = clipComponents[index]
canvas.clipRectBy(item, scale)
} }
renderDelegate.onRender(canvas, width, height, nanoTime) renderDelegate.onRender(canvas, width, height, nanoTime)
} }
......
...@@ -110,10 +110,10 @@ class AnimationFrameInfo( ...@@ -110,10 +110,10 @@ class AnimationFrameInfo(
requiredFrame, requiredFrame,
duration, duration,
fullyReceived, fullyReceived,
ColorAlphaType.values()[alphaTypeOrdinal], ColorAlphaType.entries[alphaTypeOrdinal],
hasAlphaWithinBounds, hasAlphaWithinBounds,
AnimationDisposalMode.values()[disposalMethodOrdinal], AnimationDisposalMode.entries[disposalMethodOrdinal],
BlendMode.values()[blendModeOrdinal], BlendMode.entries[blendModeOrdinal],
frameRect frameRect
) )
......
...@@ -124,7 +124,13 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -124,7 +124,13 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
Stats.onNativeCall() Stats.onNativeCall()
try { try {
interopScope { interopScope {
_nDrawPoints(_ptr, 0 /* SkCanvas::PointMode::kPoints_PointMode */, coords.size, toInterop(coords), getPtr(paint)) _nDrawPoints(
_ptr,
0 /* SkCanvas::PointMode::kPoints_PointMode */,
coords.size,
toInterop(coords),
getPtr(paint)
)
} }
} finally { } finally {
reachabilityBarrier(paint) reachabilityBarrier(paint)
...@@ -187,7 +193,13 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -187,7 +193,13 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
Stats.onNativeCall() Stats.onNativeCall()
try { try {
interopScope { interopScope {
_nDrawPoints(_ptr, 1 /* SkCanvas::PointMode::kLines_PointMode */, coords.size, toInterop(coords),getPtr(paint)) _nDrawPoints(
_ptr,
1 /* SkCanvas::PointMode::kLines_PointMode */,
coords.size,
toInterop(coords),
getPtr(paint)
)
} }
} finally { } finally {
reachabilityBarrier(paint) reachabilityBarrier(paint)
...@@ -248,7 +260,13 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -248,7 +260,13 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
Stats.onNativeCall() Stats.onNativeCall()
try { try {
interopScope { interopScope {
_nDrawPoints(_ptr, 2 /* SkCanvas::PointMode::kPolygon_PointMode */, coords.size, toInterop(coords), getPtr(paint)) _nDrawPoints(
_ptr,
2 /* SkCanvas::PointMode::kPolygon_PointMode */,
coords.size,
toInterop(coords),
getPtr(paint)
)
} }
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
...@@ -300,14 +318,7 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -300,14 +318,7 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
} }
fun drawRect(r: Rect, paint: Paint): Canvas { fun drawRect(r: Rect, paint: Paint): Canvas {
Stats.onNativeCall() return drawRect(r.left, r.top, r.right, r.bottom, paint)
try {
_nDrawRect(_ptr, r.left, r.top, r.right, r.bottom, getPtr(paint))
} finally {
reachabilityBarrier(this)
reachabilityBarrier(paint)
}
return this
} }
fun drawOval(left: Float, top: Float, right: Float, bottom: Float, paint: Paint): Canvas { fun drawOval(left: Float, top: Float, right: Float, bottom: Float, paint: Paint): Canvas {
...@@ -322,14 +333,7 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -322,14 +333,7 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
} }
fun drawOval(r: Rect, paint: Paint): Canvas { fun drawOval(r: Rect, paint: Paint): Canvas {
Stats.onNativeCall() return drawOval(r.left, r.top, r.right, r.bottom, paint)
try {
_nDrawOval(_ptr, r.left, r.top, r.right, r.bottom, getPtr(paint))
} finally {
reachabilityBarrier(paint)
reachabilityBarrier(this)
}
return this
} }
fun drawCircle(x: Float, y: Float, radius: Float, paint: Paint): Canvas { fun drawCircle(x: Float, y: Float, radius: Float, paint: Paint): Canvas {
...@@ -357,16 +361,7 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -357,16 +361,7 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
} }
fun drawRRect(r: RRect, paint: Paint): Canvas { fun drawRRect(r: RRect, paint: Paint): Canvas {
Stats.onNativeCall() return drawRRect(r.left, r.top, r.right, r.bottom, r.radii, paint)
try {
interopScope {
_nDrawRRect(_ptr, r.left, r.top, r.right, r.bottom, toInterop(r.radii), r.radii.size, getPtr(paint))
}
} finally {
reachabilityBarrier(paint)
reachabilityBarrier(this)
}
return this
} }
fun drawDRRect(outer: RRect, inner: RRect, paint: Paint): Canvas { fun drawDRRect(outer: RRect, inner: RRect, paint: Paint): Canvas {
...@@ -437,58 +432,121 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -437,58 +432,121 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
fun drawImage(image: Image, left: Float, top: Float): Canvas { fun drawImage(image: Image, left: Float, top: Float): Canvas {
return drawImageRect( return drawImageRect(
image, image = image,
Rect.makeWH(image.width.toFloat(), image.height.toFloat()), srcLeft = 0f,
Rect.makeXYWH(left, top, image.width.toFloat(), image.height.toFloat()), srcTop = 0f,
SamplingMode.DEFAULT, srcRight = image.width.toFloat(),
null, srcBottom = image.height.toFloat(),
true dstLeft = left,
dstTop = top,
dstRight = left + image.width.toFloat(),
dstBottom = top + image.height.toFloat(),
samplingMode = SamplingMode.DEFAULT,
paint = null,
strict = true
) )
} }
fun drawImage(image: Image, left: Float, top: Float, paint: Paint?): Canvas { fun drawImage(image: Image, left: Float, top: Float, paint: Paint?): Canvas {
return drawImageRect( return drawImageRect(
image, image = image,
Rect.makeWH(image.width.toFloat(), image.height.toFloat()), srcLeft = 0f,
Rect.makeXYWH(left, top, image.width.toFloat(), image.height.toFloat()), srcTop = 0f,
SamplingMode.DEFAULT, srcRight = image.width.toFloat(),
paint, srcBottom = image.height.toFloat(),
true dstLeft = left,
dstTop = top,
dstRight = left + image.width.toFloat(),
dstBottom = top + image.height.toFloat(),
samplingMode = SamplingMode.DEFAULT,
paint = paint,
strict = true
) )
} }
fun drawImageRect(image: Image, dst: Rect): Canvas { fun drawImageRect(image: Image, dst: Rect): Canvas {
return drawImageRect( return drawImageRect(
image, image = image,
Rect.makeWH(image.width.toFloat(), image.height.toFloat()), srcLeft = 0f,
dst, srcTop = 0f,
SamplingMode.DEFAULT, srcRight = image.width.toFloat(),
null, srcBottom = image.height.toFloat(),
true dstLeft = dst.left,
dstTop = dst.top,
dstRight = dst.right,
dstBottom = dst.bottom,
samplingMode = SamplingMode.DEFAULT,
paint = null,
strict = true
) )
} }
fun drawImageRect(image: Image, dst: Rect, paint: Paint?): Canvas { fun drawImageRect(image: Image, dst: Rect, paint: Paint?): Canvas {
return drawImageRect( return drawImageRect(
image, image = image,
Rect.makeWH(image.width.toFloat(), image.height.toFloat()), srcLeft = 0f,
dst, srcTop = 0f,
SamplingMode.DEFAULT, srcRight = image.width.toFloat(),
paint, srcBottom = image.height.toFloat(),
true dstLeft = dst.left,
dstTop = dst.top,
dstRight = dst.right,
dstBottom = dst.bottom,
samplingMode = SamplingMode.DEFAULT,
paint = paint,
strict = true
) )
} }
fun drawImageRect(image: Image, src: Rect, dst: Rect): Canvas { fun drawImageRect(image: Image, src: Rect, dst: Rect): Canvas {
return drawImageRect(image, src, dst, SamplingMode.DEFAULT, null, true) return drawImageRect(
image = image,
srcLeft = src.left,
srcTop = src.top,
srcRight = src.right,
srcBottom = src.bottom,
dstLeft = dst.left,
dstTop = dst.top,
dstRight = dst.right,
dstBottom = dst.bottom,
samplingMode = SamplingMode.DEFAULT,
paint = null,
strict = true
)
} }
fun drawImageRect(image: Image, src: Rect, dst: Rect, paint: Paint?): Canvas { fun drawImageRect(image: Image, src: Rect, dst: Rect, paint: Paint?): Canvas {
return drawImageRect(image, src, dst, SamplingMode.DEFAULT, paint, true) return drawImageRect(
image = image,
srcLeft = src.left,
srcTop = src.top,
srcRight = src.right,
srcBottom = src.bottom,
dstLeft = dst.left,
dstTop = dst.top,
dstRight = dst.right,
dstBottom = dst.bottom,
samplingMode = SamplingMode.DEFAULT,
paint = paint,
strict = true
)
} }
fun drawImageRect(image: Image, src: Rect, dst: Rect, paint: Paint?, strict: Boolean): Canvas { fun drawImageRect(image: Image, src: Rect, dst: Rect, paint: Paint?, strict: Boolean): Canvas {
return drawImageRect(image, src, dst, SamplingMode.DEFAULT, paint, strict) return drawImageRect(
image = image,
srcLeft = src.left,
srcTop = src.top,
srcRight = src.right,
srcBottom = src.bottom,
dstLeft = dst.left,
dstTop = dst.top,
dstRight = dst.right,
dstBottom = dst.bottom,
samplingMode = SamplingMode.DEFAULT,
paint = paint,
strict = strict
)
} }
fun drawImageRect( fun drawImageRect(
...@@ -539,30 +597,20 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -539,30 +597,20 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
paint: Paint?, paint: Paint?,
strict: Boolean strict: Boolean
): Canvas { ): Canvas {
Stats.onNativeCall() return drawImageRect(
try { image = image,
_nDrawImageRect( srcLeft = src.left,
_ptr, srcTop = src.top,
getPtr(image), srcRight = src.right,
src.left, srcBottom = src.bottom,
src.top, dstLeft = dst.left,
src.right, dstTop = dst.top,
src.bottom, dstRight = dst.right,
dst.left, dstBottom = dst.bottom,
dst.top, samplingMode = samplingMode,
dst.right, paint = paint,
dst.bottom, strict = strict
samplingMode._packedInt1(),
samplingMode._packedInt2(),
getPtr(paint),
strict
) )
} finally {
reachabilityBarrier(image)
reachabilityBarrier(paint)
reachabilityBarrier(this)
}
return this
} }
fun drawImageNine(image: Image, center: IRect, dst: Rect, filterMode: FilterMode, paint: Paint?): Canvas { fun drawImageNine(image: Image, center: IRect, dst: Rect, filterMode: FilterMode, paint: Paint?): Canvas {
...@@ -1085,47 +1133,69 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int ...@@ -1085,47 +1133,69 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
get() = localToDevice.asMatrix33() get() = localToDevice.asMatrix33()
fun clipRect(r: Rect, mode: ClipMode, antiAlias: Boolean): Canvas { fun clipRect(r: Rect, mode: ClipMode, antiAlias: Boolean): Canvas {
Stats.onNativeCall() return clipRect(r.left, r.top, r.right, r.bottom, mode, antiAlias)
_nClipRect(_ptr, r.left, r.top, r.right, r.bottom, mode.ordinal, antiAlias)
return this
} }
fun clipRect(left : Float, top : Float, right: Float, bottom : Float, mode: ClipMode, antiAlias: Boolean): Canvas { fun clipRect(left: Float, top: Float, right: Float, bottom: Float, mode: ClipMode, antiAlias: Boolean): Canvas {
Stats.onNativeCall() Stats.onNativeCall()
_nClipRect(_ptr, left, top, right, bottom, mode.ordinal, antiAlias) _nClipRect(_ptr, left, top, right, bottom, mode.ordinal, antiAlias)
return this return this
} }
fun clipRect(r: Rect, mode: ClipMode): Canvas { fun clipRect(r: Rect, mode: ClipMode): Canvas {
return clipRect(r, mode, false) return clipRect(r.left, r.top, r.right, r.bottom, mode, false)
} }
fun clipRect(r: Rect, antiAlias: Boolean): Canvas { fun clipRect(r: Rect, antiAlias: Boolean): Canvas {
return clipRect(r, ClipMode.INTERSECT, antiAlias) return clipRect(r.left, r.top, r.right, r.bottom, ClipMode.INTERSECT, antiAlias)
}
fun clipRect(left: Float, top: Float, right: Float, bottom: Float, antiAlias: Boolean): Canvas {
return clipRect(left, top, right, bottom, ClipMode.INTERSECT, antiAlias)
} }
fun clipRect(r: Rect): Canvas { fun clipRect(r: Rect): Canvas {
return clipRect(r, ClipMode.INTERSECT, false) return clipRect(r.left, r.top, r.right, r.bottom, ClipMode.INTERSECT, false)
} }
fun clipRRect(r: RRect, mode: ClipMode, antiAlias: Boolean): Canvas { fun clipRRect(r: RRect, mode: ClipMode, antiAlias: Boolean): Canvas {
return clipRRect(r.left, r.top, r.right, r.bottom, r.radii, mode, antiAlias)
}
fun clipRRect(
left: Float,
top: Float,
right: Float,
bottom: Float,
radii: FloatArray,
mode: ClipMode,
antiAlias: Boolean
): Canvas {
Stats.onNativeCall() Stats.onNativeCall()
interopScope { interopScope {
_nClipRRect(_ptr, r.left, r.top, r.right, r.bottom, toInterop(r.radii), r.radii.size, mode.ordinal, antiAlias) _nClipRRect(_ptr, left, top, right, bottom, toInterop(radii), radii.size, mode.ordinal, antiAlias)
} }
return this return this
} }
fun clipRRect(r: RRect, mode: ClipMode): Canvas { fun clipRRect(r: RRect, mode: ClipMode): Canvas {
return clipRRect(r, mode, false) return clipRRect(r.left, r.top, r.right, r.bottom, r.radii, mode, false)
}
fun clipRRect(left: Float, top: Float, right: Float, bottom: Float, radii: FloatArray, mode: ClipMode): Canvas {
return clipRRect(left, top, right, bottom, radii, mode, false)
} }
fun clipRRect(r: RRect, antiAlias: Boolean): Canvas { fun clipRRect(r: RRect, antiAlias: Boolean): Canvas {
return clipRRect(r, ClipMode.INTERSECT, antiAlias) return clipRRect(r.left, r.top, r.right, r.bottom, r.radii, ClipMode.INTERSECT, antiAlias)
}
fun clipRRect(left: Float, top: Float, right: Float, bottom: Float, radii: FloatArray, antiAlias: Boolean): Canvas {
return clipRRect(left, top, right, bottom, radii, ClipMode.INTERSECT, antiAlias)
} }
fun clipRRect(r: RRect): Canvas { fun clipRRect(left: Float, top: Float, right: Float, bottom: Float, radii: FloatArray): Canvas {
return clipRRect(r, ClipMode.INTERSECT, false) return clipRRect(left, top, right, bottom, radii, ClipMode.INTERSECT, false)
} }
fun clipPath(p: Path, mode: ClipMode, antiAlias: Boolean): Canvas { fun clipPath(p: Path, mode: ClipMode, antiAlias: Boolean): Canvas {
......
...@@ -64,14 +64,14 @@ class Codec internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHo ...@@ -64,14 +64,14 @@ class Codec internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHo
val encodedOrigin: EncodedOrigin val encodedOrigin: EncodedOrigin
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
EncodedOrigin.values().get(_nGetEncodedOrigin(_ptr)) EncodedOrigin.entries[_nGetEncodedOrigin(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
val encodedImageFormat: EncodedImageFormat val encodedImageFormat: EncodedImageFormat
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
EncodedImageFormat.values().get(_nGetEncodedImageFormat(_ptr)) EncodedImageFormat.entries[_nGetEncodedImageFormat(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
......
...@@ -214,7 +214,7 @@ class Font : Managed { ...@@ -214,7 +214,7 @@ class Font : Managed {
var edging: FontEdging var edging: FontEdging
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
FontEdging.values().get(_nGetEdging(_ptr)) FontEdging.entries[_nGetEdging(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -231,7 +231,7 @@ class Font : Managed { ...@@ -231,7 +231,7 @@ class Font : Managed {
var hinting: FontHinting var hinting: FontHinting
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
FontHinting.values().get(_nGetHinting(_ptr)) FontHinting.entries[_nGetHinting(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
......
...@@ -26,7 +26,7 @@ class FontStyle { ...@@ -26,7 +26,7 @@ class FontStyle {
} }
val slant: FontSlant val slant: FontSlant
get() = FontSlant.values()[_value shr 24 and 255] get() = FontSlant.entries[_value shr 24 and 255]
fun withSlant(slant: FontSlant): FontStyle { fun withSlant(slant: FontSlant): FontStyle {
return FontStyle(weight, width, slant) return FontStyle(weight, width, slant)
......
...@@ -5,6 +5,7 @@ import org.jetbrains.skia.impl.* ...@@ -5,6 +5,7 @@ import org.jetbrains.skia.impl.*
class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) { class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) {
companion object { companion object {
fun makeArithmetic( fun makeArithmetic(
k1: Float, k1: Float,
k2: Float, k2: Float,
...@@ -199,16 +200,23 @@ class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) { ...@@ -199,16 +200,23 @@ class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) {
} }
fun makeImage(image: Image): ImageFilter { fun makeImage(image: Image): ImageFilter {
val r: Rect = Rect.makeWH(image.width.toFloat(), image.height.toFloat()) return makeImage(
return makeImage(image, r, r, SamplingMode.DEFAULT) image,
0f,
0f,
image.width.toFloat(),
image.height.toFloat(),
0f,
0f,
image.width.toFloat(),
image.height.toFloat(),
SamplingMode.DEFAULT
)
} }
fun makeImage(image: Image?, src: Rect, dst: Rect, mode: SamplingMode): ImageFilter { fun makeImage(image: Image?, src: Rect, dst: Rect, mode: SamplingMode): ImageFilter {
return try { return makeImage(
Stats.onNativeCall() image,
ImageFilter(
_nMakeImage(
getPtr(image),
src.left, src.left,
src.top, src.top,
src.right, src.right,
...@@ -217,6 +225,35 @@ class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) { ...@@ -217,6 +225,35 @@ class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) {
dst.top, dst.top,
dst.right, dst.right,
dst.bottom, dst.bottom,
mode
)
}
fun makeImage(
image: Image?,
srcLeft: Float,
srcTop: Float,
srcRight: Float,
srcBottom: Float,
dstLeft: Float,
dstTop: Float,
dstRight: Float,
dstBottom: Float,
mode: SamplingMode
): ImageFilter {
return try {
Stats.onNativeCall()
ImageFilter(
_nMakeImage(
getPtr(image),
srcLeft,
srcTop,
srcRight,
srcBottom,
dstLeft,
dstTop,
dstRight,
dstBottom,
mode._packedInt1(), mode._packedInt1(),
mode._packedInt2() mode._packedInt2()
) )
...@@ -400,10 +437,7 @@ class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) { ...@@ -400,10 +437,7 @@ class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) {
} }
fun makeTile(src: Rect, dst: Rect, input: ImageFilter?): ImageFilter { fun makeTile(src: Rect, dst: Rect, input: ImageFilter?): ImageFilter {
return try { return makeTile(
Stats.onNativeCall()
ImageFilter(
_nMakeTile(
src.left, src.left,
src.top, src.top,
src.right, src.right,
...@@ -412,6 +446,33 @@ class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) { ...@@ -412,6 +446,33 @@ class ImageFilter internal constructor(ptr: NativePointer) : RefCnt(ptr) {
dst.top, dst.top,
dst.right, dst.right,
dst.bottom, dst.bottom,
input
)
}
fun makeTile(
srcLeft: Float,
srcTop: Float,
srcRight: Float,
srcBottom: Float,
dstLeft: Float,
dstTop: Float,
dstRight: Float,
dstBottom: Float,
input: ImageFilter?
): ImageFilter {
return try {
Stats.onNativeCall()
ImageFilter(
_nMakeTile(
srcLeft,
srcTop,
srcRight,
srcBottom,
dstLeft,
dstTop,
dstRight,
dstBottom,
getPtr(input) getPtr(input)
) )
) )
......
...@@ -42,8 +42,8 @@ class ImageInfo(val colorInfo: ColorInfo, val width: Int, val height: Int) { ...@@ -42,8 +42,8 @@ class ImageInfo(val colorInfo: ColorInfo, val width: Int, val height: Int) {
internal constructor(width: Int, height: Int, colorType: Int, alphaType: Int, colorSpace: NativePointer) : this( internal constructor(width: Int, height: Int, colorType: Int, alphaType: Int, colorSpace: NativePointer) : this(
width, width,
height, height,
ColorType.values()[colorType], ColorType.entries[colorType],
ColorAlphaType.values()[alphaType], ColorAlphaType.entries[alphaType],
if (colorSpace == Native.NullPointer) null else ColorSpace(colorSpace) if (colorSpace == Native.NullPointer) null else ColorSpace(colorSpace)
) )
......
...@@ -122,7 +122,7 @@ class Paint : Managed { ...@@ -122,7 +122,7 @@ class Paint : Managed {
var mode: PaintMode var mode: PaintMode
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
PaintMode.values().get(_nGetMode(_ptr)) PaintMode.entries[_nGetMode(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -338,7 +338,7 @@ class Paint : Managed { ...@@ -338,7 +338,7 @@ class Paint : Managed {
var strokeCap: PaintStrokeCap var strokeCap: PaintStrokeCap
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
PaintStrokeCap.values().get(_nGetStrokeCap(_ptr)) PaintStrokeCap.entries[_nGetStrokeCap(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -359,7 +359,7 @@ class Paint : Managed { ...@@ -359,7 +359,7 @@ class Paint : Managed {
var strokeJoin: PaintStrokeJoin var strokeJoin: PaintStrokeJoin
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
PaintStrokeJoin.values().get(_nGetStrokeJoin(_ptr)) PaintStrokeJoin.entries[_nGetStrokeJoin(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -436,7 +436,7 @@ class Paint : Managed { ...@@ -436,7 +436,7 @@ class Paint : Managed {
var blendMode: BlendMode var blendMode: BlendMode
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
BlendMode.values().get(_nGetBlendMode(_ptr)) BlendMode.entries[_nGetBlendMode(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
......
...@@ -320,7 +320,7 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol ...@@ -320,7 +320,7 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
var fillMode: PathFillMode var fillMode: PathFillMode
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
PathFillMode.values().get(_nGetFillMode(_ptr)) PathFillMode.entries[_nGetFillMode(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -685,9 +685,7 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol ...@@ -685,9 +685,7 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
out?.let { ptr.fromInterop(it) } out?.let { ptr.fromInterop(it) }
} }
} }
if (verbs != null) for (i in 0 until minOf(count, max)) verbs[i] = PathVerb.values().get( if (verbs != null) for (i in 0 until minOf(count, max)) verbs[i] = PathVerb.entries[out!![i].toInt()]
out!![i].toInt()
)
count count
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
...@@ -1252,8 +1250,35 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol ...@@ -1252,8 +1250,35 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
* @see [https://fiddle.skia.org/c/@Path_arcTo](https://fiddle.skia.org/c/@Path_arcTo) * @see [https://fiddle.skia.org/c/@Path_arcTo](https://fiddle.skia.org/c/@Path_arcTo)
*/ */
fun arcTo(oval: Rect, startAngle: Float, sweepAngle: Float, forceMoveTo: Boolean): Path { fun arcTo(oval: Rect, startAngle: Float, sweepAngle: Float, forceMoveTo: Boolean): Path {
return arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, forceMoveTo)
}
/**
*
* Appends arc to Path. Arc added is part of ellipse
* bounded by oval, from startAngle through sweepAngle. Both startAngle and
* sweepAngle are measured in degrees, where zero degrees is aligned with the
* positive x-axis, and positive sweeps extends arc clockwise.
*
*
* arcTo() adds line connecting Path last Point to initial arc Point if forceMoveTo
* is false and Path is not empty. Otherwise, added contour begins with first point
* of arc. Angles greater than -360 and less than 360 are treated modulo 360.
*
* @param left left edge of oval bounding ellipse
* @param top top edge of oval bounding ellipse
* @param right right edge of oval bounding ellipse
* @param bottom bottom edge of oval bounding ellipse
* @param startAngle starting angle of arc in degrees
* @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360
* @param forceMoveTo true to start a new contour with arc
* @return reference to Path
*
* @see [https://fiddle.skia.org/c/@Path_arcTo](https://fiddle.skia.org/c/@Path_arcTo)
*/
fun arcTo(left: Float, top: Float, right: Float, bottom: Float, startAngle: Float, sweepAngle: Float, forceMoveTo: Boolean): Path {
Stats.onNativeCall() Stats.onNativeCall()
_nArcTo(_ptr, oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, forceMoveTo) _nArcTo(_ptr, left, top, right, bottom, startAngle, sweepAngle, forceMoveTo)
return this return this
} }
...@@ -1504,28 +1529,37 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol ...@@ -1504,28 +1529,37 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
/** /**
* Adds Rect to Path, appending [PathVerb.MOVE], three [PathVerb.LINE], and [PathVerb.CLOSE], * Adds Rect to Path, appending [PathVerb.MOVE], three [PathVerb.LINE], and [PathVerb.CLOSE],
* starting with top-left corner of Rect; followed by top-right, bottom-right, * starting with top-left corner of Rect; followed by top-right, bottom-right,
* and bottom-left. * and bottom-left if dir is [PathDirection.CLOCKWISE]; or followed by bottom-left,
* bottom-right, and top-right if dir is [PathDirection.COUNTER_CLOCKWISE].
* *
* @param rect Rect to add as a closed contour * @param rect Rect to add as a closed contour
* @param dir Direction to wind added contour
* @return reference to Path * @return reference to Path
* *
* @see [https://fiddle.skia.org/c/@Path_addRect](https://fiddle.skia.org/c/@Path_addRect) * @see [https://fiddle.skia.org/c/@Path_addRect](https://fiddle.skia.org/c/@Path_addRect)
*/ */
fun addRect(rect: Rect, dir: PathDirection = PathDirection.CLOCKWISE, start: Int = 0): Path {
return addRect(rect.left, rect.top, rect.right, rect.bottom, dir, start)
}
/** /**
* Adds Rect to Path, appending [PathVerb.MOVE], three [PathVerb.LINE], and [PathVerb.CLOSE], * Adds Rect to Path, appending [PathVerb.MOVE], three [PathVerb.LINE], and [PathVerb.CLOSE],
* starting with top-left corner of Rect; followed by top-right, bottom-right, * starting with top-left corner of Rect; followed by top-right, bottom-right,
* and bottom-left if dir is [PathDirection.CLOCKWISE]; or followed by bottom-left, * and bottom-left if dir is [PathDirection.CLOCKWISE]; or followed by bottom-left,
* bottom-right, and top-right if dir is [PathDirection.COUNTER_CLOCKWISE]. * bottom-right, and top-right if dir is [PathDirection.COUNTER_CLOCKWISE].
* *
* @param rect Rect to add as a closed contour * @param left left edge of Rect to add as a closed contour
* @param top top edge of Rect to add as a closed contour
* @param right right edge of Rect to add as a closed contour
* @param bottom bottom edge of Rect to add as a closed contour
* @param dir Direction to wind added contour * @param dir Direction to wind added contour
* @return reference to Path * @return reference to Path
* *
* @see [https://fiddle.skia.org/c/@Path_addRect](https://fiddle.skia.org/c/@Path_addRect) * @see [https://fiddle.skia.org/c/@Path_addRect](https://fiddle.skia.org/c/@Path_addRect)
*/ */
fun addRect(rect: Rect, dir: PathDirection = PathDirection.CLOCKWISE, start: Int = 0): Path { fun addRect(left: Float, top: Float, right: Float, bottom: Float, dir: PathDirection = PathDirection.CLOCKWISE, start: Int = 0): Path {
Stats.onNativeCall() Stats.onNativeCall()
_nAddRect(_ptr, rect.left, rect.top, rect.right, rect.bottom, dir.ordinal, start) _nAddRect(_ptr, left, top, right, bottom, dir.ordinal, start)
return this return this
} }
/** /**
...@@ -1548,13 +1582,18 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol ...@@ -1548,13 +1582,18 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
* *
* Oval is upright ellipse bounded by Rect oval with radii equal to half oval width * Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
* and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues * and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
* clockwise. * clockwise if dir is [PathDirection.CLOCKWISE], counterclockwise if dir is [PathDirection.COUNTER_CLOCKWISE].
* *
* @param oval bounds of ellipse added * @param oval bounds of ellipse added
* @param dir Direction to wind ellipse
* @return reference to Path * @return reference to Path
* *
* @see [https://fiddle.skia.org/c/@Path_addOval](https://fiddle.skia.org/c/@Path_addOval) * @see [https://fiddle.skia.org/c/@Path_addOval](https://fiddle.skia.org/c/@Path_addOval)
*/ */
fun addOval(oval: Rect, dir: PathDirection = PathDirection.CLOCKWISE, start: Int = 1): Path {
return addOval(oval.left, oval.top, oval.right, oval.bottom, dir, start)
}
/** /**
* *
* Adds oval to path, appending [PathVerb.MOVE], four [PathVerb.CONIC], and [PathVerb.CLOSE]. * Adds oval to path, appending [PathVerb.MOVE], four [PathVerb.CONIC], and [PathVerb.CLOSE].
...@@ -1564,15 +1603,18 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol ...@@ -1564,15 +1603,18 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
* and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues * and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
* clockwise if dir is [PathDirection.CLOCKWISE], counterclockwise if dir is [PathDirection.COUNTER_CLOCKWISE]. * clockwise if dir is [PathDirection.CLOCKWISE], counterclockwise if dir is [PathDirection.COUNTER_CLOCKWISE].
* *
* @param oval bounds of ellipse added * @param left left edge of oval bounding ellipse
* @param top top edge of oval bounding ellipse
* @param right right edge of oval bounding ellipse
* @param bottom bottom edge of oval bounding ellipse
* @param dir Direction to wind ellipse * @param dir Direction to wind ellipse
* @return reference to Path * @return reference to Path
* *
* @see [https://fiddle.skia.org/c/@Path_addOval](https://fiddle.skia.org/c/@Path_addOval) * @see [https://fiddle.skia.org/c/@Path_addOval](https://fiddle.skia.org/c/@Path_addOval)
*/ */
fun addOval(oval: Rect, dir: PathDirection = PathDirection.CLOCKWISE, start: Int = 1): Path { fun addOval(left: Float, top: Float, right: Float, bottom: Float, dir: PathDirection = PathDirection.CLOCKWISE, start: Int = 1): Path {
Stats.onNativeCall() Stats.onNativeCall()
_nAddOval(_ptr, oval.left, oval.top, oval.right, oval.bottom, dir.ordinal, start) _nAddOval(_ptr, left, top, right, bottom, dir.ordinal, start)
return this return this
} }
/** /**
...@@ -1629,9 +1671,7 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol ...@@ -1629,9 +1671,7 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
* @see [https://fiddle.skia.org/c/@Path_addArc](https://fiddle.skia.org/c/@Path_addArc) * @see [https://fiddle.skia.org/c/@Path_addArc](https://fiddle.skia.org/c/@Path_addArc)
*/ */
fun addArc(oval: Rect, startAngle: Float, sweepAngle: Float): Path { fun addArc(oval: Rect, startAngle: Float, sweepAngle: Float): Path {
Stats.onNativeCall() return addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle)
_nAddArc(_ptr, oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle)
return this
} }
/** /**
...@@ -1640,7 +1680,10 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol ...@@ -1640,7 +1680,10 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
* winds clockwise; if dir is [PathDirection.COUNTER_CLOCKWISE], rrect winds counterclockwise. * winds clockwise; if dir is [PathDirection.COUNTER_CLOCKWISE], rrect winds counterclockwise.
* start determines the first point of rrect to add. * start determines the first point of rrect to add.
* *
* @param rrect bounds and radii of rounded rectangle * @param left left edge of rounded rectangle
* @param top top edge of rounded rectangle
* @param right right edge of rounded rectangle
* @param bottom bottom edge of rounded rectangle
* @param dir Direction to wind RRect * @param dir Direction to wind RRect
* @param start index of initial point of RRect. 0 for top-right end of the arc at top left, * @param start index of initial point of RRect. 0 for top-right end of the arc at top left,
* 1 for top-left end of the arc at top right, 2 for bottom-right end of top right arc, etc. * 1 for top-left end of the arc at top right, 2 for bottom-right end of top right arc, etc.
...@@ -1648,6 +1691,12 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol ...@@ -1648,6 +1691,12 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
* *
* @see [https://fiddle.skia.org/c/@Path_addRRect_2](https://fiddle.skia.org/c/@Path_addRRect_2) * @see [https://fiddle.skia.org/c/@Path_addRRect_2](https://fiddle.skia.org/c/@Path_addRRect_2)
*/ */
fun addArc(left: Float, top: Float, right: Float, bottom: Float, startAngle: Float, sweepAngle: Float): Path {
Stats.onNativeCall()
_nAddArc(_ptr, left, top, right, bottom, startAngle, sweepAngle)
return this
}
/** /**
* *
* Adds rrect to Path, creating a new closed contour. RRect starts at top-left of the lower-left corner and * Adds rrect to Path, creating a new closed contour. RRect starts at top-left of the lower-left corner and
...@@ -1662,9 +1711,31 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol ...@@ -1662,9 +1711,31 @@ class Path internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHol
* @see [https://fiddle.skia.org/c/@Path_addRRect](https://fiddle.skia.org/c/@Path_addRRect) * @see [https://fiddle.skia.org/c/@Path_addRRect](https://fiddle.skia.org/c/@Path_addRRect)
*/ */
fun addRRect(rrect: RRect, dir: PathDirection = PathDirection.CLOCKWISE, start: Int = 6): Path { fun addRRect(rrect: RRect, dir: PathDirection = PathDirection.CLOCKWISE, start: Int = 6): Path {
return addRRect(rrect.left, rrect.top, rrect.right, rrect.bottom, rrect.radii, dir, start)
}
/**
*
* Adds rrect to Path, creating a new closed contour. RRect starts at top-left of the lower-left corner and
* winds clockwise.
*
*
* After appending, Path may be empty, or may contain: Rect, Oval, or RRect.
*
* @param left left edge of rounded rectangle
* @param top top edge of rounded rectangle
* @param right right edge of rounded rectangle
* @param bottom bottom edge of rounded rectangle
* @param radii array of 8 radius values, 2 for each corner
* @param dir Direction to wind rounded rectangle
* @return reference to Path
*
* @see [https://fiddle.skia.org/c/@Path_addRRect](https://fiddle.skia.org/c/@Path_addRRect)
*/
fun addRRect(left: Float, top: Float, right: Float, bottom: Float, radii: FloatArray, dir: PathDirection = PathDirection.CLOCKWISE, start: Int = 6): Path {
Stats.onNativeCall() Stats.onNativeCall()
interopScope { interopScope {
_nAddRRect(_ptr, rrect.left, rrect.top, rrect.right, rrect.bottom, toInterop(rrect.radii), rrect.radii.size, dir.ordinal, start) _nAddRRect(_ptr, left, top, right, bottom, toInterop(radii), radii.size, dir.ordinal, start)
} }
return this return this
} }
......
...@@ -12,12 +12,10 @@ class PathSegment constructor( ...@@ -12,12 +12,10 @@ class PathSegment constructor(
) { ) {
constructor(verbOrdinal: Int, x0: Float, y0: Float, isClosedContour: Boolean) : this( constructor(verbOrdinal: Int, x0: Float, y0: Float, isClosedContour: Boolean) : this(
PathVerb.values().get( PathVerb.entries[verbOrdinal], Point(x0, y0), null, null, null, 0.0f, false, isClosedContour
verbOrdinal
), Point(x0, y0), null, null, null, 0.0f, false, isClosedContour
) { ) {
require(verbOrdinal == PathVerb.MOVE.ordinal || verbOrdinal == PathVerb.CLOSE.ordinal) { require(verbOrdinal == PathVerb.MOVE.ordinal || verbOrdinal == PathVerb.CLOSE.ordinal) {
"Expected MOVE or CLOSE, got " + PathVerb.values()[verbOrdinal] "Expected MOVE or CLOSE, got " + PathVerb.entries.toTypedArray()[verbOrdinal]
} }
} }
......
...@@ -69,7 +69,7 @@ private fun pathSegmentFromIntArray(points: IntArray): PathSegment { ...@@ -69,7 +69,7 @@ private fun pathSegmentFromIntArray(points: IntArray): PathSegment {
val isClosedLineBit = ((context shr 6) and 1) val isClosedLineBit = ((context shr 6) and 1)
val isClosed = isClosedBit != 0 val isClosed = isClosedBit != 0
return when (PathVerb.values()[verb]) { return when (PathVerb.entries[verb]) {
PathVerb.MOVE, PathVerb.CLOSE -> { PathVerb.MOVE, PathVerb.CLOSE -> {
PathSegment(verb, Float.fromBits(points[0]), Float.fromBits(points[1]), isClosed) PathSegment(verb, Float.fromBits(points[0]), Float.fromBits(points[1]), isClosed)
} }
......
...@@ -36,8 +36,30 @@ class Picture internal constructor(ptr: NativePointer, managed: Boolean = true) ...@@ -36,8 +36,30 @@ class Picture internal constructor(ptr: NativePointer, managed: Boolean = true)
* @see [https://fiddle.skia.org/c/@Picture_MakePlaceholder](https://fiddle.skia.org/c/@Picture_MakePlaceholder) * @see [https://fiddle.skia.org/c/@Picture_MakePlaceholder](https://fiddle.skia.org/c/@Picture_MakePlaceholder)
*/ */
fun makePlaceholder(cull: Rect): Picture { fun makePlaceholder(cull: Rect): Picture {
return makePlaceholder(cull.left, cull.top, cull.right, cull.bottom)
}
/**
*
* Returns a placeholder Picture. Result does not draw, and contains only
* cull Rect, a hint of its bounds. Result is immutable; it cannot be changed
* later. Result identifier is unique.
*
*
* Returned placeholder can be intercepted during playback to insert other
* commands into Canvas draw stream.
*
* @param left placeholder left coordinate
* @param top placeholder top coordinate
* @param right placeholder right coordinate
* @param bottom placeholder bottom coordinate
* @return placeholder with unique identifier
*
* @see [https://fiddle.skia.org/c/@Picture_MakePlaceholder](https://fiddle.skia.org/c/@Picture_MakePlaceholder)
*/
fun makePlaceholder(left: Float, top: Float, right: Float, bottom: Float): Picture {
Stats.onNativeCall() Stats.onNativeCall()
return Picture(_nMakePlaceholder(cull.left, cull.top, cull.right, cull.bottom)) return Picture(_nMakePlaceholder(left, top, right, bottom))
} }
init { init {
......
package org.jetbrains.skia package org.jetbrains.skia
import org.jetbrains.skia.impl.*
import org.jetbrains.skia.impl.Library.Companion.staticLoad import org.jetbrains.skia.impl.Library.Companion.staticLoad
import org.jetbrains.skia.impl.Managed
import org.jetbrains.skia.impl.NativePointer
import org.jetbrains.skia.impl.Stats
import org.jetbrains.skia.impl.getPtr
import org.jetbrains.skia.impl.reachabilityBarrier
class PictureRecorder internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHolder.PTR) { class PictureRecorder internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHolder.PTR) {
companion object { companion object {
...@@ -49,15 +45,39 @@ class PictureRecorder internal constructor(ptr: NativePointer) : Managed(ptr, _F ...@@ -49,15 +45,39 @@ class PictureRecorder internal constructor(ptr: NativePointer) : Managed(ptr, _F
* @return the canvas. * @return the canvas.
*/ */
fun beginRecording(bounds: Rect, bbh: BBHFactory? = null): Canvas { fun beginRecording(bounds: Rect, bbh: BBHFactory? = null): Canvas {
return beginRecording(
bounds.left,
bounds.top,
bounds.right,
bounds.bottom,
bbh
)
}
/**
* Returns the canvas that records the drawing commands.
*
* @param left the left side of the cull rect used when recording this picture. Any drawing
* that falls outside of this rect is undefined and may be drawn, or it may not.
* @param top the top side of the cull rect used when recording this picture. Any drawing
* that falls outside of this rect is undefined and may be drawn, or it may not.
* @param right the right side of the cull rect used when recording this picture. Any drawing
* that falls outside of this rect is undefined and may be drawn, or it may not.
* @param bottom the bottom side of the cull rect used when recording this picture. Any drawing
* that falls outside of this rect is undefined and may be drawn, or it may not.
* @param bbh optional acceleration structure
* @return the canvas.
*/
fun beginRecording(left: Float, top: Float, right: Float, bottom: Float, bbh: BBHFactory? = null): Canvas {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
Canvas( Canvas(
_nBeginRecording( _nBeginRecording(
_ptr, _ptr,
bounds.left, left,
bounds.top, top,
bounds.right, right,
bounds.bottom, bottom,
getPtr(bbh) getPtr(bbh)
), false, this ), false, this
) )
...@@ -109,15 +129,41 @@ class PictureRecorder internal constructor(ptr: NativePointer) : Managed(ptr, _F ...@@ -109,15 +129,41 @@ class PictureRecorder internal constructor(ptr: NativePointer) : Managed(ptr, _F
* @return the picture containing the recorded content. * @return the picture containing the recorded content.
*/ */
fun finishRecordingAsPicture(cull: Rect): Picture { fun finishRecordingAsPicture(cull: Rect): Picture {
return finishRecordingAsPicture(
cull.left,
cull.top,
cull.right,
cull.bottom
)
}
/**
* Finalizes the recording of the drawing commands and creates an immutable picture object
* that encapsulates the recorded content. The cull rect provided defines the boundaries
* for the recorded content and can be used for bounding box hierarchy (BBH) generation
* and subsequent culling operations. After this call, the canvas returned by any
* `beginRecording` or `getRecordingCanvas` method becomes invalid.
*
* @param cullLeft The left side of the cull rect defining the visible bounds of the recording.
* Any drawing outside this boundary may or may not be included in the result.
* @param cullTop The top side of the cull rect defining the visible bounds of the recording.
* Any drawing outside this boundary may or may not be included in the result.
* @param cullRight The right side of the cull rect defining the visible bounds of the recording.
* Any drawing outside this boundary may or may not be included in the result.
* @param cullBottom The bottom side of the cull rect defining the visible bounds of the recording.
* Any drawing outside this boundary may or may not be included in the result.
* @return An immutable [Picture] object that contains the recorded drawing commands.
*/
fun finishRecordingAsPicture(cullLeft: Float, cullTop: Float, cullRight: Float, cullBottom: Float): Picture {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
Picture( Picture(
_nFinishRecordingAsPictureWithCull( _nFinishRecordingAsPictureWithCull(
_ptr, _ptr,
cull.left, cullLeft,
cull.top, cullTop,
cull.right, cullRight,
cull.bottom cullBottom
) )
) )
} finally { } finally {
......
...@@ -14,7 +14,7 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) { ...@@ -14,7 +14,7 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) {
DIFFERENCE, INTERSECT, UNION, XOR, REVERSE_DIFFERENCE, REPLACE; DIFFERENCE, INTERSECT, UNION, XOR, REVERSE_DIFFERENCE, REPLACE;
companion object { companion object {
internal val _values = values() internal val _values = Op.entries.toTypedArray()
} }
} }
...@@ -92,9 +92,13 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) { ...@@ -92,9 +92,13 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) {
} }
fun setRect(rect: IRect): Boolean { fun setRect(rect: IRect): Boolean {
return setRect(rect.left, rect.top, rect.right, rect.bottom)
}
fun setRect(left: Int, top: Int, right: Int, bottom: Int): Boolean {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
Region_nSetRect(_ptr, rect.left, rect.top, rect.right, rect.bottom) Region_nSetRect(_ptr, left, top, right, bottom)
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -144,9 +148,13 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) { ...@@ -144,9 +148,13 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) {
} }
fun intersects(rect: IRect): Boolean { fun intersects(rect: IRect): Boolean {
return intersects(rect.left, rect.top, rect.right, rect.bottom)
}
fun intersects(left: Int, top: Int, right: Int, bottom: Int): Boolean {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
Region_nIntersectsIRect(_ptr, rect.left, rect.top, rect.right, rect.bottom) Region_nIntersectsIRect(_ptr, left, top, right, bottom)
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -174,15 +182,19 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) { ...@@ -174,15 +182,19 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) {
} }
} }
operator fun contains(rect: IRect): Boolean { fun contains(left: Int, top: Int, right: Int, bottom: Int): Boolean {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
Region_nContainsIRect(_ptr, rect.left, rect.top, rect.right, rect.bottom) Region_nContainsIRect(_ptr, left, top, right, bottom)
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
} }
operator fun contains(rect: IRect): Boolean {
return contains(rect.left, rect.top, rect.right, rect.bottom)
}
operator fun contains(r: Region?): Boolean { operator fun contains(r: Region?): Boolean {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
...@@ -194,18 +206,24 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) { ...@@ -194,18 +206,24 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) {
} }
fun quickContains(rect: IRect): Boolean { fun quickContains(rect: IRect): Boolean {
return quickContains(rect.left, rect.top, rect.right, rect.bottom)
}
fun quickContains(left: Int, top: Int, right: Int, bottom: Int): Boolean {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
Region_nQuickContains(_ptr, rect.left, rect.top, rect.right, rect.bottom) Region_nQuickContains(_ptr, left, top, right, bottom)
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
} }
fun quickReject(rect: IRect): Boolean { fun quickReject(rect: IRect): Boolean {
return quickReject(rect.left, rect.top, rect.right, rect.bottom)
}
fun quickReject(left: Int, top: Int, right: Int, bottom: Int): Boolean {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
Region_nQuickRejectIRect(_ptr, rect.left, rect.top, rect.right, rect.bottom) Region_nQuickRejectIRect(_ptr, left, top, right, bottom)
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -234,14 +252,18 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) { ...@@ -234,14 +252,18 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) {
} }
fun op(rect: IRect, op: Op): Boolean { fun op(rect: IRect, op: Op): Boolean {
return op(rect.left, rect.top, rect.right, rect.bottom, op)
}
fun op(left: Int, top: Int, right: Int, bottom: Int, op: Op): Boolean {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
Region_nOpIRect( Region_nOpIRect(
_ptr, _ptr,
rect.left, left,
rect.top, top,
rect.right, right,
rect.bottom, bottom,
op.ordinal op.ordinal
) )
} finally { } finally {
...@@ -264,14 +286,25 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) { ...@@ -264,14 +286,25 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) {
} }
fun op(rect: IRect, r: Region?, op: Op): Boolean { fun op(rect: IRect, r: Region?, op: Op): Boolean {
return try { return op(
Stats.onNativeCall()
Region_nOpIRectRegion(
_ptr,
rect.left, rect.left,
rect.top, rect.top,
rect.right, rect.right,
rect.bottom, rect.bottom,
r,
op
)
}
fun op(left: Int, top: Int, right: Int, bottom: Int, r: Region?, op: Op): Boolean {
return try {
Stats.onNativeCall()
Region_nOpIRectRegion(
_ptr,
left,
top,
right,
bottom,
getPtr(r), getPtr(r),
op.ordinal op.ordinal
) )
...@@ -282,15 +315,26 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) { ...@@ -282,15 +315,26 @@ class Region : Managed(Region_nMake(), _FinalizerHolder.PTR) {
} }
fun op(r: Region?, rect: IRect, op: Op): Boolean { fun op(r: Region?, rect: IRect, op: Op): Boolean {
return op(
r,
rect.left,
rect.top,
rect.right,
rect.bottom,
op
)
}
fun op(r: Region?, left: Int, top: Int, right: Int, bottom: Int, op: Op): Boolean {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
Region_nOpRegionIRect( Region_nOpRegionIRect(
_ptr, _ptr,
getPtr(r), getPtr(r),
rect.left, left,
rect.top, top,
rect.right, right,
rect.bottom, bottom,
op.ordinal op.ordinal
) )
} finally { } finally {
......
...@@ -2,7 +2,6 @@ package org.jetbrains.skia ...@@ -2,7 +2,6 @@ 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.RenderException
class Surface : RefCnt { class Surface : RefCnt {
companion object { companion object {
...@@ -757,15 +756,36 @@ class Surface : RefCnt { ...@@ -757,15 +756,36 @@ class Surface : RefCnt {
* @see [https://fiddle.skia.org/c/@Surface_makeImageSnapshot_2](https://fiddle.skia.org/c/@Surface_makeImageSnapshot_2) * @see [https://fiddle.skia.org/c/@Surface_makeImageSnapshot_2](https://fiddle.skia.org/c/@Surface_makeImageSnapshot_2)
*/ */
fun makeImageSnapshot(area: IRect): Image? { fun makeImageSnapshot(area: IRect): Image? {
return makeImageSnapshot(area.left, area.top, area.right, area.bottom)
}
/**
*
* Like the no-parameter version, this returns an image of the current surface contents.
*
*
* This variant takes a rectangle specifying the subset of the surface that is of interest.
* These bounds will be sanitized before being used.
*
*
* * If bounds extends beyond the surface, it will be trimmed to just the intersection of it and the surface.
* * If bounds does not intersect the surface, then this returns null.
* * If bounds == the surface, then this is the same as calling the no-parameter variant.
*
*
* @return Image initialized with Surface contents or null
* @see [https://fiddle.skia.org/c/@Surface_makeImageSnapshot_2](https://fiddle.skia.org/c/@Surface_makeImageSnapshot_2)
*/
fun makeImageSnapshot(left: Int, top: Int, right: Int, bottom: Int): Image? {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
Image( Image(
_nMakeImageSnapshotR( _nMakeImageSnapshotR(
_ptr, _ptr,
area.left, left,
area.top, top,
area.right, right,
area.bottom bottom
) )
) )
} finally { } finally {
......
...@@ -95,6 +95,7 @@ class TextBlobBuilder internal constructor(ptr: NativePointer) : Managed(ptr, _F ...@@ -95,6 +95,7 @@ class TextBlobBuilder internal constructor(ptr: NativePointer) : Managed(ptr, _F
reachabilityBarrier(font) reachabilityBarrier(font)
} }
} }
/** /**
* *
* Glyphs are positioned on a baseline at y, using x-axis positions from xs. * Glyphs are positioned on a baseline at y, using x-axis positions from xs.
...@@ -148,6 +149,7 @@ class TextBlobBuilder internal constructor(ptr: NativePointer) : Managed(ptr, _F ...@@ -148,6 +149,7 @@ class TextBlobBuilder internal constructor(ptr: NativePointer) : Managed(ptr, _F
reachabilityBarrier(font) reachabilityBarrier(font)
} }
} }
/** /**
* *
* Glyphs are positioned at positions from pos. * Glyphs are positioned at positions from pos.
......
...@@ -133,6 +133,7 @@ class Typeface internal constructor(ptr: NativePointer) : RefCnt(ptr) { ...@@ -133,6 +133,7 @@ class Typeface internal constructor(ptr: NativePointer) : RefCnt(ptr) {
fun makeClone(variation: FontVariation): Typeface { fun makeClone(variation: FontVariation): Typeface {
return makeClone(arrayOf(variation), 0) return makeClone(arrayOf(variation), 0)
} }
/** /**
* Return a new typeface based on this typeface but parameterized as specified in the * Return a new typeface based on this typeface but parameterized as specified in the
* variations. If the variations does not supply an argument for a parameter * variations. If the variations does not supply an argument for a parameter
......
...@@ -30,7 +30,7 @@ class DecorationStyle( ...@@ -30,7 +30,7 @@ class DecorationStyle(
lineThrough, lineThrough,
gaps, gaps,
color, color,
DecorationLineStyle.values()[lineStyle], DecorationLineStyle.entries[lineStyle],
thicknessMultiplier thicknessMultiplier
) { ) {
} }
......
...@@ -82,7 +82,7 @@ class ParagraphStyle : Managed(ParagraphStyle_nMake(), _FinalizerHolder.PTR) { ...@@ -82,7 +82,7 @@ class ParagraphStyle : Managed(ParagraphStyle_nMake(), _FinalizerHolder.PTR) {
var direction: Direction var direction: Direction
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
Direction.values()[_nGetDirection(_ptr)] Direction.entries[_nGetDirection(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -97,7 +97,7 @@ class ParagraphStyle : Managed(ParagraphStyle_nMake(), _FinalizerHolder.PTR) { ...@@ -97,7 +97,7 @@ class ParagraphStyle : Managed(ParagraphStyle_nMake(), _FinalizerHolder.PTR) {
var alignment: Alignment var alignment: Alignment
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
Alignment.values()[_nGetAlignment(_ptr)] Alignment.entries[_nGetAlignment(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -157,7 +157,7 @@ class ParagraphStyle : Managed(ParagraphStyle_nMake(), _FinalizerHolder.PTR) { ...@@ -157,7 +157,7 @@ class ParagraphStyle : Managed(ParagraphStyle_nMake(), _FinalizerHolder.PTR) {
var heightMode: HeightMode var heightMode: HeightMode
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
HeightMode.values()[_nGetHeightMode(_ptr)] HeightMode.entries[_nGetHeightMode(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -171,7 +171,7 @@ class ParagraphStyle : Managed(ParagraphStyle_nMake(), _FinalizerHolder.PTR) { ...@@ -171,7 +171,7 @@ class ParagraphStyle : Managed(ParagraphStyle_nMake(), _FinalizerHolder.PTR) {
val effectiveAlignment: Alignment val effectiveAlignment: Alignment
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
Alignment.values()[_nGetEffectiveAlignment(_ptr)] Alignment.entries[_nGetEffectiveAlignment(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
...@@ -193,9 +193,9 @@ class ParagraphStyle : Managed(ParagraphStyle_nMake(), _FinalizerHolder.PTR) { ...@@ -193,9 +193,9 @@ class ParagraphStyle : Managed(ParagraphStyle_nMake(), _FinalizerHolder.PTR) {
var fontRastrSettings: FontRastrSettings var fontRastrSettings: FontRastrSettings
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
val edging = FontEdging.values()[_nGetEdging(_ptr)] val edging = FontEdging.entries[_nGetEdging(_ptr)]
Stats.onNativeCall() Stats.onNativeCall()
val hinting = FontHinting.values()[_nGetHinting(_ptr)] val hinting = FontHinting.entries[_nGetHinting(_ptr)]
Stats.onNativeCall() Stats.onNativeCall()
// by some obscure reason kotlinjs makes difference between number encoded booleans returned from `_nGetSubpixel` and regular booleans // by some obscure reason kotlinjs makes difference between number encoded booleans returned from `_nGetSubpixel` and regular booleans
// AssertionError: Expected <FontRastrSettings(edging=ALIAS, hinting=NONE, subpixel=false)>, actual <FontRastrSettings(edging=ALIAS, hinting=NONE, subpixel=0)> // AssertionError: Expected <FontRastrSettings(edging=ALIAS, hinting=NONE, subpixel=false)>, actual <FontRastrSettings(edging=ALIAS, hinting=NONE, subpixel=0)>
......
...@@ -63,7 +63,7 @@ class StrutStyle internal constructor(ptr: NativePointer) : Managed(ptr, _Finali ...@@ -63,7 +63,7 @@ class StrutStyle internal constructor(ptr: NativePointer) : Managed(ptr, _Finali
val fontStyleData = withResult(IntArray(3)) { val fontStyleData = withResult(IntArray(3)) {
_nGetFontStyle(_ptr, it) _nGetFontStyle(_ptr, it)
} }
FontStyle(fontStyleData[0], fontStyleData[1], FontSlant.values()[fontStyleData[2]]) FontStyle(fontStyleData[0], fontStyleData[1], FontSlant.entries[fontStyleData[2]])
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
......
...@@ -11,7 +11,7 @@ class TextBox(val rect: Rect, direction: Direction) { ...@@ -11,7 +11,7 @@ class TextBox(val rect: Rect, direction: Direction) {
constructor(l: Float, t: Float, r: Float, b: Float, direction: Int) : this( constructor(l: Float, t: Float, r: Float, b: Float, direction: Int) : this(
Rect.makeLTRB(l, t, r, b), Rect.makeLTRB(l, t, r, b),
Direction.values().get(direction) Direction.entries[direction]
) )
val direction: Direction val direction: Direction
......
...@@ -49,7 +49,7 @@ class Animation internal constructor(ptr: NativePointer) : Managed(ptr, _Finaliz ...@@ -49,7 +49,7 @@ class Animation internal constructor(ptr: NativePointer) : Managed(ptr, _Finaliz
* @return this * @return this
*/ */
fun render(canvas: Canvas): Animation { fun render(canvas: Canvas): Animation {
return render(canvas, Rect.Companion.makeXYWH(0f, 0f, width, height)) return render(canvas, 0f, 0f, width, height)
} }
/** /**
...@@ -65,7 +65,7 @@ class Animation internal constructor(ptr: NativePointer) : Managed(ptr, _Finaliz ...@@ -65,7 +65,7 @@ class Animation internal constructor(ptr: NativePointer) : Managed(ptr, _Finaliz
* @return this * @return this
*/ */
fun render(canvas: Canvas, offset: Point): Animation { fun render(canvas: Canvas, offset: Point): Animation {
return render(canvas, offset.x, offset.y) return render(canvas, offset.x, offset.y, offset.x + width, offset.y + height)
} }
/** /**
...@@ -82,7 +82,7 @@ class Animation internal constructor(ptr: NativePointer) : Managed(ptr, _Finaliz ...@@ -82,7 +82,7 @@ class Animation internal constructor(ptr: NativePointer) : Managed(ptr, _Finaliz
* @return this * @return this
*/ */
fun render(canvas: Canvas, left: Float, top: Float): Animation { fun render(canvas: Canvas, left: Float, top: Float): Animation {
return render(canvas, Rect.Companion.makeXYWH(left, top, width, height)) return render(canvas, left, top, left + width, top + height)
} }
/** /**
...@@ -99,11 +99,31 @@ class Animation internal constructor(ptr: NativePointer) : Managed(ptr, _Finaliz ...@@ -99,11 +99,31 @@ class Animation internal constructor(ptr: NativePointer) : Managed(ptr, _Finaliz
* @return this * @return this
*/ */
fun render(canvas: Canvas, dst: Rect, vararg renderFlags: RenderFlag): Animation { fun render(canvas: Canvas, dst: Rect, vararg renderFlags: RenderFlag): Animation {
return render(canvas, dst.left, dst.top, dst.right, dst.bottom, renderFlags = renderFlags)
}
/**
*
* Draws the current animation frame
*
*
* It is undefined behavior to call render() on a newly created Animation
* before specifying an initial frame via one of the seek() variants.
*
* @param canvas destination canvas
* @param left destination left
* @param top destination top
* @param right destination right
* @param bottom destination bottom
* @param renderFlags render flags
* @return this
*/
fun render(canvas: Canvas, left: Float, top: Float, right: Float, bottom: Float, vararg renderFlags: RenderFlag): Animation {
return try { return try {
Stats.onNativeCall() Stats.onNativeCall()
var flags = 0 var flags = 0
for (flag in renderFlags) flags = flags or flag._flag for (flag in renderFlags) flags = flags or flag._flag
_nRender(_ptr, getPtr(canvas), dst.left, dst.top, dst.right, dst.bottom, flags) _nRender(_ptr, getPtr(canvas), left, top, right, bottom, flags)
this this
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
......
...@@ -22,7 +22,7 @@ object SVGCanvas { ...@@ -22,7 +22,7 @@ object SVGCanvas {
* @return new Canvas * @return new Canvas
*/ */
fun make(bounds: Rect, out: WStream): Canvas { fun make(bounds: Rect, out: WStream): Canvas {
return make(bounds, out, false, true) return make(bounds.left, bounds.top, bounds.right, bounds.bottom, out, convertTextToPaths = false, prettyXML = true)
} }
/** /**
...@@ -33,20 +33,23 @@ object SVGCanvas { ...@@ -33,20 +33,23 @@ object SVGCanvas {
* The canvas may buffer some drawing calls, so the output is not guaranteed to be valid * The canvas may buffer some drawing calls, so the output is not guaranteed to be valid
* or complete until the canvas instance is deleted. * or complete until the canvas instance is deleted.
* *
* @param bounds defines an initial SVG viewport (viewBox attribute on the root SVG element). * @param left left coordinate of an initial SVG viewport (viewBox attribute on the root SVG element).
* @param top top coordinate of an initial SVG viewport (viewBox attribute on the root SVG element).
* @param right right coordinate of an initial SVG viewport (viewBox attribute on the root SVG element).
* @param bottom bottom coordinate of an initial SVG viewport (viewBox attribute on the root SVG element).
* @param out stream SVG commands will be written to * @param out stream SVG commands will be written to
* @param convertTextToPaths emit text as &lt;path&gt;s * @param convertTextToPaths emit text as &lt;path&gt;s
* @param prettyXML add newlines and tabs in output * @param prettyXML add newlines and tabs in output
* @return new Canvas * @return new Canvas
*/ */
fun make(bounds: Rect, out: WStream, convertTextToPaths: Boolean, prettyXML: Boolean): Canvas { fun make(left: Float, top: Float, right: Float, bottom: Float, out: WStream, convertTextToPaths: Boolean, prettyXML: Boolean): Canvas {
Stats.onNativeCall() Stats.onNativeCall()
val ptr = try { val ptr = try {
_nMake( _nMake(
bounds.left, left,
bounds.top, top,
bounds.right, right,
bounds.bottom, bottom,
getPtr(out), getPtr(out),
0 or (if (convertTextToPaths) 1 else 0) or if (prettyXML) 0 else 2 0 or (if (convertTextToPaths) 1 else 0) or if (prettyXML) 0 else 2
) )
...@@ -56,6 +59,24 @@ object SVGCanvas { ...@@ -56,6 +59,24 @@ object SVGCanvas {
return Canvas(ptr, true, out) return Canvas(ptr, true, out)
} }
/**
* Returns a new canvas that will generate SVG commands from its draw calls, and send
* them to the provided stream. Ownership of the stream is not transfered, and it must
* remain valid for the lifetime of the returned canvas.
*
* The canvas may buffer some drawing calls, so the output is not guaranteed to be valid
* or complete until the canvas instance is deleted.
*
* @param bounds defines an initial SVG viewport (viewBox attribute on the root SVG element).
* @param out stream SVG commands will be written to
* @param convertTextToPaths emit text as &lt;path&gt;s
* @param prettyXML add newlines and tabs in output
* @return new Canvas
*/
fun make(bounds: Rect, out: WStream, convertTextToPaths: Boolean, prettyXML: Boolean): Canvas {
return make(bounds.left, bounds.top, bounds.right, bounds.bottom, out, convertTextToPaths, prettyXML)
}
init { init {
staticLoad() staticLoad()
} }
......
...@@ -12,7 +12,7 @@ class SVGLength(val value: Float, val unit: SVGLengthUnit) { ...@@ -12,7 +12,7 @@ class SVGLength(val value: Float, val unit: SVGLengthUnit) {
} }
} }
internal constructor(value: Float, unit: Int) : this(value, SVGLengthUnit.values()[unit]) internal constructor(value: Float, unit: Int) : this(value, SVGLengthUnit.entries[unit])
constructor(value: Float) : this(value, SVGLengthUnit.NUMBER) {} constructor(value: Float) : this(value, SVGLengthUnit.NUMBER) {}
......
...@@ -17,7 +17,7 @@ abstract class SVGNode internal constructor(ptr: NativePointer) : RefCnt(ptr) { ...@@ -17,7 +17,7 @@ abstract class SVGNode internal constructor(ptr: NativePointer) : RefCnt(ptr) {
val tag: SVGTag val tag: SVGTag
get() = try { get() = try {
Stats.onNativeCall() Stats.onNativeCall()
SVGTag.values()[SVGNode_nGetTag(_ptr)] SVGTag.entries[SVGNode_nGetTag(_ptr)]
} finally { } finally {
reachabilityBarrier(this) reachabilityBarrier(this)
} }
......
...@@ -18,7 +18,7 @@ class SVGPreserveAspectRatio(align: SVGPreserveAspectRatioAlign, scale: SVGPrese ...@@ -18,7 +18,7 @@ class SVGPreserveAspectRatio(align: SVGPreserveAspectRatioAlign, scale: SVGPrese
internal constructor(align: Int, scale: Int) : this( internal constructor(align: Int, scale: Int) : this(
SVGPreserveAspectRatioAlign.valueOf(align), SVGPreserveAspectRatioAlign.valueOf(align),
SVGPreserveAspectRatioScale.values()[scale] SVGPreserveAspectRatioScale.entries[scale]
) )
constructor() : this(SVGPreserveAspectRatioAlign.XMID_YMID, SVGPreserveAspectRatioScale.MEET) constructor() : this(SVGPreserveAspectRatioAlign.XMID_YMID, SVGPreserveAspectRatioScale.MEET)
......
...@@ -27,7 +27,7 @@ enum class GpuPriority(val value: String) { ...@@ -27,7 +27,7 @@ enum class GpuPriority(val value: String) {
Auto("auto"), Integrated("integrated"), Discrete("discrete"); Auto("auto"), Integrated("integrated"), Discrete("discrete");
companion object { companion object {
fun parseOrNull(value: String): GpuPriority? = GpuPriority.values().find { it.value == value } fun parseOrNull(value: String): GpuPriority? = GpuPriority.entries.find { it.value == value }
} }
} }
......
...@@ -242,29 +242,37 @@ class RenderNode internal constructor(ptr: NativePointer, managed: Boolean = tru ...@@ -242,29 +242,37 @@ class RenderNode internal constructor(ptr: NativePointer, managed: Boolean = tru
} }
fun setClipRect(r: Rect, mode: ClipMode = ClipMode.INTERSECT, antiAlias: Boolean = false) { fun setClipRect(r: Rect, mode: ClipMode = ClipMode.INTERSECT, antiAlias: Boolean = false) {
setClipRect(r.left, r.top, r.right, r.bottom, mode, antiAlias)
}
fun setClipRect(left: Float, top: Float, right: Float, bottom: Float, mode: ClipMode = ClipMode.INTERSECT, antiAlias: Boolean = false) {
Stats.onNativeCall() Stats.onNativeCall()
RenderNode_nSetClipRect( RenderNode_nSetClipRect(
ptr = _ptr, ptr = _ptr,
left = r.left, left = left,
top = r.top, top = top,
right = r.right, right = right,
bottom = r.bottom, bottom = bottom,
mode = mode.ordinal, mode = mode.ordinal,
antiAlias = antiAlias antiAlias = antiAlias
) )
} }
fun setClipRRect(r: RRect, mode: ClipMode = ClipMode.INTERSECT, antiAlias: Boolean = false) { fun setClipRRect(r: RRect, mode: ClipMode = ClipMode.INTERSECT, antiAlias: Boolean = false) {
setClipRRect(r.left, r.top, r.right, r.bottom, r.radii, mode, antiAlias)
}
fun setClipRRect(left: Float, top: Float, right: Float, bottom: Float, radii: FloatArray, mode: ClipMode = ClipMode.INTERSECT, antiAlias: Boolean = false) {
Stats.onNativeCall() Stats.onNativeCall()
interopScope { interopScope {
RenderNode_nSetClipRRect( RenderNode_nSetClipRRect(
ptr = _ptr, ptr = _ptr,
left = r.left, left = left,
top = r.top, top = top,
right = r.right, right = right,
bottom = r.bottom, bottom = bottom,
radii = toInterop(r.radii), radii = toInterop(radii),
radiiSize = r.radii.size, radiiSize = radii.size,
mode = mode.ordinal, mode = mode.ordinal,
antiAlias = antiAlias antiAlias = antiAlias
) )
......
...@@ -54,7 +54,7 @@ class ImageFilterTest { ...@@ -54,7 +54,7 @@ class ImageFilterTest {
@Test @Test
fun blend() = imageFilterTest { fun blend() = imageFilterTest {
val region = Region().apply { val region = Region().apply {
setRect(IRect(5, 5, 10, 10)) setRect(5, 5, 10, 10)
} }
ImageFilter.makeBlend( ImageFilter.makeBlend(
blendMode = BlendMode.COLOR, blendMode = BlendMode.COLOR,
...@@ -215,7 +215,7 @@ class ImageFilterTest { ...@@ -215,7 +215,7 @@ class ImageFilterTest {
@Test @Test
fun makeRuntimeShader() = imageFilterTest { fun makeRuntimeShader() = imageFilterTest {
// A simple Skia shader that bumps up the red channel of every non-transparent // A simple Skia shader that bumps up the red channel of every non-transparent
// pixel to full intensity, and leaves green and blue channels unchanged. // pixel to full intensity and leaves green and blue channels unchanged.
val sksl = """ val sksl = """
uniform shader content; uniform shader content;
vec4 main(vec2 coord) { vec4 main(vec2 coord) {
...@@ -476,7 +476,10 @@ class ImageFilterTest { ...@@ -476,7 +476,10 @@ class ImageFilterTest {
val runtimeEffect = RuntimeEffect.makeForShader(sksl) val runtimeEffect = RuntimeEffect.makeForShader(sksl)
val shaderBuilder = RuntimeShaderBuilder(runtimeEffect) val shaderBuilder = RuntimeShaderBuilder(runtimeEffect)
shaderBuilder.uniform("matrix4x4", Matrix44(0.2f, 0.3f, 0.2f, 0.1f, 0.4f, 0.1f, 0.2f, 0.1f, 0.1f, 0.3f, 0.2f, 0.1f, 0.2f, 0.2f, 0.2f, 0.3f)) shaderBuilder.uniform(
"matrix4x4",
Matrix44(0.2f, 0.3f, 0.2f, 0.1f, 0.4f, 0.1f, 0.2f, 0.1f, 0.1f, 0.3f, 0.2f, 0.1f, 0.2f, 0.2f, 0.2f, 0.3f)
)
ImageFilter.makeRuntimeShader( ImageFilter.makeRuntimeShader(
runtimeShaderBuilder = shaderBuilder, runtimeShaderBuilder = shaderBuilder,
...@@ -488,10 +491,10 @@ class ImageFilterTest { ...@@ -488,10 +491,10 @@ class ImageFilterTest {
@Test @Test
fun makeRuntimeShaderFromArrays() = imageFilterTest { fun makeRuntimeShaderFromArrays() = imageFilterTest {
// A Skia shader that has two children shaders - one that applies our custom shader logic // A Skia shader that has two children shaders - one that applies our custom shader logic
// on the underlying render node content, and another that is the built in blur. This // on the underlying render node content, and another that is the built-in blur. This
// shader also has a float uniform that is used to decide which one of these two children // shader also has a float uniform used to decide which one of these two children
// shaders to apply on a given pixel, based on the X coordinate. // shaders to apply on a given pixel, based on the X coordinate.
// This test covers not only ImageFilter.makeRuntimeShader API, but also // This test covers not only ImageFilter.makeRuntimeShader API but also
// RuntimeShaderBuilder.uniform. // RuntimeShaderBuilder.uniform.
val compositeSksl = """ val compositeSksl = """
uniform shader content; uniform shader content;
...@@ -547,7 +550,7 @@ class ImageFilterTest { ...@@ -547,7 +550,7 @@ class ImageFilterTest {
compositeShaderBuilder.uniform("cutoff", 100.0f) compositeShaderBuilder.uniform("cutoff", 100.0f)
compositeShaderBuilder.child( compositeShaderBuilder.child(
"gradient", "gradient",
Shader.Companion.makeLinearGradient( Shader.makeLinearGradient(
x0 = 0.0f, y0 = 0.0f, x0 = 0.0f, y0 = 0.0f,
x1 = 200.0f, y1 = 0.0f, x1 = 200.0f, y1 = 0.0f,
colors = intArrayOf(Color.RED, Color.BLUE), colors = intArrayOf(Color.RED, Color.BLUE),
...@@ -599,8 +602,14 @@ class ImageFilterTest { ...@@ -599,8 +602,14 @@ class ImageFilterTest {
@Test @Test
fun makeTile() = imageFilterTest { fun makeTile() = imageFilterTest {
ImageFilter.makeTile( ImageFilter.makeTile(
src = Rect(0f, 0f, 3f, 3f), 0f,
dst = Rect(5f, 5f, 19f, 19f), 0f,
3f,
3f,
5f,
5f,
19f,
19f,
input = null input = null
) )
} }
......
...@@ -69,7 +69,7 @@ class PathTests { ...@@ -69,7 +69,7 @@ class PathTests {
@Test @Test
fun isShapeTest() { fun isShapeTest() {
for (dir in PathDirection.values()) { for (dir in PathDirection.entries) {
for (start in 0..3) { for (start in 0..3) {
Path().addRect(Rect.makeLTRB(0f, 0f, 40f, 20f), dir, start).use { p -> Path().addRect(Rect.makeLTRB(0f, 0f, 40f, 20f), dir, start).use { p ->
assertEquals(Rect.makeLTRB(0f, 0f, 40f, 20f), p.isRect) assertEquals(Rect.makeLTRB(0f, 0f, 40f, 20f), p.isRect)
...@@ -78,7 +78,7 @@ class PathTests { ...@@ -78,7 +78,7 @@ class PathTests {
} }
} }
} }
for (dir in PathDirection.values()) { for (dir in PathDirection.entries) {
for (start in 0..3) { for (start in 0..3) {
Path().addOval(Rect.makeLTRB(0f, 0f, 40f, 20f), dir, start).use { p -> Path().addOval(Rect.makeLTRB(0f, 0f, 40f, 20f), dir, start).use { p ->
assertNull(p.isRect) assertNull(p.isRect)
...@@ -87,14 +87,14 @@ class PathTests { ...@@ -87,14 +87,14 @@ class PathTests {
} }
} }
} }
for (dir in PathDirection.values()) { for (dir in PathDirection.entries) {
Path().addCircle(20f, 20f, 20f, dir).use { p -> Path().addCircle(20f, 20f, 20f, dir).use { p ->
assertNull(p.isRect) assertNull(p.isRect)
assertEquals(Rect.makeLTRB(0f, 0f, 40f, 40f), p.isOval) assertEquals(Rect.makeLTRB(0f, 0f, 40f, 40f), p.isOval)
assertNull(p.isRRect) assertNull(p.isRRect)
} }
} }
for (dir in PathDirection.values()) { for (dir in PathDirection.entries) {
for (start in 0..7) { for (start in 0..7) {
Path().addRRect(RRect.makeLTRB(0f, 0f, 40f, 20f, 5f), dir, start).use { p -> Path().addRRect(RRect.makeLTRB(0f, 0f, 40f, 20f, 5f), dir, start).use { p ->
assertNull(p.isRect) assertNull(p.isRect)
......
...@@ -2,7 +2,6 @@ package org.jetbrains.skia ...@@ -2,7 +2,6 @@ package org.jetbrains.skia
import org.jetbrains.skiko.tests.runTest import org.jetbrains.skiko.tests.runTest
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
class PathUtilsTest { class PathUtilsTest {
...@@ -30,7 +29,7 @@ class PathUtilsTest { ...@@ -30,7 +29,7 @@ class PathUtilsTest {
strokeWidth = 10f strokeWidth = 10f
mode = PaintMode.STROKE mode = PaintMode.STROKE
} }
val path = Path().arcTo(Rect(0f, 0f, 40f, 40f), 0f, 90f, false) val path = Path().arcTo(0f, 0f, 40f, 40f, 0f, 90f, false)
val fillPath1 = PathUtils.fillPathWithPaint(path, paint,null, 1f) val fillPath1 = PathUtils.fillPathWithPaint(path, paint,null, 1f)
val fillPath001 = PathUtils.fillPathWithPaint(path, paint,null, 0.01f) val fillPath001 = PathUtils.fillPathWithPaint(path, paint,null, 0.01f)
......
...@@ -7,7 +7,7 @@ import kotlin.test.assertEquals ...@@ -7,7 +7,7 @@ import kotlin.test.assertEquals
class PictureTest { class PictureTest {
@Test @Test
fun canMakeShader() { fun canMakeShader() {
val pic = Picture.makePlaceholder(Rect(0.0f, 0.0f, 32.0f, 32.0f)) val pic = Picture.makePlaceholder(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 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) 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)
......
...@@ -14,7 +14,7 @@ class RuntimeShaderBuilderTest { ...@@ -14,7 +14,7 @@ class RuntimeShaderBuilderTest {
} }
val region = Region().apply { val region = Region().apply {
op(IRect(3, 3, 18, 18), Region.Op.UNION) op(3, 3, 18, 18, Region.Op.UNION)
} }
paint.shader = shader paint.shader = shader
......
...@@ -8,8 +8,8 @@ class SamplingModeTest { ...@@ -8,8 +8,8 @@ class SamplingModeTest {
@Test @Test
fun packFilterMipmap() = runTest { fun packFilterMipmap() = runTest {
FilterMode.values().forEach { filterMode -> FilterMode.entries.forEach { filterMode ->
MipmapMode.values().forEach { mipmapMode -> MipmapMode.entries.forEach { mipmapMode ->
val samplingMode = FilterMipmap(filterMode, mipmapMode) val samplingMode = FilterMipmap(filterMode, mipmapMode)
val long = samplingMode._pack() // we treat it as expected since it was used initially val long = samplingMode._pack() // we treat it as expected since it was used initially
......
...@@ -44,7 +44,7 @@ class SurfaceTest { ...@@ -44,7 +44,7 @@ class SurfaceTest {
assertEquals(200, newSurface2.width) assertEquals(200, newSurface2.width)
assertEquals(400, newSurface2.height) assertEquals(400, newSurface2.height)
val image = surface.makeImageSnapshot(IRect(0, 0, 20, 30))!! val image = surface.makeImageSnapshot(0, 0, 20, 30)!!
assertEquals(20, image.width) assertEquals(20, image.width)
assertEquals(30, image.height) assertEquals(30, image.height)
......
...@@ -60,8 +60,8 @@ class RenderNodeTest { ...@@ -60,8 +60,8 @@ class RenderNodeTest {
node.cameraDistance = 12f node.cameraDistance = 12f
assertCloseEnough(12f, node.cameraDistance) assertCloseEnough(12f, node.cameraDistance)
node.setClipRect(Rect(0f, 0f, 16f, 16f)) node.setClipRect(0f, 0f, 16f, 16f)
node.setClipRRect(RRect.makeLTRB(0f, 0f, 16f, 16f, 1f)) node.setClipRRect(0f, 0f, 16f, 16f, floatArrayOf(1f))
node.setClipPath(Path()) node.setClipPath(Path())
node.setClipPath(null) node.setClipPath(null)
...@@ -69,7 +69,7 @@ class RenderNodeTest { ...@@ -69,7 +69,7 @@ class RenderNodeTest {
assertTrue(node.clip) assertTrue(node.clip)
val recordCanvas = node.beginRecording() val recordCanvas = node.beginRecording()
recordCanvas.drawRect(Rect(0f,0f,16f,16f), Paint().apply { color = Color.BLACK }) recordCanvas.drawRect(0f,0f,16f,16f, Paint().apply { color = Color.BLACK })
node.endRecording() node.endRecording()
node.drawInto(surface.canvas) node.drawInto(surface.canvas)
...@@ -86,12 +86,12 @@ class RenderNodeTest { ...@@ -86,12 +86,12 @@ class RenderNodeTest {
node.bounds = Rect(0f, 0f, 100f, 100f) node.bounds = Rect(0f, 0f, 100f, 100f)
val recordCanvas = node.beginRecording() val recordCanvas = node.beginRecording()
recordCanvas.drawRect(Rect(20f,20f,40f,40f), Paint()) recordCanvas.drawRect(20f,20f,40f,40f, Paint())
node.endRecording() node.endRecording()
val pictureRecorder = PictureRecorder() val pictureRecorder = PictureRecorder()
val bbhFactory = RTreeFactory() val bbhFactory = RTreeFactory()
val pictureCanvas = pictureRecorder.beginRecording(Rect(0f, 0f, 100f, 100f), bbhFactory) val pictureCanvas = pictureRecorder.beginRecording(0f, 0f, 100f, 100f, bbhFactory)
node.drawInto(pictureCanvas) node.drawInto(pictureCanvas)
val picture = pictureRecorder.finishRecordingAsPicture() val picture = pictureRecorder.finishRecordingAsPicture()
......
...@@ -169,8 +169,7 @@ actual open class SkiaLayer { ...@@ -169,8 +169,7 @@ actual open class SkiaLayer {
val pictureWidth = (width * contentScale).coerceAtLeast(0.0) val pictureWidth = (width * contentScale).coerceAtLeast(0.0)
val pictureHeight = (height * contentScale).coerceAtLeast(0.0) val pictureHeight = (height * contentScale).coerceAtLeast(0.0)
val bounds = Rect.makeWH(pictureWidth.toFloat(), pictureHeight.toFloat()) val canvas = pictureRecorder.beginRecording(0f, 0f, pictureWidth.toFloat(), pictureHeight.toFloat())
val canvas = pictureRecorder.beginRecording(bounds)
renderDelegate?.onRender(canvas, pictureWidth.toInt(), pictureHeight.toInt(), nanoTime) renderDelegate?.onRender(canvas, pictureWidth.toInt(), pictureHeight.toInt(), nanoTime)
val picture = pictureRecorder.finishRecordingAsPicture() val picture = pictureRecorder.finishRecordingAsPicture()
......
...@@ -8,7 +8,7 @@ import org.jetbrains.skia.impl.withStringReferenceResult ...@@ -8,7 +8,7 @@ import org.jetbrains.skia.impl.withStringReferenceResult
internal actual fun Logger.doInit(ptr: NativePointer) { internal actual fun Logger.doInit(ptr: NativePointer) {
interopScope { interopScope {
val onLog = virtual { val onLog = virtual {
val level = LogLevel.values()[Logger_nGetLogLevel(ptr)] val level = LogLevel.entries[Logger_nGetLogLevel(ptr)]
val message = withStringReferenceResult { Logger_nGetLogMessage(ptr) } val message = withStringReferenceResult { Logger_nGetLogMessage(ptr) }
val json = withStringReferenceNullableResult { Logger_nGetLogJson(ptr) } val json = withStringReferenceNullableResult { Logger_nGetLogJson(ptr) }
log(level, message, json) log(level, message, json)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment