Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 50c0afe2 authored by Vishnu Nair's avatar Vishnu Nair
Browse files

SF: Support xy scaling for rounded corners

Currently only a single corner radius can be applied on a
layer. If the layer's x and y scale do not match, the average
is used to scale the corner radius. This can cause visual
defects in the rendered rounded corners.

This defect can be seen when moving the Camera app
to recents. The camera buffer is submitted with a rotation
and the layer's x and y scales are used to stretch the buffer
to the desired size in portrait mode.

Bug: 145094543
Test: atest librenderengine_test
Test: adb shell wm size 1000x1900 & animate camera app to recents
Change-Id: Ie76581eb200a57b847f619f4da0e61758f70dce7
parent 20c976c2
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -921,7 +921,8 @@ void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display,

    // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners
    // and the middle part without rounded corners.
    const int32_t radius = ceil(layer.geometry.roundedCornersRadius);
    const int32_t radius = ceil(
            (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) / 2.0);
    const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius);
    setScissor(topRect);
    drawMesh(mesh);
@@ -1266,23 +1267,24 @@ void GLESRenderEngine::drawLayersInternal(

        const half3 solidColor = layer.source.solidColor;
        const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
        const float radius =
                (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) /
                2.0f;
        // Buffer sources will have a black solid color ignored in the shader,
        // so in that scenario the solid color passed here is arbitrary.
        setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color,
                           layer.geometry.roundedCornersRadius);
        setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, radius);
        if (layer.disableBlending) {
            glDisable(GL_BLEND);
        }
        setSourceDataSpace(layer.sourceDataspace);

        if (layer.shadow.length > 0.0f) {
            handleShadow(layer.geometry.boundaries, layer.geometry.roundedCornersRadius,
                         layer.shadow);
            handleShadow(layer.geometry.boundaries, radius, layer.shadow);
        }
        // We only want to do a special handling for rounded corners when having rounded corners
        // is the only reason it needs to turn on blending, otherwise, we handle it like the
        // usual way since it needs to turn on blending anyway.
        else if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
        else if (radius > 0.0 && color.a >= 1.0f && isOpaque) {
            handleRoundedCorners(display, layer, mesh);
        } else {
            drawMesh(mesh);
+3 −2
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ struct Geometry {
    // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be
    // in local layer coordinate space, so we have to take the layer transform into account when
    // walking up the tree.
    float roundedCornersRadius = 0.0;
    vec2 roundedCornersRadius = vec2(0.0f, 0.0f);

    // Rectangle within which corners will be rounded.
    FloatRect roundedCornersCrop = FloatRect();
@@ -258,7 +258,8 @@ static inline void PrintTo(const Geometry& settings, ::std::ostream* os) {
    PrintTo(settings.boundaries, os);
    *os << "\n    .positionTransform = ";
    PrintMatrix(settings.positionTransform, os);
    *os << "\n    .roundedCornersRadius = " << settings.roundedCornersRadius;
    *os << "\n    .roundedCornersRadiusX = " << settings.roundedCornersRadius.x;
    *os << "\n    .roundedCornersRadiusY = " << settings.roundedCornersRadius.y;
    *os << "\n    .roundedCornersCrop = ";
    PrintTo(settings.roundedCornersCrop, os);
    *os << "\n}";
+11 −10
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin
                    Geometry{
                            .boundaries = rect,
                            .roundedCornersCrop = rect,
                            .roundedCornersRadius = 50.f,
                            .roundedCornersRadius = {50.f, 50.f},
                    },
            // drawShadow ignores alpha
            .shadow =
@@ -87,7 +87,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin
                    Geometry{
                            .boundaries = smallerRect,
                            .roundedCornersCrop = rect,
                            .roundedCornersRadius = 50.f,
                            .roundedCornersRadius = {50.f, 50.f},
                    },
            .source =
                    PixelSource{
@@ -148,7 +148,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting
        // In reduced shader mode, all non-zero round rect radii get the same code path.
        for (float roundedCornersRadius : {0.0f, 50.0f}) {
            // roundedCornersCrop is always set, but the radius triggers the behavior
            layer.geometry.roundedCornersRadius = roundedCornersRadius;
            layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius};
            for (bool isOpaque : {true, false}) {
                layer.source.buffer.isOpaque = isOpaque;
                for (auto alpha : {half(.2f), half(1.0f)}) {
@@ -181,7 +181,7 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting
    for (auto transform : {mat4(), kScaleAndTranslate}) {
        layer.geometry.positionTransform = transform;
        for (float roundedCornersRadius : {0.0f, 50.f}) {
            layer.geometry.roundedCornersRadius = roundedCornersRadius;
            layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius};
            auto layers = std::vector<LayerSettings>{layer};
            renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
                                     base::unique_fd());
@@ -238,7 +238,7 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti
            .geometry =
                    Geometry{
                            .boundaries = rect,
                            .roundedCornersRadius = 27, // larger than the 20 above.
                            .roundedCornersRadius = {27.f, 27.f},
                            .roundedCornersCrop =
                                    FloatRect(0, 0, displayRect.width(), displayRect.height()),
                    },
@@ -275,9 +275,9 @@ static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySetti
                            // larger than the layer bounds.
                            .positionTransform = kFlip,
                            .boundaries = rect,
                            .roundedCornersRadius = 94.2551,
                            .roundedCornersCrop = FloatRect(
                                -93.75, 0, displayRect.width() + 93.75, displayRect.height()),
                            .roundedCornersRadius = {94.2551f, 94.2551f},
                            .roundedCornersCrop = FloatRect(-93.75, 0, displayRect.width() + 93.75,
                                                            displayRect.height()),
                    },
            .source = PixelSource{.buffer =
                                          Buffer{
@@ -307,10 +307,11 @@ static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySett
                            // the boundaries have to be smaller than the rounded crop so that
                            // clipRRect is used instead of drawRRect
                            .boundaries = small,
                            .roundedCornersRadius = 50.f,
                            .roundedCornersRadius = {50.f, 50.f},
                            .roundedCornersCrop = rect,
                    },
            .source = PixelSource{
            .source =
                    PixelSource{
                            .solidColor = half3(0.f, 0.f, 0.f),
                    },
            .sourceDataspace = kDestDataSpace,
+12 −12
Original line number Diff line number Diff line
@@ -1307,7 +1307,7 @@ inline SkRect SkiaGLRenderEngine::getSkRect(const Rect& rect) {
 *  produce the insected roundRect. If false, the returned state of the radii param is undefined.
 */
static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
                                    const SkRect& insetCrop, float cornerRadius,
                                    const SkRect& insetCrop, const vec2& cornerRadius,
                                    SkVector radii[4]) {
    const bool leftEqual = bounds.fLeft == crop.fLeft;
    const bool topEqual = bounds.fTop == crop.fTop;
@@ -1319,8 +1319,8 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
    // In particular the round rect implementation will scale the value of all corner radii
    // if the sum of the radius along any edge is greater than the length of that edge.
    // See https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
    const bool requiredWidth = bounds.width() > (cornerRadius * 2);
    const bool requiredHeight = bounds.height() > (cornerRadius * 2);
    const bool requiredWidth = bounds.width() > (cornerRadius.x * 2);
    const bool requiredHeight = bounds.height() > (cornerRadius.y * 2);
    if (!requiredWidth || !requiredHeight) {
        return false;
    }
@@ -1329,7 +1329,7 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
    // contained within the cropped shape and does not need rounded.
    // compute the UpperLeft corner radius
    if (leftEqual && topEqual) {
        radii[0].set(cornerRadius, cornerRadius);
        radii[0].set(cornerRadius.x, cornerRadius.y);
    } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) ||
               (topEqual && bounds.fLeft >= insetCrop.fLeft)) {
        radii[0].set(0, 0);
@@ -1338,7 +1338,7 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
    }
    // compute the UpperRight corner radius
    if (rightEqual && topEqual) {
        radii[1].set(cornerRadius, cornerRadius);
        radii[1].set(cornerRadius.x, cornerRadius.y);
    } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) ||
               (topEqual && bounds.fRight <= insetCrop.fRight)) {
        radii[1].set(0, 0);
@@ -1347,7 +1347,7 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
    }
    // compute the BottomRight corner radius
    if (rightEqual && bottomEqual) {
        radii[2].set(cornerRadius, cornerRadius);
        radii[2].set(cornerRadius.x, cornerRadius.y);
    } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) ||
               (bottomEqual && bounds.fRight <= insetCrop.fRight)) {
        radii[2].set(0, 0);
@@ -1356,7 +1356,7 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
    }
    // compute the BottomLeft corner radius
    if (leftEqual && bottomEqual) {
        radii[3].set(cornerRadius, cornerRadius);
        radii[3].set(cornerRadius.x, cornerRadius.y);
    } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) ||
               (bottomEqual && bounds.fLeft >= insetCrop.fLeft)) {
        radii[3].set(0, 0);
@@ -1369,22 +1369,22 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,

inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const FloatRect& boundsRect,
                                                                        const FloatRect& cropRect,
                                                                        const float cornerRadius) {
                                                                        const vec2& cornerRadius) {
    const SkRect bounds = getSkRect(boundsRect);
    const SkRect crop = getSkRect(cropRect);

    SkRRect clip;
    if (cornerRadius > 0) {
    if (cornerRadius.x > 0 && cornerRadius.y > 0) {
        // it the crop and the bounds are equivalent or there is no crop then we don't need a clip
        if (bounds == crop || crop.isEmpty()) {
            return {SkRRect::MakeRectXY(bounds, cornerRadius, cornerRadius), clip};
            return {SkRRect::MakeRectXY(bounds, cornerRadius.x, cornerRadius.y), clip};
        }

        // This makes an effort to speed up common, simple bounds + clip combinations by
        // converting them to a single RRect draw. It is possible there are other cases
        // that can be converted.
        if (crop.contains(bounds)) {
            const auto insetCrop = crop.makeInset(cornerRadius, cornerRadius);
            const auto insetCrop = crop.makeInset(cornerRadius.x, cornerRadius.y);
            if (insetCrop.contains(bounds)) {
                return {SkRRect::MakeRect(bounds), clip}; // clip is empty - no rounding required
            }
@@ -1398,7 +1398,7 @@ inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const Fl
        }

        // we didn't hit any of our fast paths so set the clip to the cropRect
        clip.setRectXY(crop, cornerRadius, cornerRadius);
        clip.setRectXY(crop, cornerRadius.x, cornerRadius.y);
    }

    // if we hit this point then we either don't have rounded corners or we are going to rely
+2 −1
Original line number Diff line number Diff line
@@ -94,7 +94,8 @@ private:
    inline SkRect getSkRect(const FloatRect& layer);
    inline SkRect getSkRect(const Rect& layer);
    inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const FloatRect& bounds,
                                                        const FloatRect& crop, float cornerRadius);
                                                        const FloatRect& crop,
                                                        const vec2& cornerRadius);
    inline bool layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha);
    inline SkColor getSkColor(const vec4& color);
    inline SkM44 getSkM44(const mat4& matrix);
Loading