Prepare to add gif quirks
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index f04c0e3..7034209 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -3277,6 +3277,30 @@
wuffs_gif__decoder_workbuf_len_max_incl_worst_case //
WUFFS_BASE__POTENTIALLY_UNUSED = 1;
+#define WUFFS_GIF__QUIRK_IGNORE_TOO_MUCH_PIXEL_DATA 1041635329
+
+static const uint32_t //
+ wuffs_gif__quirk_ignore_too_much_pixel_data //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635329;
+
+#define WUFFS_GIF__QUIRK_IMAGE_BOUNDS_ARE_STRICT 1041635330
+
+static const uint32_t //
+ wuffs_gif__quirk_image_bounds_are_strict //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635330;
+
+#define WUFFS_GIF__QUIRK_INITIAL_BACKGROUND_IS_OPAQUE 1041635331
+
+static const uint32_t //
+ wuffs_gif__quirk_initial_background_is_opaque //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635331;
+
+#define WUFFS_GIF__QUIRK_REJECT_EMPTY_PALETTE 1041635332
+
+static const uint32_t //
+ wuffs_gif__quirk_reject_empty_palette //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635332;
+
// ---------------- Struct Declarations
typedef struct wuffs_gif__decoder__struct wuffs_gif__decoder;
@@ -3300,6 +3324,11 @@
// ---------------- Public Function Prototypes
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct //
+wuffs_gif__decoder__set_quirk_enabled(wuffs_gif__decoder* self,
+ uint32_t a_quirk,
+ bool a_enabled);
+
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_image_config(wuffs_gif__decoder* self,
wuffs_base__image_config* a_dst,
@@ -3384,6 +3413,10 @@
uint32_t f_metadata_fourcc_value;
uint64_t f_metadata_chunk_length_value;
uint64_t f_metadata_io_position;
+ bool f_quirk_enabled_ignore_too_much_pixel_data;
+ bool f_quirk_enabled_image_bounds_are_strict;
+ bool f_quirk_enabled_initial_background_is_opaque;
+ bool f_quirk_enabled_reject_empty_palette;
bool f_end_of_data;
bool f_restarted;
bool f_previous_lzw_decode_ended_abruptly;
@@ -3508,6 +3541,11 @@
initialize_flags);
}
+ inline wuffs_base__empty_struct //
+ set_quirk_enabled(uint32_t a_quirk, bool a_enabled) {
+ return wuffs_gif__decoder__set_quirk_enabled(this, a_quirk, a_enabled);
+ }
+
inline wuffs_base__status //
decode_image_config(wuffs_base__image_config* a_dst,
wuffs_base__io_reader a_src) {
@@ -8655,6 +8693,31 @@
// ---------------- Function Implementations
+// -------- func gif.decoder.set_quirk_enabled
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct //
+wuffs_gif__decoder__set_quirk_enabled(wuffs_gif__decoder* self,
+ uint32_t a_quirk,
+ bool a_enabled) {
+ if (!self) {
+ return wuffs_base__make_empty_struct();
+ }
+ if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
+ return wuffs_base__make_empty_struct();
+ }
+
+ if (a_quirk == 1041635329) {
+ self->private_impl.f_quirk_enabled_ignore_too_much_pixel_data = a_enabled;
+ } else if (a_quirk == 1041635330) {
+ self->private_impl.f_quirk_enabled_image_bounds_are_strict = a_enabled;
+ } else if (a_quirk == 1041635331) {
+ self->private_impl.f_quirk_enabled_initial_background_is_opaque = a_enabled;
+ } else if (a_quirk == 1041635332) {
+ self->private_impl.f_quirk_enabled_reject_empty_palette = a_enabled;
+ }
+ return wuffs_base__make_empty_struct();
+}
+
// -------- func gif.decoder.decode_image_config
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
diff --git a/std/gif/decode_gif.wuffs b/std/gif/decode_gif.wuffs
index fa09513..3a15ebb 100644
--- a/std/gif/decode_gif.wuffs
+++ b/std/gif/decode_gif.wuffs
@@ -27,6 +27,41 @@
// need a per-pixel-row workbuf.
pub const decoder_workbuf_len_max_incl_worst_case base.u64 = 1
+// --------
+
+// Quirks.
+//
+// A base38 (github.com/google/wuffs/lib/base38) value can fit in 21 bits.
+// Leaving the high bit of a uint32 reserved, the low 10 bits can be used for
+// package-specific quirk constants: the base38 value acts as a namespace.
+
+// The base38 encoding of "gif " is 0xF8586.
+
+// When this quirk is enabled, silently ignore e.g. a frame that reports a
+// width and height of 6 pixels each, followed by 50 pixel values. In that
+// case, we process the first 36 pixel values and discard the excess 14.
+pub const quirk_ignore_too_much_pixel_data base.u32 = (0xF8586 << 10) | 1
+
+// When this quirk is enabled, if the initial frame bounds extends beyond the
+// image bounds, then the image bounds stay unchanged. By default (with this
+// quirk disabled), the image bounds are adjusted to always contain the first
+// frame's bounds (but not necessarily subsequent frame's bounds).
+//
+// For more discussion, see
+// https://github.com/google/wuffs/blob/master/test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt
+pub const quirk_image_bounds_are_strict base.u32 = (0xF8586 << 10) | 2
+
+// When this quirk is enabled, if the initial frame bounds is smaller than the
+// image bounds, those pixels outside the initial frame bounds are assumed to
+// start as opaque black instead of transparent black.
+pub const quirk_initial_background_is_opaque base.u32 = (0xF8586 << 10) | 3
+
+// When this quirk is enabled, a frame with no explicit palette is rejected,
+// instead of implicitly having a palette with every entry being opaque black.
+pub const quirk_reject_empty_palette base.u32 = (0xF8586 << 10) | 4
+
+// --------
+
// See the spec appendix E "Interlaced Images" on page 29. The first element
// represents either that the frame was non-interlaced, or that all interlace
// stages are complete. Otherwise, the four interlace stages are elements 4, 3,
@@ -91,6 +126,11 @@
metadata_chunk_length_value base.u64,
metadata_io_position base.u64,
+ quirk_enabled_ignore_too_much_pixel_data base.bool,
+ quirk_enabled_image_bounds_are_strict base.bool,
+ quirk_enabled_initial_background_is_opaque base.bool,
+ quirk_enabled_reject_empty_palette base.bool,
+
end_of_data base.bool,
restarted base.bool,
previous_lzw_decode_ended_abruptly base.bool,
@@ -143,6 +183,18 @@
lzw lzw.decoder,
)
+pub func decoder.set_quirk_enabled!(quirk base.u32, enabled base.bool) {
+ if args.quirk == quirk_ignore_too_much_pixel_data {
+ this.quirk_enabled_ignore_too_much_pixel_data = args.enabled
+ } else if args.quirk == quirk_image_bounds_are_strict {
+ this.quirk_enabled_image_bounds_are_strict = args.enabled
+ } else if args.quirk == quirk_initial_background_is_opaque {
+ this.quirk_enabled_initial_background_is_opaque = args.enabled
+ } else if args.quirk == quirk_reject_empty_palette {
+ this.quirk_enabled_reject_empty_palette = args.enabled
+ }
+}
+
pub func decoder.decode_image_config?(dst nptr base.image_config, src base.io_reader) {
var ffio base.bool