Expose more info in SkCodec::FrameInfo

Bug: b/160984428

Add more fields to SkCodec::FrameInfo, which describes the properties of
an individual frame in an animated image. This allows a client that
wishes to seek to determine frame dependencies so that they can decode
an arbitrary frame, which in turn will allow SkCodec to remove
SkCodec::FrameInfo::fRequiredFrame. Currently, SkCodec seeks through the
stream to determine frame dependencies, but this is unnecessary work
(and storage) for a client that does not want to seek.

These fields also support the proposed APIs in go/animated-ndk.

Move SkCodecAnimation::Blend from SkCodecAnimationPriv (and delete that
file) into SkCodecAnimation.h. Rename its values to be more clear.

Merge common code for populating SkCodec::FrameInfo.

Add a test for a GIF with offsets outside the range of the image. Note
that libwebp rejects such an image.

Update libgifcodec.

Change-Id: Ie27e0531e7d62eaae153eccb3105bf2121b5aac4
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/339857
Commit-Queue: Leon Scroggins <scroggo@google.com>
Reviewed-by: Derek Sollenberger <djsollen@google.com>
Reviewed-by: Nigel Tao <nigeltao@google.com>
diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp
index 533cef5..98a6846 100644
--- a/src/codec/SkCodec.cpp
+++ b/src/codec/SkCodec.cpp
@@ -765,6 +765,20 @@
     }
 }
 
+void SkFrame::fillIn(SkCodec::FrameInfo* frameInfo, bool fullyReceived) const {
+    SkASSERT(frameInfo);
+
+    frameInfo->fRequiredFrame = fRequiredFrame;
+    frameInfo->fDuration = fDuration;
+    frameInfo->fFullyReceived = fullyReceived;
+    frameInfo->fAlphaType = fHasAlpha ? kUnpremul_SkAlphaType
+                                      : kOpaque_SkAlphaType;
+    frameInfo->fHasAlphaWithinBounds = this->reportedAlpha() != SkEncodedInfo::kOpaque_Alpha;
+    frameInfo->fDisposalMethod = fDisposalMethod;
+    frameInfo->fBlend = fBlend;
+    frameInfo->fFrameRect = fRect;
+}
+
 static bool independent(const SkFrame& frame) {
     return frame.getRequiredFrame() == SkCodec::kNoFrame;
 }
@@ -828,7 +842,7 @@
     }
 
 
-    const bool blendWithPrevFrame = frame->getBlend() == SkCodecAnimation::Blend::kPriorFrame;
+    const bool blendWithPrevFrame = frame->getBlend() == SkCodecAnimation::Blend::kSrcOver;
     if ((!reportsAlpha || !blendWithPrevFrame) && frameRect == screenRect) {
         frame->setHasAlpha(reportsAlpha);
         frame->setRequiredFrame(SkCodec::kNoFrame);  // IND2
diff --git a/src/codec/SkCodecAnimationPriv.h b/src/codec/SkCodecAnimationPriv.h
deleted file mode 100644
index e326919..0000000
--- a/src/codec/SkCodecAnimationPriv.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkCodecAnimationPriv_DEFINED
-#define SkCodecAnimationPriv_DEFINED
-
-namespace SkCodecAnimation {
-    /**
-     * How to blend the current frame.
-     */
-    enum class Blend {
-        /**
-         *  Blend with the prior frame. This is the typical case, supported
-         *  by all animated image types.
-         */
-        kPriorFrame,
-
-        /**
-         *  Do not blend.
-         *
-         *  This frames pixels overwrite previous pixels "blending" with
-         *  the background color of transparent.
-         */
-        kBG,
-    };
-
-} // namespace SkCodecAnimation
-#endif // SkCodecAnimationPriv_DEFINED
diff --git a/src/codec/SkFrameHolder.h b/src/codec/SkFrameHolder.h
index c44d2e0..7b4031e 100644
--- a/src/codec/SkFrameHolder.h
+++ b/src/codec/SkFrameHolder.h
@@ -8,12 +8,12 @@
 #ifndef SkFrameHolder_DEFINED
 #define SkFrameHolder_DEFINED
 
+#include "include/codec/SkCodec.h"
 #include "include/codec/SkCodecAnimation.h"
 #include "include/core/SkRect.h"
 #include "include/core/SkTypes.h"
 #include "include/private/SkEncodedInfo.h"
 #include "include/private/SkNoncopyable.h"
-#include "src/codec/SkCodecAnimationPriv.h"
 
 /**
  *  Base class for a single frame of an animated image.
@@ -29,7 +29,7 @@
         , fRequiredFrame(kUninitialized)
         , fDisposalMethod(SkCodecAnimation::DisposalMethod::kKeep)
         , fDuration(0)
-        , fBlend(SkCodecAnimation::Blend::kPriorFrame)
+        , fBlend(SkCodecAnimation::Blend::kSrcOver)
     {
         fRect.setEmpty();
     }
@@ -142,6 +142,11 @@
         return fBlend;
     }
 
+    /**
+     * Fill in the FrameInfo with details from this object.
+     */
+    void fillIn(SkCodec::FrameInfo*, bool fullyReceived) const;
+
 protected:
     virtual SkEncodedInfo::Alpha onReportedAlpha() const = 0;
 
diff --git a/src/codec/SkHeifCodec.cpp b/src/codec/SkHeifCodec.cpp
index 1c83481..2a162e8 100644
--- a/src/codec/SkHeifCodec.cpp
+++ b/src/codec/SkHeifCodec.cpp
@@ -348,11 +348,7 @@
     }
 
     if (frameInfo) {
-        frameInfo->fRequiredFrame = SkCodec::kNoFrame;
-        frameInfo->fDuration = frame->getDuration();
-        frameInfo->fFullyReceived = true;
-        frameInfo->fAlphaType = kOpaque_SkAlphaType;
-        frameInfo->fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
+        frame->fillIn(frameInfo, true);
     }
 
     return true;
diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp
index b66d576..e8b1bb4 100644
--- a/src/codec/SkWebpCodec.cpp
+++ b/src/codec/SkWebpCodec.cpp
@@ -12,7 +12,6 @@
 #include "include/core/SkCanvas.h"
 #include "include/private/SkTemplates.h"
 #include "include/private/SkTo.h"
-#include "src/codec/SkCodecAnimationPriv.h"
 #include "src/codec/SkCodecPriv.h"
 #include "src/codec/SkParseEncodedOrigin.h"
 #include "src/codec/SkSampler.h"
@@ -266,7 +265,7 @@
                 SkCodecAnimation::DisposalMethod::kKeep);
         frame->setDuration(iter.duration);
         if (WEBP_MUX_BLEND != iter.blend_method) {
-            frame->setBlend(SkCodecAnimation::Blend::kBG);
+            frame->setBlend(SkCodecAnimation::Blend::kSrc);
         }
         fFrameHolder.setAlphaAndRequiredFrame(frame);
     }
@@ -295,14 +294,9 @@
     }
 
     if (frameInfo) {
-        frameInfo->fRequiredFrame = frame->getRequiredFrame();
-        frameInfo->fDuration = frame->getDuration();
         // libwebp only reports fully received frames for an
         // animated image.
-        frameInfo->fFullyReceived = true;
-        frameInfo->fAlphaType = frame->hasAlpha() ? kUnpremul_SkAlphaType
-                                                  : kOpaque_SkAlphaType;
-        frameInfo->fDisposalMethod = frame->getDisposalMethod();
+        frame->fillIn(frameInfo, true);
     }
 
     return true;
diff --git a/src/codec/SkWuffsCodec.cpp b/src/codec/SkWuffsCodec.cpp
index 4fd2a04..8b828b2 100644
--- a/src/codec/SkWuffsCodec.cpp
+++ b/src/codec/SkWuffsCodec.cpp
@@ -156,7 +156,6 @@
 public:
     SkWuffsFrame(wuffs_base__frame_config* fc);
 
-    SkCodec::FrameInfo frameInfo(bool fullyReceived) const;
     uint64_t           ioPosition() const;
 
     // SkFrame overrides.
@@ -332,18 +331,8 @@
     this->setXYWH(r.min_incl_x, r.min_incl_y, r.width(), r.height());
     this->setDisposalMethod(wuffs_disposal_to_skia_disposal(fc->disposal()));
     this->setDuration(fc->duration() / WUFFS_BASE__FLICKS_PER_MILLISECOND);
-    this->setBlend(fc->overwrite_instead_of_blend() ? SkCodecAnimation::Blend::kBG
-                                                    : SkCodecAnimation::Blend::kPriorFrame);
-}
-
-SkCodec::FrameInfo SkWuffsFrame::frameInfo(bool fullyReceived) const {
-    SkCodec::FrameInfo ret;
-    ret.fRequiredFrame = getRequiredFrame();
-    ret.fDuration = getDuration();
-    ret.fFullyReceived = fullyReceived;
-    ret.fAlphaType = hasAlpha() ? kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
-    ret.fDisposalMethod = getDisposalMethod();
-    return ret;
+    this->setBlend(fc->overwrite_instead_of_blend() ? SkCodecAnimation::Blend::kSrc
+                                                    : SkCodecAnimation::Blend::kSrcOver);
 }
 
 uint64_t SkWuffsFrame::ioPosition() const {
@@ -854,7 +843,7 @@
         return false;
     }
     if (frameInfo) {
-        *frameInfo = f->frameInfo(static_cast<uint64_t>(i) < this->fNumFullyReceivedFrames);
+        f->fillIn(frameInfo, static_cast<uint64_t>(i) < this->fNumFullyReceivedFrames);
     }
     return true;
 }
diff --git a/src/utils/SkAnimCodecPlayer.cpp b/src/utils/SkAnimCodecPlayer.cpp
index e26ce38..0a33616 100644
--- a/src/utils/SkAnimCodecPlayer.cpp
+++ b/src/utils/SkAnimCodecPlayer.cpp
@@ -86,7 +86,7 @@
             // of transparent black, and then draw that through the origin matrix
             // onto the required frame. To do that, SkCodec needs to expose the
             // rectangle of the delta and the blend mode, so we can handle
-            // kRestoreBGColor frames and Blend::kBG.
+            // kRestoreBGColor frames and Blend::kSrc.
             SkMatrix inverse;
             SkAssertResult(originMatrix.invert(&inverse));
             canvas->concat(inverse);