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();