Update SurfaceFlinger to handle stretching
of surfaces that are part of a scrolling container

Bug: 184297961
Test: In progress
Change-Id: I959df097ae1fc833fb755f1fb2d759d79f260963
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index acdb78a..3e3649e 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -56,6 +56,7 @@
 #include "log/log_main.h"
 #include "skia/debug/SkiaCapture.h"
 #include "skia/debug/SkiaMemoryReporter.h"
+#include "skia/filters/StretchShaderFactory.h"
 #include "system/graphics-base-v1.0.h"
 
 namespace {
@@ -541,14 +542,19 @@
     }
 }
 
-sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> shader,
-                                                              const LayerSettings* layer,
-                                                              const DisplaySettings& display,
-                                                              bool undoPremultipliedAlpha,
-                                                              bool requiresLinearEffect) {
-    if (layer->stretchEffect.hasEffect()) {
-        // TODO: Implement
+sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(
+        sk_sp<SkShader> shader,
+        const LayerSettings* layer, const DisplaySettings& display, bool undoPremultipliedAlpha,
+        bool requiresLinearEffect) {
+    const auto stretchEffect = layer->stretchEffect;
+    if (stretchEffect.hasEffect()) {
+        const auto targetBuffer = layer->source.buffer.buffer;
+        const auto graphicsBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
+        if (graphicsBuffer && shader) {
+            shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
+        }
     }
+
     if (requiresLinearEffect) {
         const ui::Dataspace inputDataspace =
                 mUseColorManagement ? layer->sourceDataspace : ui::Dataspace::UNKNOWN;
@@ -634,6 +640,33 @@
     int mSaveCount;
 };
 
+void drawStretch(const SkRect& bounds, const StretchEffect& stretchEffect,
+                 SkCanvas* canvas, const SkPaint& paint) {
+    float top = bounds.top();
+    float left = bounds.left();
+    float bottom = bounds.bottom();
+    float right = bounds.right();
+    // Adjust the drawing bounds based on the stretch itself.
+    float stretchOffsetX =
+        round(bounds.width() * stretchEffect.getStretchWidthMultiplier());
+    float stretchOffsetY =
+        round(bounds.height() * stretchEffect.getStretchHeightMultiplier());
+    if (stretchEffect.vectorY < 0.f) {
+        top -= stretchOffsetY;
+    } else if (stretchEffect.vectorY > 0.f){
+        bottom += stretchOffsetY;
+    }
+
+    if (stretchEffect.vectorX < 0.f) {
+        left -= stretchOffsetX;
+    } else if (stretchEffect.vectorX > 0.f) {
+        right += stretchOffsetX;
+    }
+
+    auto stretchBounds = SkRect::MakeLTRB(left, top, right, bottom);
+    canvas->drawRect(stretchBounds, paint);
+}
+
 status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
                                         const std::vector<const LayerSettings*>& layers,
                                         const std::shared_ptr<ExternalTexture>& buffer,
@@ -671,9 +704,7 @@
     } else {
         surfaceTextureRef =
                 std::make_shared<AutoBackendTexture::LocalRef>(grContext.get(),
-                                                               buffer->getBuffer()
-                                                                       ->toAHardwareBuffer(),
-                                                               true);
+                      buffer->getBuffer()->toAHardwareBuffer(), true);
     }
 
     const ui::Dataspace dstDataspace =
@@ -988,7 +1019,17 @@
             paint.setAntiAlias(true);
             canvas->drawRRect(getRoundedRect(layer), paint);
         } else {
-            canvas->drawRect(bounds, paint);
+            auto& stretchEffect = layer->stretchEffect;
+            // TODO (njawad) temporarily disable manipulation of geometry
+            //  the layer bounds will be updated in HWUI instead of RenderEngine
+            //  in a subsequent CL
+            // Keep the method call in a dead code path to make -Werror happy
+            // with unused methods
+            if (stretchEffect.hasEffect() && /* DISABLES CODE */ (false)) {
+                drawStretch(bounds, stretchEffect, canvas, paint);
+            } else {
+                canvas->drawRect(bounds, paint);
+            }
         }
         if (kFlushAfterEveryLayer) {
             ATRACE_NAME("flush surface");