Merge "Fix Skia pipeline readback for non-portrait mode"
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
index e798edf..025503b 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -85,11 +85,6 @@
 
     uint32_t width = graphicBuffer->getWidth();
     uint32_t height = graphicBuffer->getHeight();
-    // If this is a 90 or 270 degree rotation we need to swap width/height
-    // This is a fuzzy way of checking that.
-    if (texTransform[Matrix4::kSkewX] >= 0.5f || texTransform[Matrix4::kSkewX] <= -0.5f) {
-        std::swap(width, height);
-    }
     CopyResult copyResult = copyImageInto(sourceImage, texTransform, width, height,
             srcRect, bitmap);
 
@@ -254,6 +249,12 @@
         const Matrix4& imgTransform, int imgWidth, int imgHeight, const Rect& srcRect,
         SkBitmap* bitmap) {
 
+    // If this is a 90 or 270 degree rotation we need to swap width/height
+    // This is a fuzzy way of checking that.
+    if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) {
+        std::swap(imgWidth, imgHeight);
+    }
+
     Caches& caches = Caches::getInstance();
     GLuint sourceTexId;
     // Create a 2D texture to sample from the EGLImage
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 69b9c01fe..311419d 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -60,37 +60,51 @@
     sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture,
             kTopLeft_GrSurfaceOrigin));
     if (image) {
-        // convert to Skia data structures
-        const SkRect bufferRect = SkRect::MakeIWH(imgWidth, imgHeight);
-        SkRect skiaSrcRect = srcRect.toSkRect();
         SkMatrix textureMatrix;
         imgTransform.copyTo(textureMatrix);
 
-        // remove the y-flip applied to the matrix so that we can scale the srcRect.
-        // This flip is not needed as we specify the origin of the texture when we
-        // wrap it as an SkImage.
+        // remove the y-flip applied to the matrix
         SkMatrix yFlip = SkMatrix::MakeScale(1, -1);
         yFlip.postTranslate(0,1);
         textureMatrix.preConcat(yFlip);
 
-        // copy the entire src if the rect is empty
-        if (skiaSrcRect.isEmpty()) {
-            skiaSrcRect = bufferRect;
+        // multiply by image size, because textureMatrix maps to [0..1] range
+        textureMatrix[SkMatrix::kMTransX] *= imgWidth;
+        textureMatrix[SkMatrix::kMTransY] *= imgHeight;
+
+        // swap rotation and translation part of the matrix, because we convert from
+        // right-handed Cartesian to left-handed coordinate system.
+        std::swap(textureMatrix[SkMatrix::kMTransX], textureMatrix[SkMatrix::kMTransY]);
+        std::swap(textureMatrix[SkMatrix::kMSkewX], textureMatrix[SkMatrix::kMSkewY]);
+
+        // convert to Skia data structures
+        SkRect skiaSrcRect = srcRect.toSkRect();
+        SkMatrix textureMatrixInv;
+        SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height());
+        bool srcNotEmpty = false;
+        if (textureMatrix.invert(&textureMatrixInv)) {
+            if (skiaSrcRect.isEmpty()) {
+                skiaSrcRect = SkRect::MakeIWH(imgWidth, imgHeight);
+                srcNotEmpty = !skiaSrcRect.isEmpty();
+            } else {
+                // src and dest rectangles need to be converted into texture coordinates before the
+                // rotation matrix is applied (because drawImageRect preconcat its matrix).
+                textureMatrixInv.mapRect(&skiaSrcRect);
+                srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(imgWidth, imgHeight));
+            }
+            textureMatrixInv.mapRect(&skiaDestRect);
         }
 
-        // since the y-flip has been removed we can simply scale & translate
-        // the source rectangle
-        textureMatrix.mapRect(&skiaSrcRect);
-
-        if (skiaSrcRect.intersect(bufferRect)) {
+        if (srcNotEmpty) {
             // we render in an offscreen buffer to scale and to avoid an issue b/62262733
             // with reading incorrect data from EGLImage backed SkImage (likely a driver bug)
             sk_sp<SkSurface> scaledSurface = SkSurface::MakeRenderTarget(
                     grContext.get(), SkBudgeted::kYes, bitmap->info());
             SkPaint paint;
             paint.setBlendMode(SkBlendMode::kSrc);
-            scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect,
-                    SkRect::MakeWH(bitmap->width(), bitmap->height()), &paint);
+            scaledSurface->getCanvas()->concat(textureMatrix);
+            scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint);
+
             image = scaledSurface->makeImageSnapshot();
 
             if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {