diff --git a/compose/foundation/foundation/src/skikoMain/kotlin/androidx/compose/foundation/draganddrop/DragAndDropSource.skiko.kt b/compose/foundation/foundation/src/skikoMain/kotlin/androidx/compose/foundation/draganddrop/DragAndDropSource.skiko.kt index 368118c3e7566..327f5eda563f9 100644 --- a/compose/foundation/foundation/src/skikoMain/kotlin/androidx/compose/foundation/draganddrop/DragAndDropSource.skiko.kt +++ b/compose/foundation/foundation/src/skikoMain/kotlin/androidx/compose/foundation/draganddrop/DragAndDropSource.skiko.kt @@ -82,7 +82,12 @@ internal actual class CacheDrawScopeDragShadowCallback { onDrawWithContent { val pictureRecorder = PictureRecorder() val pictureCanvas = pictureRecorder - .beginRecording(Rect.makeWH(width, height)) + .beginRecording( + 0f, + 0f, + width, + height + ) .asComposeCanvas() draw( density = this, diff --git a/compose/ui/ui-graphics/src/skikoMain/kotlin/androidx/compose/ui/graphics/SkiaBackedPath.skiko.kt b/compose/ui/ui-graphics/src/skikoMain/kotlin/androidx/compose/ui/graphics/SkiaBackedPath.skiko.kt index ecac9dc4685e5..7e6fb59f0b117 100644 --- a/compose/ui/ui-graphics/src/skikoMain/kotlin/androidx/compose/ui/graphics/SkiaBackedPath.skiko.kt +++ b/compose/ui/ui-graphics/src/skikoMain/kotlin/androidx/compose/ui/graphics/SkiaBackedPath.skiko.kt @@ -130,7 +130,10 @@ internal class SkiaBackedPath( forceMoveTo: Boolean ) { internalPath.arcTo( - rect.toSkiaRect(), + rect.left, + rect.top, + rect.right, + rect.bottom, startAngleDegrees, sweepAngleDegrees, forceMoveTo @@ -138,27 +141,83 @@ internal class SkiaBackedPath( } override fun addRect(rect: Rect) { - internalPath.addRect(rect.toSkiaRect(), PathDirection.COUNTER_CLOCKWISE) + internalPath.addRect( + rect.left, + rect.top, + rect.right, + rect.bottom, + PathDirection.COUNTER_CLOCKWISE + ) } override fun addRect(rect: Rect, direction: Path.Direction) { - internalPath.addRect(rect.toSkiaRect(), direction.toSkiaPathDirection()) + internalPath.addRect( + rect.left, + rect.top, + rect.right, + rect.bottom, + direction.toSkiaPathDirection() + ) } override fun addOval(oval: Rect) { - internalPath.addOval(oval.toSkiaRect(), PathDirection.COUNTER_CLOCKWISE) + internalPath.addOval( + oval.left, + oval.top, + oval.right, + oval.bottom, + PathDirection.COUNTER_CLOCKWISE + ) } override fun addOval(oval: Rect, direction: Path.Direction) { - internalPath.addOval(oval.toSkiaRect(), direction.toSkiaPathDirection()) + internalPath.addOval( + oval.left, + oval.top, + oval.right, + oval.bottom, + direction.toSkiaPathDirection() + ) } override fun addRoundRect(roundRect: RoundRect) { - internalPath.addRRect(roundRect.toSkiaRRect(), PathDirection.COUNTER_CLOCKWISE) + internalPath.addRRect( + roundRect.left, + roundRect.top, + roundRect.right, + roundRect.bottom, + floatArrayOf( + roundRect.topLeftCornerRadius.x, + roundRect.topLeftCornerRadius.y, + roundRect.topRightCornerRadius.x, + roundRect.topRightCornerRadius.y, + roundRect.bottomRightCornerRadius.x, + roundRect.bottomRightCornerRadius.y, + roundRect.bottomLeftCornerRadius.x, + roundRect.bottomLeftCornerRadius.y + ), + PathDirection.COUNTER_CLOCKWISE + ) } override fun addRoundRect(roundRect: RoundRect, direction: Path.Direction) { - internalPath.addRRect(roundRect.toSkiaRRect(), direction.toSkiaPathDirection()) + internalPath.addRRect( + roundRect.left, + roundRect.top, + roundRect.right, + roundRect.bottom, + floatArrayOf( + roundRect.topLeftCornerRadius.x, + roundRect.topLeftCornerRadius.y, + roundRect.topRightCornerRadius.x, + roundRect.topRightCornerRadius.y, + roundRect.bottomRightCornerRadius.x, + roundRect.bottomRightCornerRadius.y, + roundRect.bottomLeftCornerRadius.x, + roundRect.bottomLeftCornerRadius.y + ), + direction.toSkiaPathDirection() + ) } override fun addArcRad(oval: Rect, startAngleRadians: Float, sweepAngleRadians: Float) { @@ -166,7 +225,13 @@ internal class SkiaBackedPath( } override fun addArc(oval: Rect, startAngleDegrees: Float, sweepAngleDegrees: Float) { - internalPath.addArc(oval.toSkiaRect(), startAngleDegrees, sweepAngleDegrees) + internalPath.addArc( + oval.left, + oval.top, + oval.right, + oval.bottom, + startAngleDegrees, sweepAngleDegrees + ) } override fun addPath(path: Path, offset: Offset) { diff --git a/compose/ui/ui-graphics/src/skikoMain/kotlin/androidx/compose/ui/graphics/layer/SkiaGraphicsLayer.skiko.kt b/compose/ui/ui-graphics/src/skikoMain/kotlin/androidx/compose/ui/graphics/layer/SkiaGraphicsLayer.skiko.kt index 1f1492e416557..19015e3ccf412 100644 --- a/compose/ui/ui-graphics/src/skikoMain/kotlin/androidx/compose/ui/graphics/layer/SkiaGraphicsLayer.skiko.kt +++ b/compose/ui/ui-graphics/src/skikoMain/kotlin/androidx/compose/ui/graphics/layer/SkiaGraphicsLayer.skiko.kt @@ -40,8 +40,6 @@ import androidx.compose.ui.graphics.drawscope.draw import androidx.compose.ui.graphics.nativeCanvas import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toSkia -import androidx.compose.ui.graphics.toSkiaRRect -import androidx.compose.ui.graphics.toSkiaRect import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize @@ -376,10 +374,31 @@ actual class GraphicsLayer internal constructor( renderNode.setClipPath(null) } else { renderNode.clip = clip - val tmpOutline = outline - when (tmpOutline) { - is Outline.Rectangle -> renderNode.setClipRect(tmpOutline.rect.toSkiaRect(), antiAlias = true) - is Outline.Rounded -> renderNode.setClipRRect(tmpOutline.roundRect.toSkiaRRect(), antiAlias = true) + when (val tmpOutline = outline) { + is Outline.Rectangle -> renderNode.setClipRect( + tmpOutline.rect.left, + tmpOutline.rect.top, + tmpOutline.rect.right, + tmpOutline.rect.bottom, + antiAlias = true + ) + is Outline.Rounded -> renderNode.setClipRRect( + tmpOutline.roundRect.left, + tmpOutline.roundRect.top, + tmpOutline.roundRect.right, + tmpOutline.roundRect.bottom, + floatArrayOf( + tmpOutline.roundRect.topLeftCornerRadius.x, + tmpOutline.roundRect.topLeftCornerRadius.y, + tmpOutline.roundRect.topRightCornerRadius.x, + tmpOutline.roundRect.topRightCornerRadius.y, + tmpOutline.roundRect.bottomRightCornerRadius.x, + tmpOutline.roundRect.bottomRightCornerRadius.y, + tmpOutline.roundRect.bottomLeftCornerRadius.x, + tmpOutline.roundRect.bottomLeftCornerRadius.y + ), + antiAlias = true + ) is Outline.Generic -> renderNode.setClipPath(tmpOutline.path.asSkiaPath(), antiAlias = true) } } diff --git a/compose/ui/ui-graphics/src/skikoTest/kotlin/androidx/compose/ui/graphics/layer/SkiaGraphicsLayerTest.kt b/compose/ui/ui-graphics/src/skikoTest/kotlin/androidx/compose/ui/graphics/layer/SkiaGraphicsLayerTest.kt index d09a0aaf3b7be..486e3429979b2 100644 --- a/compose/ui/ui-graphics/src/skikoTest/kotlin/androidx/compose/ui/graphics/layer/SkiaGraphicsLayerTest.kt +++ b/compose/ui/ui-graphics/src/skikoTest/kotlin/androidx/compose/ui/graphics/layer/SkiaGraphicsLayerTest.kt @@ -1044,12 +1044,14 @@ class SkiaGraphicsLayerTest { } } surface.flushAndSubmit(true) - val area = - IRect.makeWH( + val imageBitmap = surface + .makeImageSnapshot( + 0, + 0, if (entireScene) TEST_WIDTH * 2 else TEST_WIDTH, if (entireScene) TEST_HEIGHT * 2 else TEST_HEIGHT - ) - val imageBitmap = surface.makeImageSnapshot(area)!!.toComposeImageBitmap() + )!! + .toComposeImageBitmap() verify?.invoke(imageBitmap.toPixelMap()) } finally { surface.close() diff --git a/compose/ui/ui-graphics/src/skikoTest/kotlin/androidx/compose/ui/graphics/shadow/SkiaShadowTestHelper.kt b/compose/ui/ui-graphics/src/skikoTest/kotlin/androidx/compose/ui/graphics/shadow/SkiaShadowTestHelper.kt index fed089885f303..ed6792d6fd740 100644 --- a/compose/ui/ui-graphics/src/skikoTest/kotlin/androidx/compose/ui/graphics/shadow/SkiaShadowTestHelper.kt +++ b/compose/ui/ui-graphics/src/skikoTest/kotlin/androidx/compose/ui/graphics/shadow/SkiaShadowTestHelper.kt @@ -53,9 +53,14 @@ fun shadowTest(block: DrawScope.() -> Unit, verify: (PixelMap) -> Unit) { block() } surface.flushAndSubmit(true) - val area = - IRect.makeWH(TEST_WIDTH, TEST_HEIGHT) - val imageBitmap = surface.makeImageSnapshot(area)!!.toComposeImageBitmap() + val imageBitmap = surface + .makeImageSnapshot( + 0, + 0, + TEST_WIDTH, + TEST_HEIGHT + )!! + .toComposeImageBitmap() verify(imageBitmap.toPixelMap()) } finally { surface.close() diff --git a/compose/ui/ui-test/src/skikoMain/kotlin/androidx/compose/ui/test/ComposeUiTest.skiko.kt b/compose/ui/ui-test/src/skikoMain/kotlin/androidx/compose/ui/test/ComposeUiTest.skiko.kt index 1c5a01bb73336..6d2570c79700b 100644 --- a/compose/ui/ui-test/src/skikoMain/kotlin/androidx/compose/ui/test/ComposeUiTest.skiko.kt +++ b/compose/ui/ui-test/src/skikoMain/kotlin/androidx/compose/ui/test/ComposeUiTest.skiko.kt @@ -459,8 +459,12 @@ open class SkikoComposeUiTest @InternalTestApi constructor( fun captureToImage(semanticsNode: SemanticsNode): ImageBitmap { val rect = semanticsNode.boundsInWindow - val iRect = IRect.makeLTRB(rect.left.toInt(), rect.top.toInt(), rect.right.toInt(), rect.bottom.toInt()) - val image = surface.makeImageSnapshot(iRect) + val image = surface.makeImageSnapshot( + rect.left.toInt(), + rect.top.toInt(), + rect.right.toInt(), + rect.bottom.toInt() + ) return image!!.toComposeImageBitmap() } diff --git a/compose/ui/ui-test/src/skikoMain/kotlin/androidx/compose/ui/test/InputDispatcher.skiko.kt b/compose/ui/ui-test/src/skikoMain/kotlin/androidx/compose/ui/test/InputDispatcher.skiko.kt index b7ccfc3d4cffa..737c95ab54823 100644 --- a/compose/ui/ui-test/src/skikoMain/kotlin/androidx/compose/ui/test/InputDispatcher.skiko.kt +++ b/compose/ui/ui-test/src/skikoMain/kotlin/androidx/compose/ui/test/InputDispatcher.skiko.kt @@ -28,6 +28,7 @@ import androidx.compose.ui.input.pointer.PointerType import androidx.compose.ui.node.RootForTest import androidx.compose.ui.platform.PlatformRootForTest import androidx.compose.ui.scene.ComposeScenePointer +import androidx.compose.ui.util.fastForEach @OptIn(InternalComposeUiApi::class) internal actual fun createInputDispatcher( @@ -300,7 +301,7 @@ internal class SkikoInputDispatcher( override fun flush() { val copy = batchedEvents.toList() batchedEvents.clear() - for (event in copy) { + copy.fastForEach { event -> advanceClockTime(event.eventTime - currentClockTime) currentClockTime = event.eventTime event.action() diff --git a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/SkiaParagraph.skiko.kt b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/SkiaParagraph.skiko.kt index f9d32bd22bcb3..6cd68684c8d6e 100644 --- a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/SkiaParagraph.skiko.kt +++ b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/SkiaParagraph.skiko.kt @@ -172,7 +172,7 @@ internal class SkiaParagraph( ) val path = Path() for (b in boxes) { - path.asSkiaPath().addRect(b.rect) + path.asSkiaPath().addRect(b.rect.left, b.rect.top, b.rect.right, b.rect.bottom) } return path } diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/ComposeContainer.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/ComposeContainer.desktop.kt index 9e55fa93badf5..6c15da2b5200b 100644 --- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/ComposeContainer.desktop.kt +++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/ComposeContainer.desktop.kt @@ -440,7 +440,7 @@ internal class ComposeContainer( */ fun layersAbove(layer: DesktopComposeSceneLayer) = sequence { var isAbove = false - for (i in layers) { + layers.fastForEach { i -> if (i == layer) { isAbove = true } else if (isAbove) { diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/ComposeSceneMediator.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/ComposeSceneMediator.desktop.kt index aa2237557e16b..3ce8a81beeffd 100644 --- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/ComposeSceneMediator.desktop.kt +++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/ComposeSceneMediator.desktop.kt @@ -68,6 +68,8 @@ import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.toOffset +import androidx.compose.ui.util.fastCoerceAtLeast +import androidx.compose.ui.util.fastRoundToInt import androidx.compose.ui.viewinterop.SwingInteropContainer import androidx.compose.ui.window.WindowExceptionHandler import androidx.compose.ui.window.asDpOffset @@ -97,7 +99,6 @@ import java.awt.im.InputMethodRequests import javax.swing.JComponent import javax.swing.SwingUtilities import kotlin.coroutines.CoroutineContext -import kotlin.math.roundToInt import org.jetbrains.skia.Canvas import org.jetbrains.skiko.ClipRectangle import org.jetbrains.skiko.ExperimentalSkikoApi @@ -673,8 +674,8 @@ internal class ComposeSceneMediator( val size = sceneBoundsInPx?.size ?: container.sizeInPx scene.size = IntSize( // container.sizeInPx can be negative - width = size.width.coerceAtLeast(0f).roundToInt(), - height = size.height.coerceAtLeast(0f).roundToInt() + width = size.width.fastCoerceAtLeast(0f).fastRoundToInt(), + height = size.height.fastCoerceAtLeast(0f).fastRoundToInt() ) } diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/SwingComposeSceneLayer.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/SwingComposeSceneLayer.desktop.kt index b12239f4cd266..48b14c4d06ade 100644 --- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/SwingComposeSceneLayer.desktop.kt +++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/SwingComposeSceneLayer.desktop.kt @@ -20,14 +20,14 @@ import androidx.compose.runtime.CompositionContext import androidx.compose.ui.awt.toAwtColor import androidx.compose.ui.awt.toAwtRectangle import androidx.compose.ui.geometry.Rect -import androidx.compose.ui.geometry.toRect import androidx.compose.ui.graphics.Color import androidx.compose.ui.scene.skia.SkiaLayerComponent import androidx.compose.ui.scene.skia.SwingSkiaLayerComponent import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.IntRect import androidx.compose.ui.unit.LayoutDirection -import androidx.compose.ui.unit.roundToIntRect import androidx.compose.ui.unit.toOffset +import androidx.compose.ui.util.fastRoundToInt import androidx.compose.ui.window.density import androidx.compose.ui.window.sizeInPx import java.awt.Dimension @@ -97,8 +97,12 @@ internal class SwingComposeSceneLayer( override var scrimColor: Color? = null init { - val boundsInPx = windowContainer.sizeInPx.toRect() - drawBounds = boundsInPx.roundToIntRect() + drawBounds = IntRect( + 0, + 0, + windowContainer.sizeInPx.width.fastRoundToInt(), + windowContainer.sizeInPx.height.fastRoundToInt() + ) mediator = ComposeSceneMediator( container = container, isWindowLevel = false, diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/WindowComposeSceneLayer.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/WindowComposeSceneLayer.desktop.kt index d8f49334d9fd2..9d98c22253b42 100644 --- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/WindowComposeSceneLayer.desktop.kt +++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/WindowComposeSceneLayer.desktop.kt @@ -41,7 +41,6 @@ import java.awt.event.ComponentAdapter import java.awt.event.ComponentEvent import javax.swing.JDialog import org.jetbrains.skia.Canvas -import org.jetbrains.skia.Rect as SkRect import org.jetbrains.skiko.DelicateSkikoApi import org.jetbrains.skiko.SkiaLayerAnalytics import org.jetbrains.skiko.transparentWindowBackgroundHack @@ -195,7 +194,7 @@ internal class WindowComposeSceneLayer( color = scrimColor blendMode = getDialogScrimBlendMode(transparent) }.asFrameworkPaint() - canvas.drawRect(SkRect.makeWH(width.toFloat(), height.toFloat()), paint) + canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint) } private fun createSkiaLayerComponent(mediator: ComposeSceneMediator): SkiaLayerComponent { diff --git a/compose/ui/ui/src/iosMain/kotlin/androidx/compose/ui/window/MetalRedrawer.ios.kt b/compose/ui/ui/src/iosMain/kotlin/androidx/compose/ui/window/MetalRedrawer.ios.kt index a44c57056c8af..73ba32b1c9612 100644 --- a/compose/ui/ui/src/iosMain/kotlin/androidx/compose/ui/window/MetalRedrawer.ios.kt +++ b/compose/ui/ui/src/iosMain/kotlin/androidx/compose/ui/window/MetalRedrawer.ios.kt @@ -334,12 +334,10 @@ internal class MetalRedrawer( // Perform timestep and record all draw commands into [Picture] val picture = trace("MetalRedrawer:draw:pictureRecording") { pictureRecorder.beginRecording( - Rect( left = 0f, top = 0f, width.toFloat(), height.toFloat() - ) ).also { canvas -> render(canvas, lastRenderTimestamp) } diff --git a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/node/RootNodeOwner.skiko.kt b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/node/RootNodeOwner.skiko.kt index d77d5dfc451f8..e2c10fcd75ef4 100644 --- a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/node/RootNodeOwner.skiko.kt +++ b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/node/RootNodeOwner.skiko.kt @@ -358,10 +358,10 @@ internal class RootNodeOwner( } private fun isInBounds(localPosition: Offset): Boolean = - size?.toIntRect()?.toRect()?.contains(localPosition) ?: true + size?.toRect()?.contains(localPosition) ?: true private fun calculateBoundsInWindow(): Rect? { - val rect = size?.toIntRect()?.toRect() ?: return null + val rect = size?.toRect() ?: return null val p0 = platformContext.convertLocalToWindowPosition(Offset(rect.left, rect.top)) val p1 = platformContext.convertLocalToWindowPosition(Offset(rect.left, rect.bottom)) val p3 = platformContext.convertLocalToWindowPosition(Offset(rect.right, rect.top)) @@ -732,7 +732,7 @@ internal class RootNodeOwner( override val semanticsOwner get() = owner.semanticsOwner override val visibleBounds: Rect get() { - val windowRect = platformContext.windowInfo.containerSize.toIntRect().toRect() + val windowRect = platformContext.windowInfo.containerSize.toRect() val ownerRect = calculateBoundsInWindow() return ownerRect?.intersect(windowRect) ?: windowRect } diff --git a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/LegacyRenderNodeLayer.skiko.kt b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/LegacyRenderNodeLayer.skiko.kt index 73c5324577c17..33ea84afef8ff 100644 --- a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/LegacyRenderNodeLayer.skiko.kt +++ b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/LegacyRenderNodeLayer.skiko.kt @@ -17,17 +17,14 @@ package androidx.compose.ui.platform import androidx.compose.runtime.InternalComposeApi -import org.jetbrains.skia.Rect as SkRect import androidx.compose.runtime.SnapshotMutationPolicy import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.FrameRateCategory import androidx.compose.ui.geometry.MutableRect import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Rect -import androidx.compose.ui.geometry.RoundRect import androidx.compose.ui.geometry.toRect import androidx.compose.ui.graphics.Canvas -import androidx.compose.ui.graphics.ClipOp import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.DefaultCameraDistance @@ -46,14 +43,13 @@ import androidx.compose.ui.graphics.asSkiaPath import androidx.compose.ui.graphics.layer.GraphicsLayer import androidx.compose.ui.graphics.prepareTransformationMatrix import androidx.compose.ui.graphics.toArgb -import androidx.compose.ui.graphics.toSkiaRRect -import androidx.compose.ui.graphics.toSkiaRect import androidx.compose.ui.graphics.nativeCanvas import androidx.compose.ui.node.OwnedLayer import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.toRect import androidx.compose.ui.unit.toSize import kotlin.math.abs import kotlin.math.max @@ -250,9 +246,12 @@ internal class LegacyRenderNodeLayer( if (picture == null) { val measureDrawBounds = !clip || shadowElevation > 0 - val bounds = size.toSize().toRect() + val bounds = size.toRect() val pictureCanvas = pictureRecorder.beginRecording( - bounds = if (measureDrawBounds) PICTURE_BOUNDS else bounds.toSkiaRect(), + left = if (measureDrawBounds) PICTURE_MIN_VALUE else bounds.left, + top = if (measureDrawBounds) PICTURE_MIN_VALUE else bounds.top, + right = if (measureDrawBounds) PICTURE_MAX_VALUE else bounds.right, + bottom = if (measureDrawBounds) PICTURE_MAX_VALUE else bounds.bottom, bbh = if (measureDrawBounds) bbhFactory else null ) performDrawLayer(pictureCanvas.asComposeCanvas(), bounds) @@ -287,8 +286,34 @@ internal class LegacyRenderNodeLayer( val isClipping = if (clip && outline != null) { canvas.save() when (outline) { - is Outline.Rectangle -> canvas.clipRect(outline.rect) - is Outline.Rounded -> canvas.clipRoundRect(outline.roundRect) + is Outline.Rectangle -> canvas.clipRect( + outline.rect.left, + outline.rect.top, + outline.rect.right, + outline.rect.bottom + ) + is Outline.Rounded -> { + val antiAlias = true + canvas.nativeCanvas.clipRRect( + outline.roundRect.left, + outline.roundRect.top, + outline.roundRect.right, + outline.roundRect.bottom, + floatArrayOf( + outline.roundRect.topLeftCornerRadius.x, + outline.roundRect.topLeftCornerRadius.y, + outline.roundRect.topRightCornerRadius.x, + outline.roundRect.topRightCornerRadius.y, + outline.roundRect.bottomRightCornerRadius.x, + outline.roundRect.bottomRightCornerRadius.y, + outline.roundRect.bottomLeftCornerRadius.x, + outline.roundRect.bottomLeftCornerRadius.y + ), + + ClipMode.INTERSECT, + antiAlias + ) + } is Outline.Generic -> canvas.clipPath(outline.path) } true @@ -328,17 +353,6 @@ internal class LegacyRenderNodeLayer( } } - private fun Canvas.clipRoundRect(rect: RoundRect, clipOp: ClipOp = ClipOp.Intersect) { - val antiAlias = true - nativeCanvas.clipRRect(rect.toSkiaRRect(), clipOp.toSkia(), antiAlias) - } - - private fun ClipOp.toSkia() = when (this) { - ClipOp.Difference -> ClipMode.DIFFERENCE - ClipOp.Intersect -> ClipMode.INTERSECT - else -> ClipMode.INTERSECT - } - override fun updateDisplayList() = Unit fun drawShadow(canvas: Canvas) = with(density) { @@ -386,10 +400,4 @@ private inline fun Float.isZero(): Boolean = abs(this) <= NON_ZERO_EPSILON // and Float.MAX_VALUE, and also lets the width and height fit into int32 (just in // case). private const val PICTURE_MIN_VALUE = -(1 shl 30).toFloat() -private const val PICTURE_MAX_VALUE = ((1 shl 30)-1).toFloat() -private val PICTURE_BOUNDS = SkRect.makeLTRB( - l = PICTURE_MIN_VALUE, - t = PICTURE_MIN_VALUE, - r = PICTURE_MAX_VALUE, - b = PICTURE_MAX_VALUE -) +private const val PICTURE_MAX_VALUE = ((1 shl 30)-1).toFloat() \ No newline at end of file diff --git a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/semantics/SemanticsRegion.skiko.kt b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/semantics/SemanticsRegion.skiko.kt index c6a72042da2c9..219fa01adc1bb 100644 --- a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/semantics/SemanticsRegion.skiko.kt +++ b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/semantics/SemanticsRegion.skiko.kt @@ -24,7 +24,7 @@ private class SemanticRegionImpl : SemanticsRegion { val region = Region() override fun set(rect: IntRect) { - region.setRect(IRect.makeLTRB(rect.left, rect.top, rect.right, rect.bottom)) + region.setRect(rect.left, rect.top, rect.right, rect.bottom) } override val bounds: IntRect @@ -40,7 +40,7 @@ private class SemanticRegionImpl : SemanticsRegion { } override fun difference(rect: IntRect): Boolean { - return region.op(IRect.makeLTRB(rect.left, rect.top, rect.right, rect.bottom), Region.Op.DIFFERENCE) + return region.op(rect.left, rect.top, rect.right, rect.bottom, Region.Op.DIFFERENCE) } } diff --git a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/skiko/RecordDrawRectRenderDecorator.skiko.kt b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/skiko/RecordDrawRectRenderDecorator.skiko.kt index e991593993c2a..fb693f121dee1 100644 --- a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/skiko/RecordDrawRectRenderDecorator.skiko.kt +++ b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/skiko/RecordDrawRectRenderDecorator.skiko.kt @@ -16,13 +16,13 @@ package androidx.compose.ui.skiko -import org.jetbrains.skia.Rect as SkRect import androidx.compose.ui.geometry.Rect import androidx.compose.ui.graphics.toComposeRect import org.jetbrains.skia.Canvas import org.jetbrains.skia.Picture import org.jetbrains.skia.PictureRecorder import org.jetbrains.skia.RTreeFactory +import org.jetbrains.skia.Rect as SkRect import org.jetbrains.skiko.SkikoRenderDelegate internal class RecordDrawRectRenderDecorator( @@ -54,7 +54,13 @@ internal class RecordDrawRectRenderDecorator( private inline fun Canvas.recordCullRect( block: (Canvas) -> Unit ): SkRect? { - val pictureCanvas = pictureRecorder.beginRecording(SkRect.Unconstrained, bbhFactory) + val pictureCanvas = pictureRecorder.beginRecording( + Float.MIN_VALUE, + Float.MIN_VALUE, + Float.MAX_VALUE, + Float.MAX_VALUE, + bbhFactory + ) pictureCanvas.translate(MeasureOffset, MeasureOffset) block(pictureCanvas) val picture = pictureRecorder.finishRecordingAsPicture() diff --git a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/unit/Density.skiko.kt b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/unit/Density.skiko.kt index 150c7b33db91b..611ae04a7c836 100644 --- a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/unit/Density.skiko.kt +++ b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/unit/Density.skiko.kt @@ -79,3 +79,11 @@ internal inline fun Size.toDpSize(density: Density): DpSize = with(density) { internal inline fun DpSize.toSize(density: Density): Size = with(density) { toSize() } + +/** + * Converts a [IntSize] to a [Rect]. + */ +@Stable +internal inline fun IntSize.toRect(): Rect = + Rect(0f, 0f, width.toFloat(), height.toFloat()) +