Adjust crop to account for child scaling
The computed crop is in view-relative domain, but we need
it to be in surface-relative domain since that's what
surfaceflinger is speaking. So adjust the crop by the scale
from surfaceWidth/Height to the RenderNode's width/height
Bug: 298621623
Flag: com.android.graphics.hwui.flags.clip_surfaceviews
Test: HwAccelerationTest demo & atest CtsUiRenderingTestCases
Change-Id: I9d5908c2ca2c6b6331c8f35f658783ab3b2fe6f1
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 94f415b..10fba5e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -3455,15 +3455,15 @@
* @return this This transaction for chaining
* @hide
*/
- public @NonNull Transaction setCrop(@NonNull SurfaceControl sc, float top, float left,
- float bottom, float right) {
+ public @NonNull Transaction setCrop(@NonNull SurfaceControl sc, float left, float top,
+ float right, float bottom) {
checkPreconditions(sc);
if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
"setCrop", this, sc, "crop={" + top + ", " + left + ", " +
bottom + ", " + right + "}");
}
- nativeSetCrop(mNativeObject, sc.mNativeObject, top, left, bottom, right);
+ nativeSetCrop(mNativeObject, sc.mNativeObject, left, top, right, bottom);
return this;
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 9cad3e5..4df7649 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -40,6 +40,7 @@
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.RenderNode;
import android.hardware.input.InputManager;
@@ -1666,7 +1667,7 @@
}
private final Rect mRTLastReportedPosition = new Rect();
- private final Rect mRTLastSetCrop = new Rect();
+ private final RectF mRTLastSetCrop = new RectF();
private class SurfaceViewPositionUpdateListener implements RenderNode.PositionUpdateListener {
private final int mRtSurfaceWidth;
@@ -1711,16 +1712,18 @@
@Override
public void positionChanged(long frameNumber, int left, int top, int right, int bottom,
- int clipLeft, int clipTop, int clipRight, int clipBottom) {
+ int clipLeft, int clipTop, int clipRight, int clipBottom,
+ int nodeWidth, int nodeHeight) {
try {
if (DEBUG_POSITION) {
Log.d(TAG, String.format(
"%d updateSurfacePosition RenderWorker, frameNr = %d, "
+ "position = [%d, %d, %d, %d] clip = [%d, %d, %d, %d] "
- + "surfaceSize = %dx%d",
+ + "surfaceSize = %dx%d renderNodeSize = %d%d",
System.identityHashCode(SurfaceView.this), frameNumber,
left, top, right, bottom, clipLeft, clipTop, clipRight, clipBottom,
- mRtSurfaceWidth, mRtSurfaceHeight));
+ mRtSurfaceWidth, mRtSurfaceHeight,
+ nodeWidth, nodeHeight));
}
synchronized (mSurfaceControlLock) {
if (mSurfaceControl == null) return;
@@ -1735,14 +1738,29 @@
mRTLastReportedPosition.top /*positionTop*/,
postScaleX, postScaleY);
- mRTLastSetCrop.set(clipLeft, clipTop, clipRight, clipBottom);
+ // The computed crop is in view-relative dimensions, however we need it to be
+ // in buffer-relative dimensions. So scale the crop by the ratio between
+ // the view's unscaled width/height (nodeWidth/Height), and the surface's
+ // width/height
+ // That is, if the Surface has a fixed size of 50x50, the SurfaceView is laid
+ // out to a size of 100x100, and the SurfaceView is ultimately scaled to
+ // 1000x1000, then we need to scale the crop by just the 2x from surface
+ // domain to SV domain.
+ final float surfaceToNodeScaleX = (float) mRtSurfaceWidth / (float) nodeWidth;
+ final float surfaceToNodeScaleY = (float) mRtSurfaceHeight / (float) nodeHeight;
+ mRTLastSetCrop.set(clipLeft * surfaceToNodeScaleX,
+ clipTop * surfaceToNodeScaleY,
+ clipRight * surfaceToNodeScaleX,
+ clipBottom * surfaceToNodeScaleY);
+
if (DEBUG_POSITION) {
- Log.d(TAG, String.format("Setting layer crop = [%d, %d, %d, %d] "
+ Log.d(TAG, String.format("Setting layer crop = [%f, %f, %f, %f] "
+ "from scale %f, %f", mRTLastSetCrop.left,
mRTLastSetCrop.top, mRTLastSetCrop.right, mRTLastSetCrop.bottom,
- postScaleX, postScaleY));
+ surfaceToNodeScaleX, surfaceToNodeScaleY));
}
- mPositionChangedTransaction.setCrop(mSurfaceControl, mRTLastSetCrop);
+ mPositionChangedTransaction.setCrop(mSurfaceControl, mRTLastSetCrop.left,
+ mRTLastSetCrop.top, mRTLastSetCrop.right, mRTLastSetCrop.bottom);
if (mRTLastSetCrop.isEmpty()) {
mPositionChangedTransaction.hide(mSurfaceControl);
} else {
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 211f74a..03a8b30 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -279,7 +279,8 @@
* @hide
*/
default void positionChanged(long frameNumber, int left, int top, int right, int bottom,
- int clipLeft, int clipTop, int clipRight, int clipBottom) {
+ int clipLeft, int clipTop, int clipRight, int clipBottom,
+ int nodeWidth, int nodeHeight) {
positionChanged(frameNumber, left, top, right, bottom);
}
@@ -304,11 +305,12 @@
* @hide */
static boolean callPositionChanged2(WeakReference<PositionUpdateListener> weakListener,
long frameNumber, int left, int top, int right, int bottom,
- int clipLeft, int clipTop, int clipRight, int clipBottom) {
+ int clipLeft, int clipTop, int clipRight, int clipBottom,
+ int nodeWidth, int nodeHeight) {
final PositionUpdateListener listener = weakListener.get();
if (listener != null) {
listener.positionChanged(frameNumber, left, top, right, bottom, clipLeft,
- clipTop, clipRight, clipBottom);
+ clipTop, clipRight, clipBottom, nodeWidth, nodeHeight);
return true;
} else {
return false;
@@ -401,10 +403,11 @@
@Override
public void positionChanged(long frameNumber, int left, int top, int right, int bottom,
- int clipLeft, int clipTop, int clipRight, int clipBottom) {
+ int clipLeft, int clipTop, int clipRight, int clipBottom,
+ int nodeWidth, int nodeHeight) {
for (PositionUpdateListener pul : mListeners) {
pul.positionChanged(frameNumber, left, top, right, bottom, clipLeft, clipTop,
- clipRight, clipBottom);
+ clipRight, clipBottom, nodeWidth, nodeHeight);
}
}
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index 6e03bbd..d9dc8eb 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -593,9 +593,9 @@
Matrix4 transform;
SkIRect clipBounds;
+ uirenderer::Rect initialClipBounds;
+ const auto clipFlags = props.getClippingFlags();
if (enableClip) {
- uirenderer::Rect initialClipBounds;
- const auto clipFlags = props.getClippingFlags();
if (clipFlags) {
props.getClippingRectForFlags(clipFlags, &initialClipBounds);
} else {
@@ -659,8 +659,8 @@
static_cast<jint>(bounds.left), static_cast<jint>(bounds.top),
static_cast<jint>(bounds.right), static_cast<jint>(bounds.bottom),
static_cast<jint>(clipBounds.fLeft), static_cast<jint>(clipBounds.fTop),
- static_cast<jint>(clipBounds.fRight),
- static_cast<jint>(clipBounds.fBottom));
+ static_cast<jint>(clipBounds.fRight), static_cast<jint>(clipBounds.fBottom),
+ static_cast<jint>(props.getWidth()), static_cast<jint>(props.getHeight()));
}
if (!keepListening) {
env->DeleteGlobalRef(mListener);
@@ -891,7 +891,7 @@
gPositionListener.callPositionChanged = GetStaticMethodIDOrDie(
env, clazz, "callPositionChanged", "(Ljava/lang/ref/WeakReference;JIIII)Z");
gPositionListener.callPositionChanged2 = GetStaticMethodIDOrDie(
- env, clazz, "callPositionChanged2", "(Ljava/lang/ref/WeakReference;JIIIIIIII)Z");
+ env, clazz, "callPositionChanged2", "(Ljava/lang/ref/WeakReference;JIIIIIIIIII)Z");
gPositionListener.callApplyStretch = GetStaticMethodIDOrDie(
env, clazz, "callApplyStretch", "(Ljava/lang/ref/WeakReference;JFFFFFFFFFF)Z");
gPositionListener.callPositionLost = GetStaticMethodIDOrDie(
diff --git a/tests/graphics/HwAccelerationTest/AndroidManifest.xml b/tests/graphics/HwAccelerationTest/AndroidManifest.xml
index db3a992..05b2f4c 100644
--- a/tests/graphics/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/graphics/HwAccelerationTest/AndroidManifest.xml
@@ -24,7 +24,7 @@
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
- <uses-sdk android:minSdkVersion="21"/>
+ <uses-sdk android:minSdkVersion="21" />
<application android:label="HwUi"
android:theme="@android:style/Theme.Material.Light">
@@ -409,6 +409,24 @@
</intent-filter>
</activity>
+ <activity android:name="ScrollingZAboveSurfaceView"
+ android:label="SurfaceView/Z-Above scrolling"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="ScrollingZAboveScaledSurfaceView"
+ android:label="SurfaceView/Z-Above scrolling, scaled surface"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
<activity android:name="StretchySurfaceViewActivity"
android:label="SurfaceView/Stretchy Movement"
android:exported="true">
diff --git a/tests/graphics/HwAccelerationTest/res/layout/scrolling_zabove_surfaceview.xml b/tests/graphics/HwAccelerationTest/res/layout/scrolling_zabove_surfaceview.xml
new file mode 100644
index 0000000..31e5774
--- /dev/null
+++ b/tests/graphics/HwAccelerationTest/res/layout/scrolling_zabove_surfaceview.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".MainActivity">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Above the ScrollView"
+ android:textColor="#FFFFFFFF"
+ android:background="#FF444444"
+ android:padding="32dp" />
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Scrolling Header"
+ android:background="#FFCCCCCC"
+ android:padding="32dp" />
+
+ <SurfaceView
+ android:layout_width="match_parent"
+ android:layout_height="500dp"
+ android:id="@+id/surfaceview" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Scrolling Item"
+ android:background="#FFCCCCCC"
+ android:padding="32dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Scrolling Item"
+ android:background="#FFCCCCCC"
+ android:padding="32dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Scrolling Item"
+ android:background="#FFCCCCCC"
+ android:padding="32dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Scrolling Item"
+ android:background="#FFCCCCCC"
+ android:padding="32dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Scrolling Item"
+ android:background="#FFCCCCCC"
+ android:padding="32dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Scrolling Item"
+ android:background="#FFCCCCCC"
+ android:padding="32dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Scrolling Item"
+ android:background="#FFCCCCCC"
+ android:padding="32dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Scrolling Item"
+ android:background="#FFCCCCCC"
+ android:padding="32dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Scrolling Item"
+ android:background="#FFCCCCCC"
+ android:padding="32dp" />
+
+ </LinearLayout>
+
+ </ScrollView>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Below the ScrollView"
+ android:textColor="#FFFFFFFF"
+ android:background="#FF444444"
+ android:padding="32dp" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ScrollingZAboveScaledSurfaceView.kt b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ScrollingZAboveScaledSurfaceView.kt
new file mode 100644
index 0000000..59ae885
--- /dev/null
+++ b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ScrollingZAboveScaledSurfaceView.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui
+
+import android.app.Activity
+import android.graphics.Color
+import android.graphics.Paint
+import android.os.Bundle
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+
+class ScrollingZAboveScaledSurfaceView : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.scrolling_zabove_surfaceview)
+
+ findViewById<SurfaceView>(R.id.surfaceview).apply {
+ setZOrderOnTop(true)
+ holder.setFixedSize(1000, 2000)
+ holder.addCallback(object : SurfaceHolder.Callback {
+ override fun surfaceCreated(p0: SurfaceHolder) {
+
+ }
+
+ override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
+ holder.unlockCanvasAndPost(holder.lockCanvas().apply {
+ drawColor(Color.BLUE)
+ val paint = Paint()
+ paint.textSize = 16 * resources.displayMetrics.density
+ paint.textAlign = Paint.Align.CENTER
+ paint.color = Color.WHITE
+ drawText("I'm a setZOrderOnTop(true) SurfaceView!",
+ (width / 2).toFloat(), (height / 2).toFloat(), paint)
+ })
+ }
+
+ override fun surfaceDestroyed(p0: SurfaceHolder) {
+
+ }
+
+ })
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ScrollingZAboveSurfaceView.kt b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ScrollingZAboveSurfaceView.kt
new file mode 100644
index 0000000..ccb71ec
--- /dev/null
+++ b/tests/graphics/HwAccelerationTest/src/com/android/test/hwui/ScrollingZAboveSurfaceView.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui
+
+import android.app.Activity
+import android.graphics.Color
+import android.graphics.Paint
+import android.os.Bundle
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+
+class ScrollingZAboveSurfaceView : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.scrolling_zabove_surfaceview)
+
+ findViewById<SurfaceView>(R.id.surfaceview).apply {
+ setZOrderOnTop(true)
+ holder.addCallback(object : SurfaceHolder.Callback {
+ override fun surfaceCreated(p0: SurfaceHolder) {
+
+ }
+
+ override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
+ holder.unlockCanvasAndPost(holder.lockCanvas().apply {
+ drawColor(Color.BLUE)
+ val paint = Paint()
+ paint.textSize = 16 * resources.displayMetrics.density
+ paint.textAlign = Paint.Align.CENTER
+ paint.color = Color.WHITE
+ drawText("I'm a setZOrderOnTop(true) SurfaceView!",
+ (width / 2).toFloat(), (height / 2).toFloat(), paint)
+ })
+ }
+
+ override fun surfaceDestroyed(p0: SurfaceHolder) {
+
+ }
+
+ })
+ }
+ }
+}
\ No newline at end of file