Skip to content

Commit 31c2f6d

Browse files
committed
Merge tag 'v0.8.18'
2 parents 8c80141 + 6d73ad7 commit 31c2f6d

File tree

14 files changed

+318
-20
lines changed

14 files changed

+318
-20
lines changed

skiko/buildSrc/src/main/kotlin/tasks/configuration/JvmTasksConfiguration.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ fun SkikoProjectContext.createSkikoJvmJarTask(os: OS, arch: Arch, commonJar: Tas
457457
val createChecksums2 = createChecksumsTask(os, altArch, nativeLib2)
458458
nativeFiles.add(nativeLib2)
459459
nativeFiles.add(createChecksums2.map { it.outputs.files.singleFile })
460+
allJvmRuntimeJars[os to altArch] = skikoJvmRuntimeJarTask(os, altArch, commonJar, nativeFiles)
460461
}
461462
val skikoJvmRuntimeJar = skikoJvmRuntimeJarTask(os, arch, commonJar, nativeFiles)
462463
allJvmRuntimeJars[os to arch] = skikoJvmRuntimeJar

skiko/buildSrc/src/main/kotlin/tasks/configuration/NativeTasksConfiguration.kt

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@ fun String.withSuffix(isUikitSim: Boolean = false) =
3131
fun KotlinTarget.isUikitSimulator() =
3232
name.contains("Simulator", ignoreCase = true) || name == "tvosX64" // x64 tvOS is implicitly a simulator
3333

