Fix up row bytes for single level texture in GrResourceProvider.

Change-Id: I5419a79255f9e9cdb3322238bd0d3b14e88ef6e6
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/226156
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index 60cabf5..0e171a8 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -42,6 +42,33 @@
     fCaps = sk_ref_sp(fGpu->caps());
 }
 
+// Ensures the row bytes are populated (not 0) and makes a copy to a temporary
+// to make the row bytes tight if necessary. Returns false if the input row bytes are invalid.
+static bool prepare_level(const GrMipLevel& inLevel, size_t bpp, int w, int h, bool rowBytesSupport,
+                          GrMipLevel* outLevel, std::unique_ptr<char[]>* data) {
+    if (!inLevel.fPixels) {
+        outLevel->fPixels = nullptr;
+        outLevel->fRowBytes = 0;
+        return true;
+    }
+    size_t minRB = w * bpp;
+    size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
+    if (actualRB < minRB) {
+        return false;
+    }
+    if (actualRB == minRB || rowBytesSupport) {
+        outLevel->fRowBytes = actualRB;
+        outLevel->fPixels = inLevel.fPixels;
+    } else {
+        data->reset(new char[minRB * h]);
+        outLevel->fPixels = data->get();
+        outLevel->fRowBytes = minRB;
+        SkRectMemcpy(data->get(), outLevel->fRowBytes, inLevel.fPixels, inLevel.fRowBytes, minRB,
+                     h);
+    }
+    return true;
+}
+
 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
                                                    const GrMipLevel texels[], int mipLevelCount) {
     ASSERT_SINGLE_OWNER
@@ -66,30 +93,9 @@
         int h = desc.fHeight;
         size_t bpp = GrBytesPerPixel(desc.fConfig);
         for (int i = 0; i < mipLevelCount; ++i) {
-            if (texels->fPixels) {
-                size_t minRB = w * bpp;
-                if (!texels->fRowBytes) {
-                    tmpTexels[i].fRowBytes = minRB;
-                    tmpTexels[i].fPixels = texels[i].fPixels;
-                } else {
-                    if (texels[i].fRowBytes < minRB) {
-                        return nullptr;
-                    }
-                    if (!this->caps()->writePixelsRowBytesSupport() &&
-                        texels[i].fRowBytes != minRB) {
-                        auto copy = new char[minRB * h];
-                        tmpDatas[i].reset(copy);
-                        SkRectMemcpy(copy, minRB, texels[i].fPixels, texels[i].fRowBytes, minRB, h);
-                        tmpTexels[i].fPixels = copy;
-                        tmpTexels[i].fRowBytes = minRB;
-                    } else {
-                        tmpTexels[i].fPixels = texels[i].fPixels;
-                        tmpTexels[i].fRowBytes = texels[i].fRowBytes;
-                    }
-                }
-            } else {
-                tmpTexels[i].fPixels = nullptr;
-                tmpTexels[i].fRowBytes = 0;
+            if (!prepare_level(texels[i], bpp, w, h, this->caps()->writePixelsRowBytesSupport(),
+                               &tmpTexels[i], &tmpDatas[i])) {
+                return nullptr;
             }
             w = std::max(w / 2, 1);
             h = std::max(h / 2, 1);
@@ -130,6 +136,14 @@
     GrContext* context = fGpu->getContext();
     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
 
+    size_t bpp = GrBytesPerPixel(desc.fConfig);
+    std::unique_ptr<char[]> tmpData;
+    GrMipLevel tmpLevel;
+    if (!prepare_level(mipLevel, bpp, desc.fWidth, desc.fHeight,
+                       this->caps()->writePixelsRowBytesSupport(), &tmpLevel, &tmpData)) {
+        return nullptr;
+    }
+
     SkColorType colorType;
     if (GrPixelConfigToColorType(desc.fConfig, &colorType)) {
         sk_sp<GrTexture> tex = (SkBackingFit::kApprox == fit)
@@ -155,10 +169,10 @@
             return nullptr;
         }
         SkAssertResult(
-                sContext->writePixels(srcInfo, mipLevel.fPixels, mipLevel.fRowBytes, {0, 0}));
+                sContext->writePixels(srcInfo, tmpLevel.fPixels, tmpLevel.fRowBytes, {0, 0}));
         return sk_ref_sp(sContext->asTextureProxy()->peekTexture());
     } else {
-        return fGpu->createTexture(desc, budgeted, &mipLevel, 1);
+        return fGpu->createTexture(desc, budgeted, &tmpLevel, 1);
     }
 }