Merge "SurfaceFlinger: Handle multiple rounded corner settings" into sc-v2-dev
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7cfc321..b989b51 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1915,27 +1915,48 @@
}
Layer::RoundedCornerState Layer::getRoundedCornerState() const {
- const auto& p = mDrawingParent.promote();
- if (p != nullptr) {
- RoundedCornerState parentState = p->getRoundedCornerState();
- if (parentState.radius > 0) {
+ // Get parent settings
+ RoundedCornerState parentSettings;
+ const auto& parent = mDrawingParent.promote();
+ if (parent != nullptr) {
+ parentSettings = parent->getRoundedCornerState();
+ if (parentSettings.radius > 0) {
ui::Transform t = getActiveTransform(getDrawingState());
t = t.inverse();
- parentState.cropRect = t.transform(parentState.cropRect);
+ parentSettings.cropRect = t.transform(parentSettings.cropRect);
// The rounded corners shader only accepts 1 corner radius for performance reasons,
// but a transform matrix can define horizontal and vertical scales.
// Let's take the average between both of them and pass into the shader, practically we
// never do this type of transformation on windows anyway.
auto scaleX = sqrtf(t[0][0] * t[0][0] + t[0][1] * t[0][1]);
auto scaleY = sqrtf(t[1][0] * t[1][0] + t[1][1] * t[1][1]);
- parentState.radius *= (scaleX + scaleY) / 2.0f;
- return parentState;
+ parentSettings.radius *= (scaleX + scaleY) / 2.0f;
}
}
+
+ // Get layer settings
+ Rect layerCropRect = getCroppedBufferSize(getDrawingState());
const float radius = getDrawingState().cornerRadius;
- return radius > 0 && getCroppedBufferSize(getDrawingState()).isValid()
- ? RoundedCornerState(getCroppedBufferSize(getDrawingState()).toFloatRect(), radius)
- : RoundedCornerState();
+ RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius);
+
+ if (layerSettings.radius > 0 && parentSettings.radius > 0) {
+ // If the parent and the layer have rounded corner settings, use the parent settings if the
+ // parent crop is entirely inside the layer crop.
+ // This has limitations and cause rendering artifacts. See b/200300845 for correct fix.
+ if (parentSettings.cropRect.left > layerCropRect.left &&
+ parentSettings.cropRect.top > layerCropRect.top &&
+ parentSettings.cropRect.right < layerCropRect.right &&
+ parentSettings.cropRect.bottom < layerCropRect.bottom) {
+ return parentSettings;
+ } else {
+ return layerSettings;
+ }
+ } else if (layerSettings.radius > 0) {
+ return layerSettings;
+ } else if (parentSettings.radius > 0) {
+ return parentSettings;
+ }
+ return {};
}
void Layer::prepareShadowClientComposition(LayerFE::LayerSettings& caster,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 470103c..94fb7d7 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -606,10 +606,8 @@
virtual bool getTransformToDisplayInverse() const { return false; }
// Returns how rounded corners should be drawn for this layer.
- // This will traverse the hierarchy until it reaches its root, finding topmost rounded
- // corner definition and converting it into current layer's coordinates.
- // As of now, only 1 corner radius per display list is supported. Subsequent ones will be
- // ignored.
+ // A layer can override its parent's rounded corner settings if the parent's rounded
+ // corner crop does not intersect with its own rounded corner crop.
virtual RoundedCornerState getRoundedCornerState() const;
bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; }
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index 43d957c..ab1d589 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -465,6 +465,95 @@
}
}
+TEST_P(LayerTypeAndRenderTypeTransactionTest, ChildCornerRadiusTakesPrecedence) {
+ sp<SurfaceControl> parent;
+ sp<SurfaceControl> child;
+ const uint32_t size = 64;
+ const uint32_t parentSize = size * 3;
+ const uint32_t testLength = 4;
+ const float cornerRadius = 20.0f;
+ ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize));
+ ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));
+
+ Transaction()
+ .setCornerRadius(parent, cornerRadius)
+ .setCornerRadius(child, cornerRadius)
+ .reparent(child, parent)
+ .setPosition(child, size, size)
+ .apply();
+
+ {
+ const uint32_t top = size - 1;
+ const uint32_t left = size - 1;
+ const uint32_t bottom = size * 2 - 1;
+ const uint32_t right = size * 2 - 1;
+ auto shot = getScreenCapture();
+ // Edges are transparent
+ // TL
+ shot->expectColor(Rect(left, top, testLength, testLength), Color::RED);
+ // TR
+ shot->expectColor(Rect(right - testLength, top, right, testLength), Color::RED);
+ // BL
+ shot->expectColor(Rect(left, bottom - testLength, testLength, bottom - testLength),
+ Color::RED);
+ // BR
+ shot->expectColor(Rect(right - testLength, bottom - testLength, right, bottom), Color::RED);
+ // Solid center
+ shot->expectColor(Rect(parentSize / 2 - testLength / 2, parentSize / 2 - testLength / 2,
+ parentSize / 2 + testLength / 2, parentSize / 2 + testLength / 2),
+ Color::GREEN);
+ }
+}
+
+// Test if ParentCornerRadiusTakesPrecedence if the parent corner radius crop is fully contained by
+// the child corner radius crop.
+TEST_P(LayerTypeAndRenderTypeTransactionTest, ParentCornerRadiusTakesPrecedence) {
+ sp<SurfaceControl> parent;
+ sp<SurfaceControl> child;
+ const uint32_t size = 64;
+ const uint32_t parentSize = size * 3;
+ const Rect parentCrop(size + 1, size + 1, size * 2 - 1, size * 2 - 1);
+ const uint32_t testLength = 4;
+ const float cornerRadius = 20.0f;
+ ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize));
+ ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));
+
+ Transaction()
+ .setCornerRadius(parent, cornerRadius)
+ .setCrop(parent, parentCrop)
+ .setCornerRadius(child, cornerRadius)
+ .reparent(child, parent)
+ .setPosition(child, size, size)
+ .apply();
+
+ {
+ const uint32_t top = size - 1;
+ const uint32_t left = size - 1;
+ const uint32_t bottom = size * 2 - 1;
+ const uint32_t right = size * 2 - 1;
+ auto shot = getScreenCapture();
+ // Edges are transparent
+ // TL
+ shot->expectColor(Rect(left, top, testLength, testLength), Color::BLACK);
+ // TR
+ shot->expectColor(Rect(right - testLength, top, right, testLength), Color::BLACK);
+ // BL
+ shot->expectColor(Rect(left, bottom - testLength, testLength, bottom - testLength),
+ Color::BLACK);
+ // BR
+ shot->expectColor(Rect(right - testLength, bottom - testLength, right, bottom),
+ Color::BLACK);
+ // Solid center
+ shot->expectColor(Rect(parentSize / 2 - testLength / 2, parentSize / 2 - testLength / 2,
+ parentSize / 2 + testLength / 2, parentSize / 2 + testLength / 2),
+ Color::GREEN);
+ }
+}
+
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) {
if (!deviceSupportsBlurs()) GTEST_SKIP();
if (!deviceUsesSkiaRenderEngine()) GTEST_SKIP();