34+
fun Project.findXcodeSdkRoot(): String {
35+
val defaultPath = "/Applications/Xcode.app/Contents/Developer/Platforms"
36+
if (File(defaultPath).exists()) {
37+
return defaultPath.also {
38+
println("findXcodeSdkRoot = $it")
39+
}
40+
}
41+
42+
return (project.property("skiko.ci.xcodehome") as? String)?.let {
43+
val sdkPath = it + "/Platforms"
44+
println("findXcodeSdkRoot = $sdkPath")
45+
sdkPath
46+
} ?: error("gradle property `skiko.ci.xcodehome` is not set")
47+
}
48+
3449
fun SkikoProjectContext.compileNativeBridgesTask(
3550
os: OS, arch: Arch, isUikitSim: Boolean
3651
): TaskProvider<CompileSkikoCppTask> = with (this.project) {
@@ -52,7 +67,7 @@ fun SkikoProjectContext.compileNativeBridgesTask(
5267

5368
when (os) {
5469
OS.IOS -> {
55-
val sdkRoot = "/Applications/Xcode.app/Contents/Developer/Platforms"
70+
val sdkRoot = findXcodeSdkRoot()
5671
val iphoneOsSdk = "$sdkRoot/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk"
5772
val iphoneSimSdk = "$sdkRoot/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"
5873
val iosArchFlags = when (arch) {
@@ -76,7 +91,7 @@ fun SkikoProjectContext.compileNativeBridgesTask(
7691
))
7792
}
7893
OS.TVOS -> {
79-
val sdkRoot = "/Applications/Xcode.app/Contents/Developer/Platforms"
94+
val sdkRoot = findXcodeSdkRoot()
8095
val tvOsSdk = "$sdkRoot/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk"
8196
val tvSimSdk = "$sdkRoot/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator.sdk"
8297
val tvosArchFlags = when (arch) {

skiko/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ kotlin.code.style=official
22
deploy.version=0.0.0
33

44

5-
dependencies.skia=m126-d2aaacc35d-4
5+
dependencies.skia=m126-6bfb13368b
66

77
# you can override general skia dependencies by passing platform-specific property:
88
# dependencies.skia.android-arm64

skiko/src/awtMain/kotlin/org/jetbrains/skiko/swing/SwingOffscreenDrawer.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ internal class SwingOffscreenDrawer(
1515
) {
1616
@Volatile
1717
private var volatileImage: VolatileImage? = null
18+
private var bufferedImage: BufferedImage? = null
19+
private var bufferedImageGraphics: Graphics2D? = null
1820

1921
/**
2022
* Draws rendered image that is represented by [bytes] on [g].
@@ -56,7 +58,15 @@ internal class SwingOffscreenDrawer(
5658
dirtyRectangles: List<Rectangle>
5759
): BufferedImage {
5860
val src = ByteBuffer.wrap(bytes)
59-
val image = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE)
61+
if (bufferedImage == null || bufferedImage?.width != width || bufferedImage?.height != height) {
62+
bufferedImage?.flush()
63+
bufferedImage = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE)
64+
bufferedImageGraphics = bufferedImage?.createGraphics()
65+
} else {
66+
bufferedImageGraphics?.clearRect(0,0, width, height)
67+
}
68+
val image = bufferedImage!!
69+
6070
val dstData = (image.raster.dataBuffer as DataBufferInt).data
6171
val srcData: IntBuffer = src.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer()
6272
for (rect in dirtyRectangles) {

skiko/src/commonMain/kotlin/org/jetbrains/skia/Canvas.kt

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,36 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
13491349
}
13501350
}
13511351

1352+
fun saveLayer(layerRec: SaveLayerRec): Int {
1353+
return try {
1354+
Stats.onNativeCall()
1355+
if (layerRec.bounds != null) {
1356+
_nSaveLayerSaveLayerRecRect(
1357+
_ptr,
1358+
layerRec.bounds.left,
1359+
layerRec.bounds.top,
1360+
layerRec.bounds.right,
1361+
layerRec.bounds.bottom,
1362+
getPtr(layerRec.paint),
1363+
getPtr(layerRec.backdrop),
1364+
getPtr(layerRec.colorSpace),
1365+
layerRec.saveLayerFlags.mask
1366+
)
1367+
} else {
1368+
_nSaveLayerSaveLayerRec(
1369+
_ptr,
1370+
getPtr(layerRec.paint),
1371+
getPtr(layerRec.backdrop),
1372+
getPtr(layerRec.colorSpace),
1373+
layerRec.saveLayerFlags.mask
1374+
)
1375+
}
1376+
} finally {
1377+
reachabilityBarrier(this)
1378+
reachabilityBarrier(layerRec)
1379+
}
1380+
}
1381+
13521382
val saveCount: Int
13531383
get() = try {
13541384
Stats.onNativeCall()
@@ -1369,6 +1399,39 @@ open class Canvas internal constructor(ptr: NativePointer, managed: Boolean, int
13691399
return this
13701400
}
13711401

1402+
class SaveLayerRec(
1403+
val bounds: Rect? = null,
1404+
val paint: Paint? = null,
1405+
val backdrop: ImageFilter? = null,
1406+
val colorSpace: ColorSpace? = null,
1407+
val saveLayerFlags: SaveLayerFlags = SaveLayerFlags()
1408+
)
1409+
1410+
enum class SaveLayerFlagsSet(val mask: Int) {
1411+
PreserveLCDText(1 shl 1),
1412+
InitWithPrevious(1 shl 2),
1413+
F16ColorType(1 shl 4)
1414+
}
1415+
1416+
class SaveLayerFlags internal constructor(internal val mask: Int) {
1417+
constructor(vararg flagsSet: SaveLayerFlagsSet) : this(flagsSet.fold(0) { acc, flag -> acc or flag.mask })
1418+
1419+
operator fun contains(flag: SaveLayerFlagsSet): Boolean = (mask and flag.mask) != 0
1420+
1421+
override fun equals(other: Any?): Boolean {
1422+
if (this === other) return true
1423+
if (other == null || this::class != other::class) return false
1424+
1425+
other as SaveLayerFlags
1426+
1427+
return mask == other.mask
1428+
}
1429+
1430+
override fun hashCode(): Int {
1431+
return mask
1432+
}
1433+
}
1434+
13721435
private object _FinalizerHolder {
13731436
val PTR = Canvas_nGetFinalizer()
13741437
}
@@ -1645,6 +1708,29 @@ private external fun _nSaveLayerRect(
16451708
paintPtr: NativePointer
16461709
): Int
16471710

1711+
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRec")
1712+
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRec")
1713+
private external fun _nSaveLayerSaveLayerRec(
1714+
ptr: NativePointer,
1715+
paintPtr: NativePointer,
1716+
backdropImageFilterPtr: NativePointer,
1717+
colorSpacePtr: NativePointer,
1718+
saveLayerFlags: Int
1719+
): Int
1720+
1721+
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRecRect")
1722+
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_Canvas__1nSaveLayerSaveLayerRecRect")
1723+
private external fun _nSaveLayerSaveLayerRecRect(
1724+
ptr: NativePointer,
1725+
left: Float,
1726+
top: Float,
1727+
right: Float,
1728+
bottom: Float,
1729+
paintPtr: NativePointer,
1730+
backdropImageFilterPtr: NativePointer,
1731+
colorSpacePtr: NativePointer,
1732+
saveLayerFlags: Int
1733+
): Int
16481734

16491735
@ExternalSymbolName("org_jetbrains_skia_Canvas__1nGetSaveCount")
16501736
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_Canvas__1nGetSaveCount")

skiko/src/commonMain/kotlin/org/jetbrains/skia/paragraph/ParagraphStyle.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,19 @@ class ParagraphStyle : Managed(ParagraphStyle_nMake(), _FinalizerHolder.PTR) {
191191
reachabilityBarrier(this)
192192
}
193193

194+
var isApplyRoundingHackEnabled: Boolean
195+
get() = try {
196+
Stats.onNativeCall()
197+
_nGetApplyRoundingHack(_ptr).not().not()
198+
} finally {
199+
reachabilityBarrier(this)
200+
}
201+
set(value) = try {
202+
Stats.onNativeCall()
203+
_nSetApplyRoundingHack(_ptr, value)
204+
} finally {
205+
reachabilityBarrier(this)
206+
}
194207

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

338+
@ExternalSymbolName("org_jetbrains_skia_paragraph_ParagraphStyle__1nGetApplyRoundingHack")
339+
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_paragraph_ParagraphStyle__1nGetApplyRoundingHack")
340+
private external fun _nGetApplyRoundingHack(ptr: NativePointer): Boolean
341+
342+
@ExternalSymbolName("org_jetbrains_skia_paragraph_ParagraphStyle__1nSetApplyRoundingHack")
343+
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_paragraph_ParagraphStyle__1nSetApplyRoundingHack")
344+
private external fun _nSetApplyRoundingHack(ptr: NativePointer, value: Boolean)
345+
325346
@ExternalSymbolName("org_jetbrains_skia_paragraph_ParagraphStyle__1nSetTextIndent")
326347
@ModuleImport("./skiko.mjs", "org_jetbrains_skia_paragraph_ParagraphStyle__1nSetTextIndent")
327348
private external fun _nSetTextIndent(ptr: NativePointer, firstLine: Float, restLine: Float)

skiko/src/commonTest/kotlin/org/jetbrains/skia/CanvasTest.kt

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class CanvasTest {
9999
fun drawString() = runTest {
100100
val surface = Surface.makeRasterN32Premul(100, 100)
101101

102-
val bytes = Bitmap.makeFromImage(surface.makeImageSnapshot()).readPixels()!!
102+
val bytes = Bitmap.makeFromImage(surface.makeImageSnapshot()).readPixels()!!
103103
assertTrue {
104104
bytes.isNotEmpty() && bytes.all { it == 0.toByte() }
105105
}
@@ -114,7 +114,7 @@ class CanvasTest {
114114
}
115115
)
116116

117-
val bytes2 = Bitmap.makeFromImage(surface.makeImageSnapshot()).readPixels()!!
117+
val bytes2 = Bitmap.makeFromImage(surface.makeImageSnapshot()).readPixels()!!
118118
assertTrue {
119119
bytes2.isNotEmpty() && bytes2.any { it != 0.toByte() }
120120
}
@@ -210,7 +210,7 @@ class CanvasTest {
210210
surface.canvas.drawBlackPixel(1, 1)
211211

212212
surface.assertPixelsMatch(
213-
IntArray(16){ index ->
213+
IntArray(16) { index ->
214214
when (index) {
215215
10, 11, 14, 15 -> 0xff000000.toInt()
216216
else -> 0xffffffff.toInt()
@@ -233,7 +233,7 @@ class CanvasTest {
233233
@Test
234234
fun testRotateXY() {
235235
val surface = whiteSurface(4, 4)
236-
surface.canvas.rotate(deg = 90f, x = 2f, y=2f)
236+
surface.canvas.rotate(deg = 90f, x = 2f, y = 2f)
237237
surface.canvas.drawBlackPixel(0, 0)
238238

239239
surface.assertSingleBlackPixelAt(3, 0)
@@ -247,7 +247,7 @@ class CanvasTest {
247247
surface.canvas.drawBlackPixel(0, 2)
248248

249249
surface.assertPixelsMatch(
250-
IntArray(16){ index ->
250+
IntArray(16) { index ->
251251
when (index) {
252252
// Skewing skews the shape of the pixel itself, so it becomes a parallelogram
253253
9 -> 0xff3f3f3f.toInt()
@@ -258,6 +258,56 @@ class CanvasTest {
258258
)
259259
}
260260

261+
@Test
262+
fun testSaveLayerRecRect() {
263+
val surface = whiteSurface(5, 5)
264+
265+
surface.canvas.saveLayer(
266+
Canvas.SaveLayerRec(
267+
bounds = Rect(1f, 1f, 4f, 4f),
268+
saveLayerFlags = Canvas.SaveLayerFlags(Canvas.SaveLayerFlagsSet.InitWithPrevious)
269+
)
270+
)
271+
272+
val black = Paint().also { it.setARGB(255, 0, 0, 0) }
273+
surface.canvas.drawRect(Rect(1f, 1f, 4f, 4f), black)
274+
275+
surface.canvas.restore()
276+
277+
surface.assertPixelsMatch(
278+
intArrayOf(
279+
Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
280+
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
281+
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
282+
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
283+
Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
284+
)
285+
)
286+
}
287+
288+
289+
@Test
290+
fun testSaveLayerRec() {
291+
val surface = whiteSurface(5, 5)
292+
293+
surface.canvas.saveLayer(Canvas.SaveLayerRec(saveLayerFlags = Canvas.SaveLayerFlags(Canvas.SaveLayerFlagsSet.InitWithPrevious)))
294+
295+
val black = Paint().also { it.setARGB(255, 0, 0, 0) }
296+
surface.canvas.drawRect(Rect(1f, 1f, 4f, 4f), black)
297+
298+
surface.canvas.restore()
299+
300+
surface.assertPixelsMatch(
301+
intArrayOf(
302+
Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
303+
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
304+
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
305+
Color.WHITE, Color.BLACK, Color.BLACK, Color.BLACK, Color.WHITE,
306+
Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
307+
)
308+
)
309+
}
310+
261311

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

287337

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

292342
assertPixelsMatch(pixArray)
293343
}

0 commit comments

Comments
 (0)