Clamp ReadPixels calls to unsigned limits in D3D11.

GL allows reads beyond the defined pixel rectangle, although their
resultant values are undefined. D3D11 gives an error when reading
out-of-bounds, hence clamping the area satisfies both APIs.

This fixes a Renderer crash in our ReadPixels out of bounds test,
and also fixes the test to test the correct area of pixels.

BUG=angle:590

Change-Id: I12439c22d53ec6a2d69e1b8cf80f53e9c18e11f7
Reviewed-on: https://chromium-review.googlesource.com/191080
Reviewed-by: Shannon Woods <shannonwoods@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libGLESv2/renderer/d3d11/Renderer11.cpp b/src/libGLESv2/renderer/d3d11/Renderer11.cpp
index 3ba36d0..ca97c04 100644
--- a/src/libGLESv2/renderer/d3d11/Renderer11.cpp
+++ b/src/libGLESv2/renderer/d3d11/Renderer11.cpp
@@ -3319,12 +3319,35 @@
                                  GLenum format, GLenum type, GLsizei outputPitch, bool packReverseRowOrder,
                                  GLint packAlignment, void *pixels)
 {
+    ASSERT(area.width >= 0);
+    ASSERT(area.height >= 0);
+
     D3D11_TEXTURE2D_DESC textureDesc;
     texture->GetDesc(&textureDesc);
 
+    // Clamp read region to the defined texture boundaries, preventing out of bounds reads
+    // and reads of uninitialized data.
+    gl::Rectangle safeArea;
+    safeArea.x      = gl::clamp(area.x, 0, static_cast<int>(textureDesc.Width));
+    safeArea.y      = gl::clamp(area.y, 0, static_cast<int>(textureDesc.Height));
+    safeArea.width  = gl::clamp(area.width + std::min(area.x, 0), 0,
+                                static_cast<int>(textureDesc.Width) - safeArea.x);
+    safeArea.height = gl::clamp(area.height + std::min(area.y, 0), 0,
+                                static_cast<int>(textureDesc.Height) - safeArea.y);
+
+    ASSERT(safeArea.x >= 0 && safeArea.y >= 0);
+    ASSERT(safeArea.x + safeArea.width  <= static_cast<int>(textureDesc.Width));
+    ASSERT(safeArea.y + safeArea.height <= static_cast<int>(textureDesc.Height));
+
+    if (safeArea.width == 0 || safeArea.height == 0)
+    {
+        // no work to do
+        return;
+    }
+
     D3D11_TEXTURE2D_DESC stagingDesc;
-    stagingDesc.Width = area.width;
-    stagingDesc.Height = area.height;
+    stagingDesc.Width = safeArea.width;
+    stagingDesc.Height = safeArea.height;
     stagingDesc.MipLevels = 1;
     stagingDesc.ArraySize = 1;
     stagingDesc.Format = textureDesc.Format;
@@ -3377,12 +3400,12 @@
     }
 
     D3D11_BOX srcBox;
-    srcBox.left = area.x;
-    srcBox.right = area.x + area.width;
-    srcBox.top = area.y;
-    srcBox.bottom = area.y + area.height;
-    srcBox.front = 0;
-    srcBox.back = 1;
+    srcBox.left   = static_cast<UINT>(safeArea.x);
+    srcBox.right  = static_cast<UINT>(safeArea.x + safeArea.width);
+    srcBox.top    = static_cast<UINT>(safeArea.y);
+    srcBox.bottom = static_cast<UINT>(safeArea.y + safeArea.height);
+    srcBox.front  = 0;
+    srcBox.back   = 1;
 
     mDeviceContext->CopySubresourceRegion(stagingTex, 0, 0, 0, 0, srcTex, subResource, &srcBox);
 
@@ -3395,7 +3418,7 @@
     int inputPitch;
     if (packReverseRowOrder)
     {
-        source = static_cast<unsigned char*>(mapping.pData) + mapping.RowPitch * (area.height - 1);
+        source = static_cast<unsigned char*>(mapping.pData) + mapping.RowPitch * (safeArea.height - 1);
         inputPitch = -static_cast<int>(mapping.RowPitch);
     }
     else
@@ -3416,9 +3439,9 @@
     {
         // Direct copy possible
         unsigned char *dest = static_cast<unsigned char*>(pixels);
-        for (int y = 0; y < area.height; y++)
+        for (int y = 0; y < safeArea.height; y++)
         {
-            memcpy(dest + y * outputPitch, source + y * inputPitch, area.width * sourcePixelSize);
+            memcpy(dest + y * outputPitch, source + y * inputPitch, safeArea.width * sourcePixelSize);
         }
     }
     else
@@ -3430,9 +3453,9 @@
         if (fastCopyFunc)
         {
             // Fast copy is possible through some special function
-            for (int y = 0; y < area.height; y++)
+            for (int y = 0; y < safeArea.height; y++)
             {
-                for (int x = 0; x < area.width; x++)
+                for (int x = 0; x < safeArea.width; x++)
                 {
                     void *dest = static_cast<unsigned char*>(pixels) + y * outputPitch + x * destPixelSize;
                     void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize;
@@ -3451,9 +3474,9 @@
                         sizeof(temp) >= sizeof(gl::ColorUI) &&
                         sizeof(temp) >= sizeof(gl::ColorI));
 
-            for (int y = 0; y < area.height; y++)
+            for (int y = 0; y < safeArea.height; y++)
             {
-                for (int x = 0; x < area.width; x++)
+                for (int x = 0; x < safeArea.width; x++)
                 {
                     void *dest = static_cast<unsigned char*>(pixels) + y * outputPitch + x * destPixelSize;
                     void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize;