summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/surfaceflinger/Layer.cpp56
-rw-r--r--services/surfaceflinger/Layer.h8
-rw-r--r--services/surfaceflinger/tests/Transaction_test.cpp153
3 files changed, 190 insertions, 27 deletions
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 16e69b9b26..512a0b4f10 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -278,14 +278,12 @@ FloatRect Layer::getBounds(const Region& activeTransparentRegion) const {
return reduce(mBounds, activeTransparentRegion);
}
-ui::Transform Layer::getTransformWithScale() const {
+ui::Transform Layer::getBufferScaleTransform() const {
// If the layer is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g.
// it isFixedSize) then there may be additional scaling not accounted
- // for in the transform. We need to mirror this scaling to child surfaces
- // or we will break the contract where WM can treat child surfaces as
- // pixels in the parent surface.
+ // for in the layer transform.
if (!isFixedSize() || !mActiveBuffer) {
- return mEffectiveTransform;
+ return {};
}
// If the layer is a buffer state layer, the active width and height
@@ -293,24 +291,40 @@ ui::Transform Layer::getTransformWithScale() const {
const uint32_t activeWidth = getActiveWidth(getDrawingState());
const uint32_t activeHeight = getActiveHeight(getDrawingState());
if (activeWidth >= UINT32_MAX && activeHeight >= UINT32_MAX) {
- return mEffectiveTransform;
+ return {};
}
- int bufferWidth;
- int bufferHeight;
- if ((mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
- bufferWidth = mActiveBuffer->getWidth();
- bufferHeight = mActiveBuffer->getHeight();
- } else {
- bufferHeight = mActiveBuffer->getWidth();
- bufferWidth = mActiveBuffer->getHeight();
+ int bufferWidth = mActiveBuffer->getWidth();
+ int bufferHeight = mActiveBuffer->getHeight();
+
+ if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
}
+
float sx = activeWidth / static_cast<float>(bufferWidth);
float sy = activeHeight / static_cast<float>(bufferHeight);
ui::Transform extraParentScaling;
extraParentScaling.set(sx, 0, 0, sy);
- return mEffectiveTransform * extraParentScaling;
+ return extraParentScaling;
+}
+
+ui::Transform Layer::getTransformWithScale(const ui::Transform& bufferScaleTransform) const {
+ // We need to mirror this scaling to child surfaces or we will break the contract where WM can
+ // treat child surfaces as pixels in the parent surface.
+ if (!isFixedSize() || !mActiveBuffer) {
+ return mEffectiveTransform;
+ }
+ return mEffectiveTransform * bufferScaleTransform;
+}
+
+FloatRect Layer::getBoundsPreScaling(const ui::Transform& bufferScaleTransform) const {
+ // We need the pre scaled layer bounds when computing child bounds to make sure the child is
+ // cropped to its parent layer after any buffer transform scaling is applied.
+ if (!isFixedSize() || !mActiveBuffer) {
+ return mBounds;
+ }
+ return bufferScaleTransform.inverse().transform(mBounds);
}
void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform) {
@@ -322,7 +336,7 @@ void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform)
// Transform parent bounds to layer space
parentBounds = getActiveTransform(s).inverse().transform(parentBounds);
- // Calculate display frame
+ // Calculate source bounds
mSourceBounds = computeSourceBounds(parentBounds);
// Calculate bounds by croping diplay frame with layer crop and parent bounds
@@ -335,8 +349,12 @@ void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform)
mBounds = bounds;
mScreenBounds = mEffectiveTransform.transform(mBounds);
+
+ // Add any buffer scaling to the layer's children.
+ ui::Transform bufferScaleTransform = getBufferScaleTransform();
for (const sp<Layer>& child : mDrawingChildren) {
- child->computeBounds(mBounds, getTransformWithScale());
+ child->computeBounds(getBoundsPreScaling(bufferScaleTransform),
+ getTransformWithScale(bufferScaleTransform));
}
}
@@ -1436,7 +1454,9 @@ bool Layer::reparentChildren(const sp<IBinder>& newParentHandle) {
void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
for (const sp<Layer>& child : mDrawingChildren) {
child->mDrawingParent = newParent;
- child->computeBounds(newParent->mBounds, newParent->getTransformWithScale());
+ child->computeBounds(newParent->mBounds,
+ newParent->getTransformWithScale(
+ newParent->getBufferScaleTransform()));
}
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index aba3ff2ff3..89063da251 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -361,9 +361,15 @@ public:
// Compute bounds for the layer and cache the results.
void computeBounds(FloatRect parentBounds, ui::Transform parentTransform);
+ // Returns the buffer scale transform if a scaling mode is set.
+ ui::Transform getBufferScaleTransform() const;
+
// Get effective layer transform, taking into account all its parent transform with any
// scaling if the parent scaling more is not NATIVE_WINDOW_SCALING_MODE_FREEZE.
- ui::Transform getTransformWithScale() const;
+ ui::Transform getTransformWithScale(const ui::Transform& bufferScaleTransform) const;
+
+ // Returns the bounds of the layer without any buffer scaling.
+ FloatRect getBoundsPreScaling(const ui::Transform& bufferScaleTransform) const;
int32_t getSequence() const { return sequence; }
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index bc5642ecd3..d62afa5ec2 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -4307,7 +4307,7 @@ class ChildLayerTest : public LayerUpdateTest {
protected:
void SetUp() override {
LayerUpdateTest::SetUp();
- mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0,
+ mChild = createSurface(mClient, "Child surface", 10, 15, PIXEL_FORMAT_RGBA_8888, 0,
mFGSurfaceControl.get());
fillSurfaceRGBA8(mChild, 200, 200, 200);
@@ -4413,6 +4413,32 @@ TEST_F(ChildLayerTest, ChildLayerScaling) {
}
}
+// A child with a scale transform should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildLayerScalingCroppedByParent) {
+ asTransaction([&](Transaction& t) {
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setPosition(mChild, 0, 0);
+ });
+
+ // Find the boundary between the parent and child.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 9);
+ mCapture->expectFGColor(10, 10);
+ }
+
+ asTransaction([&](Transaction& t) { t.setMatrix(mChild, 10.0, 0, 0, 10.0); });
+
+ // The child should fill its parent bounds and be cropped by it.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+}
+
TEST_F(ChildLayerTest, ChildLayerAlpha) {
fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254);
fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0);
@@ -4649,8 +4675,8 @@ TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
mCapture = screenshot();
// We've positioned the child in the top left.
mCapture->expectChildColor(0, 0);
- // But it's only 10x10.
- mCapture->expectFGColor(10, 10);
+ // But it's only 10x15.
+ mCapture->expectFGColor(10, 15);
}
asTransaction([&](Transaction& t) {
@@ -4664,9 +4690,9 @@ TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
// We've positioned the child in the top left.
mCapture->expectChildColor(0, 0);
mCapture->expectChildColor(10, 10);
- mCapture->expectChildColor(19, 19);
- // And now it should be scaled all the way to 20x20
- mCapture->expectFGColor(20, 20);
+ mCapture->expectChildColor(19, 29);
+ // And now it should be scaled all the way to 20x30
+ mCapture->expectFGColor(20, 30);
}
}
@@ -4682,8 +4708,9 @@ TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
mCapture = screenshot();
// We've positioned the child in the top left.
mCapture->expectChildColor(0, 0);
- // But it's only 10x10.
- mCapture->expectFGColor(10, 10);
+ mCapture->expectChildColor(9, 14);
+ // But it's only 10x15.
+ mCapture->expectFGColor(10, 15);
}
// We set things up as in b/37673612 so that there is a mismatch between the buffer size and
// the WM specified state size.
@@ -4704,6 +4731,115 @@ TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
}
}
+// A child with a buffer transform from its parents should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setSize(mChild, 100, 100);
+ });
+ fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ {
+ mCapture = screenshot();
+
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ // Apply a 90 transform on the buffer.
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 64, 128);
+ fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+
+ // The child should be cropped by the new parent bounds.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(99, 63);
+ mCapture->expectFGColor(100, 63);
+ mCapture->expectBGColor(128, 64);
+ }
+}
+
+// A child with a scale transform from its parents should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setSize(mChild, 200, 200);
+ });
+ fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ {
+ mCapture = screenshot();
+
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // Set a scaling by 2.
+ t.setSize(mFGSurfaceControl, 128, 128);
+ });
+
+ // Child should inherit its parents scale but should be cropped by its parent bounds.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(127, 127);
+ mCapture->expectBGColor(128, 128);
+ }
+}
+
+// Regression test for b/127368943
+// Child should ignore the buffer transform but apply parent scale transform.
+TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 14);
+ mCapture->expectFGColor(10, 15);
+ }
+
+ // Change the size of the foreground to 128 * 64 so we can test rotation as well.
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ t.setSize(mFGSurfaceControl, 128, 64);
+ });
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ // Apply a 90 transform on the buffer and submit a buffer half the expected size so that we
+ // have an effective scale of 2.0 applied to the buffer along with a rotation transform.
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 32, 64);
+ fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+
+ // The child should ignore the buffer transform but apply the 2.0 scale from parent.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(19, 29);
+ mCapture->expectFGColor(20, 30);
+ }
+}
+
TEST_F(ChildLayerTest, Bug36858924) {
// Destroy the child layer
mChild.clear();
@@ -4857,6 +4993,7 @@ TEST_F(ChildLayerTest, ChildLayerRelativeLayer) {
mCapture->checkPixel(10, 10, 255, 255, 255);
}
}
+
class BoundlessLayerTest : public LayerUpdateTest {
protected:
std::unique_ptr<ScreenCapture> mCapture;