Skip to content

Commit

Permalink
Merge tag 'v0.8.18'
Browse files Browse the repository at this point in the history
  • Loading branch information
silenium-dev committed Jan 7, 2025
2 parents 8c80141 + 6d73ad7 commit 31c2f6d
Show file tree
Hide file tree
Showing 14 changed files with 318 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ fun SkikoProjectContext.createSkikoJvmJarTask(os: OS, arch: Arch, commonJar: Tas
val createChecksums2 = createChecksumsTask(os, altArch, nativeLib2)
nativeFiles.add(nativeLib2)
nativeFiles.add(createChecksums2.map { it.outputs.files.singleFile })
allJvmRuntimeJars[os to altArch] = skikoJvmRuntimeJarTask(os, altArch, commonJar, nativeFiles)
}
val skikoJvmRuntimeJar = skikoJvmRuntimeJarTask(os, arch, commonJar, nativeFiles)
allJvmRuntimeJars[os to arch] = skikoJvmRuntimeJar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ fun String.withSuffix(isUikitSim: Boolean = false) =
fun KotlinTarget.isUikitSimulator() =
name.contains("Simulator", ignoreCase = true) || name == "tvosX64" // x64 tvOS is implicitly a simulator

fun Project.findXcodeSdkRoot(): String {
val defaultPath = "/Applications/Xcode.app/Contents/Developer/Platforms"
if (File(defaultPath).exists()) {
return defaultPath.also {
println("findXcodeSdkRoot = $it")
}
}

return (project.property("skiko.ci.xcodehome") as? String)?.let {
val sdkPath = it + "/Platforms"
println("findXcodeSdkRoot = $sdkPath")
sdkPath
} ?: error("gradle property `skiko.ci.xcodehome` is not set")
}

fun SkikoProjectContext.compileNativeBridgesTask(
os: OS, arch: Arch, isUikitSim: Boolean
): TaskProvider<CompileSkikoCppTask> = with (this.project) {
Expand All @@ -52,7 +67,7 @@ fun SkikoProjectContext.compileNativeBridgesTask(

when (os) {
OS.IOS -> {
val sdkRoot = "/Applications/Xcode.app/Contents/Developer/Platforms"
val sdkRoot = findXcodeSdkRoot()
val iphoneOsSdk = "$sdkRoot/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk"
val iphoneSimSdk = "$sdkRoot/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"
val iosArchFlags = when (arch) {
Expand All @@ -76,7 +91,7 @@ fun SkikoProjectContext.compileNativeBridgesTask(
))
}
OS.TVOS -> {
val sdkRoot = "/Applications/Xcode.app/Contents/Developer/Platforms"
val sdkRoot = findXcodeSdkRoot()
val tvOsSdk = "$sdkRoot/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk"
val tvSimSdk = "$sdkRoot/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator.sdk"
val tvosArchFlags = when (arch) {
Expand Down
2 changes: 1 addition & 1 deletion skiko/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ kotlin.code.style=official
deploy.version=0.0.0


dependencies.skia=m126-d2aaacc35d-4
dependencies.skia=m126-6bfb13368b

# you can override general skia dependencies by passing platform-specific property:
# dependencies.skia.android-arm64
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ internal class SwingOffscreenDrawer(
) {
@Volatile
private var volatileImage: VolatileImage? = null
private var bufferedImage: BufferedImage? = null
private var bufferedImageGraphics: Graphics2D? = null

/**
* Draws rendered image that is represented by [bytes] on [g].
Expand Down Expand Up @@ -56,7 +58,15 @@ internal class SwingOffscreenDrawer(
dirtyRectangles: List<Rectangle>
): BufferedImage {
val src = ByteBuffer.wrap(bytes)
val image = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE)
if (bufferedImage == null || bufferedImage?.width != width || bufferedImage?.height != height) {
bufferedImage?.flush()
bufferedImage = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE)
bufferedImageGraphics = bufferedImage?.createGraphics()
} else {
bufferedImageGraphics?.clearRect(0,0, width, height)
}
val image = bufferedImage!!

val dstData = (image.raster.dataBuffer as DataBufferInt).data
val srcData: IntBuffer = src.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer()
for (rect in dirtyRectangles) {
Expand Down
86 changes: 86 additions & 0 deletions skiko/src/commonMain/kotlin/org/jetbrains/skia/Canvas.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,36 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
}
}

fun saveLayer(layerRec: SaveLayerRec): Int {
return try {
Stats.onNativeCall()
if (layerRec.bounds != null) {
_nSaveLayerSaveLayerRecRect(
_ptr,
layerRec.bounds.left,
layerRec.bounds.top,
layerRec.bounds.right,
layerRec.bounds.bottom,
getPtr(layerRec.paint),
getPtr(layerRec.backdrop),
getPtr(layerRec.colorSpace),
layerRec.saveLayerFlags.mask
)
} else {
_nSaveLayerSaveLayerRec(
_ptr,
getPtr(layerRec.paint),
getPtr(layerRec.backdrop),
getPtr(layerRec.colorSpace),
layerRec.saveLayerFlags.mask
)
}
} finally {
reachabilityBarrier(this)
reachabilityBarrier(layerRec)
}
}

val saveCount: Int
get() = try {
Stats.onNativeCall()
Expand All @@ -1369,6 +1399,39 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
return this
}

class SaveLayerRec(
val bounds: Rect? = null,
val paint: Paint? = null,
val backdrop: ImageFilter? = null,
val colorSpace: ColorSpace? = null,
val saveLayerFlags: SaveLayerFlags = SaveLayerFlags()
)

enum class SaveLayerFlagsSet(val mask: Int) {
PreserveLCDText(1 shl 1),
InitWithPrevious(1 shl 2),
F16ColorType(1 shl 4)
}

class SaveLayerFlags internal constructor(internal val mask: Int) {
constructor(vararg flagsSet: SaveLayerFlagsSet) : this(flagsSet.fold(0) { acc, flag -> acc or flag.mask })

operator fun contains(flag: SaveLayerFlagsSet): Boolean = (mask and flag.mask) != 0

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false

other as SaveLayerFlags

return mask == other.mask
}

override fun hashCode(): Int {
return mask
}
}

private object _FinalizerHolder {
val PTR = Canvas_nGetFinalizer()
}
Expand Down Expand Up @@ -1645,6 +1708,29 @@ private external fun _nSaveLayerRect(
paintPtr: NativePointer
): Int

@ExternalSymbolName("org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRec")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRec")
private external fun _nSaveLayerSaveLayerRec(
ptr: NativePointer,
paintPtr: NativePointer,
backdropImageFilterPtr: NativePointer,
colorSpacePtr: NativePointer,
saveLayerFlags: Int
): Int

@ExternalSymbolName("org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRecRect")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRecRect")
private external fun _nSaveLayerSaveLayerRecRect(
ptr: NativePointer,
left: Float,
top: Float,
right: Float,
bottom: Float,
paintPtr: NativePointer,
backdropImageFilterPtr: NativePointer,
colorSpacePtr: NativePointer,
saveLayerFlags: Int
): Int

@ExternalSymbolName("org_jetbrains_skia_Canvas__1nGetSaveCount")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_Canvas__1nGetSaveCount")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,19 @@ class ParagraphStyle : Managed(ParagraphStyle_nMake(), _FinalizerHolder.PTR) {
reachabilityBarrier(this)
}

var isApplyRoundingHackEnabled: Boolean
get() = try {
Stats.onNativeCall()
_nGetApplyRoundingHack(_ptr).not().not()
} finally {
reachabilityBarrier(this)
}
set(value) = try {
Stats.onNativeCall()
_nSetApplyRoundingHack(_ptr, value)
} finally {
reachabilityBarrier(this)
}

var textIndent: TextIndent
get() = try {
Expand Down Expand Up @@ -322,6 +335,14 @@ private external fun _nGetHinting(ptr: NativePointer): Int
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_paragraph_ParagraphStyle__1nGetSubpixel")
private external fun _nGetSubpixel(ptr: NativePointer): Boolean

@ExternalSymbolName("org_jetbrains_skia_paragraph_ParagraphStyle__1nGetApplyRoundingHack")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_paragraph_ParagraphStyle__1nGetApplyRoundingHack")
private external fun _nGetApplyRoundingHack(ptr: NativePointer): Boolean

@ExternalSymbolName("org_jetbrains_skia_paragraph_ParagraphStyle__1nSetApplyRoundingHack")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_paragraph_ParagraphStyle__1nSetApplyRoundingHack")
private external fun _nSetApplyRoundingHack(ptr: NativePointer, value: Boolean)

@ExternalSymbolName("org_jetbrains_skia_paragraph_ParagraphStyle__1nSetTextIndent")
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_paragraph_ParagraphStyle__1nSetTextIndent")
private external fun _nSetTextIndent(ptr: NativePointer, firstLine: Float, restLine: Float)
Expand Down
64 changes: 57 additions & 7 deletions skiko/src/commonTest/kotlin/org/jetbrains/skia/CanvasTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class CanvasTest {
fun drawString() = runTest {
val surface = Surface.makeRasterN32Premul(100, 100)

val bytes = Bitmap.makeFromImage(surface.makeImageSnapshot()).readPixels()!!
val bytes = Bitmap.makeFromImage(surface.makeImageSnapshot()).readPixels()!!
assertTrue {
bytes.isNotEmpty() && bytes.all { it == 0.toByte() }
}
Expand All @@ -114,7 +114,7 @@ class CanvasTest {
}
)

val bytes2 = Bitmap.makeFromImage(surface.makeImageSnapshot()).readPixels()!!
val bytes2 = Bitmap.makeFromImage(surface.makeImageSnapshot()).readPixels()!!
assertTrue {
bytes2.isNotEmpty() && bytes2.any { it != 0.toByte() }
}
Expand Down Expand Up @@ -210,7 +210,7 @@ class CanvasTest {
surface.canvas.drawBlackPixel(1, 1)

surface.assertPixelsMatch(
IntArray(16){ index ->
IntArray(16) { index ->
when (index) {
10, 11, 14, 15 -> 0xff000000.toInt()
else -> 0xffffffff.toInt()
Expand All @@ -233,7 +233,7 @@ class CanvasTest {
@Test
fun testRotateXY() {
val surface = whiteSurface(4, 4)
surface.canvas.rotate(deg = 90f, x = 2f, y=2f)
surface.canvas.rotate(deg = 90f, x = 2f, y = 2f)
surface.canvas.drawBlackPixel(0, 0)

surface.assertSingleBlackPixelAt(3, 0)
Expand All @@ -247,7 +247,7 @@ class CanvasTest {
surface.canvas.drawBlackPixel(0, 2)

surface.assertPixelsMatch(
IntArray(16){ index ->
IntArray(16) { index ->
when (index) {
// Skewing skews the shape of the pixel itself, so it becomes a parallelogram
9 -> 0xff3f3f3f.toInt()
Expand All @@ -258,6 +258,56 @@ class CanvasTest {
)
}

@Test
fun testSaveLayerRecRect() {
val surface = whiteSurface(5, 5)

surface.canvas.saveLayer(
Canvas.SaveLayerRec(
bounds = Rect(1f, 1f, 4f, 4f),
saveLayerFlags = Canvas.SaveLayerFlags(Canvas.SaveLayerFlagsSet.InitWithPrevious)
)
)

val black = Paint().also { it.setARGB(255, 0, 0, 0) }
surface.canvas.drawRect(Rect(1f, 1f, 4f, 4f), black)

surface.canvas.restore()

surface.assertPixelsMatch(
intArrayOf(
Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
)
)
}


@Test
fun testSaveLayerRec() {
val surface = whiteSurface(5, 5)

surface.canvas.saveLayer(Canvas.SaveLayerRec(saveLayerFlags = Canvas.SaveLayerFlags(Canvas.SaveLayerFlagsSet.InitWithPrevious)))

val black = Paint().also { it.setARGB(255, 0, 0, 0) }
surface.canvas.drawRect(Rect(1f, 1f, 4f, 4f), black)

surface.canvas.restore()

surface.assertPixelsMatch(
intArrayOf(
Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
)
)
}


private fun whiteSurface(width: Int, height: Int): Surface {
val surface = Surface.makeRasterN32Premul(width, height)
Expand Down Expand Up @@ -286,8 +336,8 @@ class CanvasTest {


private fun Surface.assertSingleBlackPixelAt(x: Int, y: Int) {
val pixArray = IntArray(width * height){ 0xffffffff.toInt() }
pixArray[y*width + x] = 0xff000000.toInt()
val pixArray = IntArray(width * height) { 0xffffffff.toInt() }
pixArray[y * width + x] = 0xff000000.toInt()

assertPixelsMatch(pixArray)
}
Expand Down
Loading

0 comments on commit 31c2f6d

Please sign in to comment.