summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/Layer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/Layer.cpp')
-rw-r--r--services/surfaceflinger/Layer.cpp137
1 files changed, 58 insertions, 79 deletions
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8c77a8b648..fc73181c87 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2166,9 +2166,9 @@ Rect Layer::getInputBounds() const {
return getCroppedBufferSize(getDrawingState());
}
-void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTransform) {
- Rect layerBounds = getInputBounds();
- if (!layerBounds.isValid()) {
+void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
+ Rect tmpBounds = getInputBounds();
+ if (!tmpBounds.isValid()) {
info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE;
info.focusable = false;
info.touchableRegion.clear();
@@ -2176,82 +2176,61 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTra
// replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated
// correctly to determine the coordinate space for input events. Use an empty rect so that
// the layer will receive input in its own layer space.
- layerBounds = Rect::EMPTY_RECT;
- }
-
- const ui::Transform layerTransform = getInputTransform();
- // Transform that takes window coordinates to non-rotated display coordinates
- ui::Transform t = displayTransform * layerTransform;
- int32_t xSurfaceInset = info.surfaceInset;
- int32_t ySurfaceInset = info.surfaceInset;
- // Bring screenBounds into non-unrotated space
- Rect screenBounds = displayTransform.transform(Rect{mScreenBounds});
-
- const float xScale = t.getScaleX();
- const float yScale = t.getScaleY();
- if (xScale != 1.0f || yScale != 1.0f) {
- xSurfaceInset = std::round(xSurfaceInset * xScale);
- ySurfaceInset = std::round(ySurfaceInset * yScale);
- }
-
- // Transform the layer bounds from layer coordinate space to display coordinate space.
- Rect transformedLayerBounds = t.transform(layerBounds);
-
- // clamp inset to layer bounds
- xSurfaceInset = (xSurfaceInset >= 0)
- ? std::min(xSurfaceInset, transformedLayerBounds.getWidth() / 2)
- : 0;
- ySurfaceInset = (ySurfaceInset >= 0)
- ? std::min(ySurfaceInset, transformedLayerBounds.getHeight() / 2)
- : 0;
-
- // inset while protecting from overflow TODO(b/161235021): What is going wrong
- // in the overflow scenario?
- {
- int32_t tmp;
- if (!__builtin_add_overflow(transformedLayerBounds.left, xSurfaceInset, &tmp))
- transformedLayerBounds.left = tmp;
- if (!__builtin_sub_overflow(transformedLayerBounds.right, xSurfaceInset, &tmp))
- transformedLayerBounds.right = tmp;
- if (!__builtin_add_overflow(transformedLayerBounds.top, ySurfaceInset, &tmp))
- transformedLayerBounds.top = tmp;
- if (!__builtin_sub_overflow(transformedLayerBounds.bottom, ySurfaceInset, &tmp))
- transformedLayerBounds.bottom = tmp;
- }
-
- // Compute the correct transform to send to input. This will allow it to transform the
- // input coordinates from display space into window space. Therefore, it needs to use the
- // final layer frame to create the inverse transform. Since surface insets are added later,
- // along with the overflow, the best way to ensure we get the correct transform is to use
- // the final frame calculated.
- // 1. Take the original transform set on the window and get the inverse transform. This is
- // used to get the final bounds in display space (ignorning the transform). Apply the
- // inverse transform on the layerBounds to get the untransformed frame (in layer space)
- // 2. Take the top and left of the untransformed frame to get the real position on screen.
- // Apply the layer transform on top/left so it includes any scale or rotation. These will
- // be the new translation values for the transform.
- // 3. Update the translation of the original transform to the new translation values.
- // 4. Send the inverse transform to input so the coordinates can be transformed back into
- // window space.
- ui::Transform inverseTransform = t.inverse();
- Rect nonTransformedBounds = inverseTransform.transform(transformedLayerBounds);
- vec2 translation = t.transform(nonTransformedBounds.left, nonTransformedBounds.top);
- ui::Transform inputTransform(t);
- inputTransform.set(translation.x, translation.y);
- info.transform = inputTransform.inverse();
-
- // We need to send the layer bounds cropped to the screenbounds since the layer can be cropped.
- // The frame should be the area the user sees on screen since it's used for occlusion
- // detection.
- transformedLayerBounds.intersect(screenBounds, &transformedLayerBounds);
- info.frameLeft = transformedLayerBounds.left;
- info.frameTop = transformedLayerBounds.top;
- info.frameRight = transformedLayerBounds.right;
- info.frameBottom = transformedLayerBounds.bottom;
-
- // Position the touchable region relative to frame screen location and restrict it to frame
- // bounds.
- info.touchableRegion = inputTransform.transform(info.touchableRegion);
+ tmpBounds = Rect::EMPTY_RECT;
+ }
+
+ // InputDispatcher works in the display device's coordinate space. Here, we calculate the
+ // frame and transform used for the layer, which determines the bounds and the coordinate space
+ // within which the layer will receive input.
+ //
+ // The coordinate space within which each of the bounds are specified is explicitly documented
+ // in the variable name. For example "inputBoundsInLayer" is specified in layer space. A
+ // Transform converts one coordinate space to another, which is apparent in its naming. For
+ // example, "layerToDisplay" transforms layer space to display space.
+ //
+ // Coordinate space definitions:
+ // - display: The display device's coordinate space. Correlates to pixels on the display.
+ // - screen: The post-rotation coordinate space for the display, a.k.a. logical display space.
+ // - layer: The coordinate space of this layer.
+ // - input: The coordinate space in which this layer will receive input events. This could be
+ // different than layer space if a surfaceInset is used, which changes the origin
+ // of the input space.
+ const FloatRect inputBoundsInLayer = tmpBounds.toFloatRect();
+
+ // Clamp surface inset to the input bounds.
+ const auto surfaceInset = static_cast<float>(info.surfaceInset);
+ const float xSurfaceInset =
+ std::max(0.f, std::min(surfaceInset, inputBoundsInLayer.getWidth() / 2.f));
+ const float ySurfaceInset =
+ std::max(0.f, std::min(surfaceInset, inputBoundsInLayer.getHeight() / 2.f));
+
+ // Apply the insets to the input bounds.
+ const FloatRect insetBoundsInLayer(inputBoundsInLayer.left + xSurfaceInset,
+ inputBoundsInLayer.top + ySurfaceInset,
+ inputBoundsInLayer.right - xSurfaceInset,
+ inputBoundsInLayer.bottom - ySurfaceInset);
+
+ // Crop the input bounds to ensure it is within the parent's bounds.
+ const FloatRect croppedInsetBoundsInLayer = mBounds.intersect(insetBoundsInLayer);
+
+ const ui::Transform layerToScreen = getInputTransform();
+ const ui::Transform layerToDisplay = screenToDisplay * layerToScreen;
+
+ const Rect roundedFrameInDisplay{layerToDisplay.transform(croppedInsetBoundsInLayer)};
+ info.frameLeft = roundedFrameInDisplay.left;
+ info.frameTop = roundedFrameInDisplay.top;
+ info.frameRight = roundedFrameInDisplay.right;
+ info.frameBottom = roundedFrameInDisplay.bottom;
+
+ ui::Transform inputToLayer;
+ inputToLayer.set(insetBoundsInLayer.left, insetBoundsInLayer.top);
+ const ui::Transform inputToDisplay = layerToDisplay * inputToLayer;
+
+ // InputDispatcher expects a display-to-input transform.
+ info.transform = inputToDisplay.inverse();
+
+ // The touchable region is specified in the input coordinate space. Change it to display space.
+ info.touchableRegion = inputToDisplay.transform(info.touchableRegion);
}
void Layer::fillTouchOcclusionMode(WindowInfo& info) {