diff options
Diffstat (limited to 'services/surfaceflinger/Layer.cpp')
| -rw-r--r-- | services/surfaceflinger/Layer.cpp | 137 |
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) { |