SkAnimatedImage: Reject invalid crops

A crop is invalid if it is empty/unsorted or does not intersect with
the image. Android (the only known client of the cropping API) will not
pass such a rectangle to the API, but this prevents other clients from
passing an invalid rectangle.

Change-Id: I09e007ecd378c358a1c604aff518035090f1e0a4
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/333224
Commit-Queue: Leon Scroggins <scroggo@google.com>
Reviewed-by: Derek Sollenberger <djsollen@google.com>
diff --git a/tests/AnimatedImageTest.cpp b/tests/AnimatedImageTest.cpp
index 741fada..0b72bc2 100644
--- a/tests/AnimatedImageTest.cpp
+++ b/tests/AnimatedImageTest.cpp
@@ -29,6 +29,66 @@
 #include <utility>
 #include <vector>
 
+DEF_TEST(AnimatedImage_invalidCrop, r) {
+    if (GetResourcePath().isEmpty()) {
+        return;
+    }
+
+    const char* file = "images/alphabetAnim.gif";
+    auto data = GetResourceAsData(file);
+    if (!data) {
+        ERRORF(r, "Could not get %s", file);
+        return;
+    }
+
+    const struct Rec {
+        bool    valid;
+        SkISize scaledSize;
+        SkIRect cropRect;
+    } gRecs[] = {
+        // cropRect contained by original dimensions
+        { true,  {100, 100}, {   0,  0, 100, 100} },
+        { true,  {100, 100}, {   0,  0,  50,  50} },
+        { true,  {100, 100}, {  10, 10, 100, 100} },
+        { true,  {100, 100}, {   0,  0, 100, 100} },
+
+        // unsorted cropRect
+        { false, {100, 100}, {   0, 100, 100,   0} },
+        { false, {100, 100}, { 100,   0,   0, 100} },
+
+        // cropRect not contained by original dimensions
+        { false, {100, 100}, {   0,   1, 100, 101} },
+        { false, {100, 100}, {   0,  -1, 100,  99} },
+        { false, {100, 100}, {  -1,   0,  99, 100} },
+        { false, {100, 100}, { 100, 100, 200, 200} },
+
+        // cropRect contained by scaled dimensions
+        { true,  { 50,  50}, {   0,   0,  50,  50} },
+        { true,  { 50,  50}, {   0,   0,  25,  25} },
+        { true,  {200, 200}, {   0,   1, 100, 101} },
+
+        // cropRect not contained by scaled dimensions
+        { false, { 50,  50}, {   0,   0,  75,  25} },
+        { false, { 50,  50}, {   0,   0,  25,  75} },
+
+    };
+    for (const auto& rec : gRecs) {
+        auto codec = SkAndroidCodec::MakeFromData(data);
+        if (!codec) {
+            ERRORF(r, "Could not create codec for %s", file);
+            return;
+        }
+
+        auto info = codec->getInfo();
+        REPORTER_ASSERT(r, info.dimensions() == SkISize::Make(100, 100));
+
+        auto image = SkAnimatedImage::Make(std::move(codec), info.makeDimensions(rec.scaledSize),
+                rec.cropRect, nullptr);
+
+        REPORTER_ASSERT(r, rec.valid == !!image.get());
+    }
+}
+
 DEF_TEST(AnimatedImage_scaled, r) {
     if (GetResourcePath().isEmpty()) {
         return;