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

Commit bc341860 authored by Nader Jawad's avatar Nader Jawad
Browse files

Updated HWUI to calculate the stretch bounds for a surface

Added logic to StretchEffect to be able to calculate the
stretched position of a pixel on an input texture based
on the current stretch parameters.

Updated shader to leverage linear easing instead of
cubic in order to have a reversible method that
can be used to map input textures to the corresponding
stretch position.

Bug: 179047472
Test: manual

Change-Id: Id32afcf0df1cca03e68ac0c594d307a1090264f2
parent 0408e507
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -272,18 +272,21 @@ void DamageAccumulator::finish(SkRect* totalDirty) {

DamageAccumulator::StretchResult DamageAccumulator::findNearestStretchEffect() const {
    DirtyStack* frame = mHead;
    const auto& headProperties = mHead->renderNode->properties();
    float startWidth = headProperties.getWidth();
    float startHeight = headProperties.getHeight();
    while (frame->prev != frame) {
        if (frame->type == TransformRenderNode) {
            const auto& renderNode = frame->renderNode;
            const auto& frameRenderNodeProperties = renderNode->properties();
            const auto& effect =
                    frameRenderNodeProperties.layerProperties().getStretchEffect();
            const float width = (float) renderNode->getWidth();
            const float height = (float) renderNode->getHeight();
            const float width = (float) frameRenderNodeProperties.getWidth();
            const float height = (float) frameRenderNodeProperties.getHeight();
            if (!effect.isEmpty()) {
                Matrix4 stretchMatrix;
                computeTransformImpl(mHead, frame, &stretchMatrix);
                Rect stretchRect = Rect(0.f, 0.f, width, height);
                Rect stretchRect = Rect(0.f, 0.f, startWidth, startHeight);
                stretchMatrix.mapRect(stretchRect);

                return StretchResult{
+80 −5
Original line number Diff line number Diff line
@@ -68,9 +68,8 @@ static const SkString stretchShader = SkString(R"(
    // and the other way around.
    uniform float uInterpolationStrength;

    float easeInCubic(float t, float d) {
        float tmp = t * d;
        return tmp * tmp * tmp;
    float easeIn(float t, float d) {
        return t * d;
    }

    float computeOverscrollStart(
@@ -83,7 +82,7 @@ static const SkString stretchShader = SkString(R"(
    ) {
        float offsetPos = uStretchAffectedDist - inPos;
        float posBasedVariation = mix(
                1. ,easeInCubic(offsetPos, uInverseStretchAffectedDist), interpolationStrength);
                1. ,easeIn(offsetPos, uInverseStretchAffectedDist), interpolationStrength);
        float stretchIntensity = overscroll * posBasedVariation;
        return distanceStretched - (offsetPos / (1. + stretchIntensity));
    }
@@ -99,7 +98,7 @@ static const SkString stretchShader = SkString(R"(
    ) {
        float offsetPos = inPos - reverseStretchDist;
        float posBasedVariation = mix(
                1. ,easeInCubic(offsetPos, uInverseStretchAffectedDist), interpolationStrength);
                1. ,easeIn(offsetPos, uInverseStretchAffectedDist), interpolationStrength);
        float stretchIntensity = (-overscroll) * posBasedVariation;
        return 1 - (distanceStretched - (offsetPos / (1. + stretchIntensity)));
    }
@@ -234,4 +233,80 @@ sk_sp<SkRuntimeEffect> StretchEffect::getStretchEffect() {
    return instance.effect;
}

/**
 * Helper method that maps the input texture position to the stretch position
 * based on the given overscroll value that represents an overscroll from
 * either the top or left
 * @param overscroll current overscroll value
 * @param input normalized input position (can be x or y) on the input texture
 * @return stretched position of the input normalized from 0 to 1
 */
float reverseMapStart(float overscroll, float input) {
    float numerator = (-input * overscroll * overscroll) -
        (2 * input * overscroll) - input;
    float denominator = 1.f + (.3f * overscroll) +
        (.7f * input * overscroll * overscroll) + (.7f * input * overscroll);
    return -(numerator / denominator);
}

/**
 * Helper method that maps the input texture position to the stretch position
 * based on the given overscroll value that represents an overscroll from
 * either the bottom or right
 * @param overscroll current overscroll value
 * @param input normalized input position (can be x or y) on the input texture
 * @return stretched position of the input normalized from 0 to 1
 */
float reverseMapEnd(float overscroll, float input) {
    float numerator = (.3f * overscroll * overscroll) -
        (.3f * input * overscroll * overscroll) +
        (1.3f * input * overscroll) - overscroll - input;
    float denominator = (.7f * input * overscroll * overscroll) -
        (.7f * input * overscroll) - (.7f * overscroll * overscroll) +
        overscroll - 1.f;
    return numerator / denominator;
}

/**
  * Calculates the normalized stretch position given the normalized input
  * position. This handles calculating the overscroll from either the
  * top or left vs bottom or right depending on the sign of the given overscroll
  * value
  *
  * @param overscroll unit vector of overscroll from -1 to 1 indicating overscroll
  * from the bottom or right vs top or left respectively
  * @param normalizedInput the
  * @return
  */
float computeReverseOverscroll(float overscroll, float normalizedInput) {
    float distanceStretched = 1.f / (1.f + abs(overscroll));
    float distanceDiff = distanceStretched - 1.f;
    if (overscroll > 0) {
        float output = reverseMapStart(overscroll, normalizedInput);
        if (output <= 1.0f) {
            return output;
        } else if (output >= distanceStretched){
            return output - distanceDiff;
        }
    }

    if (overscroll < 0) {
        float output = reverseMapEnd(overscroll, normalizedInput);
        if (output >= 0.f) {
            return output;
        } else if (output < 0.f){
            return output + distanceDiff;
        }
    }
    return normalizedInput;
}

float StretchEffect::computeStretchedPositionX(float normalizedX) const {
  return computeReverseOverscroll(mStretchDirection.x(), normalizedX);
}

float StretchEffect::computeStretchedPositionY(float normalizedY) const {
  return computeReverseOverscroll(mStretchDirection.y(), normalizedY);
}

} // namespace android::uirenderer
 No newline at end of file
+16 −0
Original line number Diff line number Diff line
@@ -75,6 +75,22 @@ public:
        maxStretchAmountY = std::max(maxStretchAmountY, other.maxStretchAmountY);
    }

    /**
     * Return the stretched x position given the normalized x position with
     * the current horizontal stretch direction
     * @param normalizedX x position on the input texture from 0 to 1
     * @return x position when the horizontal stretch direction applied
     */
    float computeStretchedPositionX(float normalizedX) const;

    /**
     * Return the stretched y position given the normalized y position with
     * the current horizontal stretch direction
     * @param normalizedX y position on the input texture from 0 to 1
     * @return y position when the horizontal stretch direction applied
     */
    float computeStretchedPositionY(float normalizedY) const;

    sk_sp<SkShader> getShader(float width, float height,
                              const sk_sp<SkImage>& snapshotImage) const;

+31 −3
Original line number Diff line number Diff line
@@ -572,11 +572,11 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
            info.damageAccumulator->computeCurrentTransform(&transform);
            const RenderProperties& props = node.properties();

            uirenderer::Rect bounds(props.getWidth(), props.getHeight());
            if (info.stretchEffectCount) {
                handleStretchEffect(info, transform);
                handleStretchEffect(info, bounds);
            }

            uirenderer::Rect bounds(props.getWidth(), props.getHeight());
            transform.mapRect(bounds);

            if (CC_LIKELY(transform.isPureTranslate())) {
@@ -639,7 +639,33 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
            return env;
        }

        void handleStretchEffect(const TreeInfo& info, const Matrix4& transform) {
        void stretchTargetBounds(const StretchEffect& stretchEffect,
                                 float width, float height,
                                 const SkRect& childRelativeBounds,
                                 uirenderer::Rect& bounds) {
              float normalizedLeft = childRelativeBounds.left() / width;
              float normalizedTop = childRelativeBounds.top() / height;
              float normalizedRight = childRelativeBounds.right() / width;
              float normalizedBottom = childRelativeBounds.bottom() / height;
              float reverseLeft = width *
                  (stretchEffect.computeStretchedPositionX(normalizedLeft) -
                    normalizedLeft);
              float reverseTop = height *
                  (stretchEffect.computeStretchedPositionY(normalizedTop) -
                    normalizedTop);
              float reverseRight = width *
                  (stretchEffect.computeStretchedPositionX(normalizedRight) -
                    normalizedLeft);
              float reverseBottom = height *
                  (stretchEffect.computeStretchedPositionY(normalizedBottom) -
                    normalizedTop);
              bounds.left = reverseLeft;
              bounds.top = reverseTop;
              bounds.right = reverseRight;
              bounds.bottom = reverseBottom;
        }

        void handleStretchEffect(const TreeInfo& info, uirenderer::Rect& targetBounds) {
            // Search up to find the nearest stretcheffect parent
            const DamageAccumulator::StretchResult result =
                info.damageAccumulator->findNearestStretchEffect();
@@ -649,6 +675,8 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
            }

            const auto& childRelativeBounds = result.childRelativeBounds;
            stretchTargetBounds(*effect, result.width, result.height,
                                childRelativeBounds,targetBounds);

            JNIEnv* env = jnienv();