1*c8dee2aaSAndroid Build Coastguard WorkerFrom 657f75b63a9c1d05a6d8dd2307c371ab304f968a Mon Sep 17 00:00:00 2001 2*c8dee2aaSAndroid Build Coastguard WorkerFrom: Lukasz Anforowicz <[email protected]> 3*c8dee2aaSAndroid Build Coastguard WorkerDate: Thu, 3 Oct 2024 19:52:22 +0000 4*c8dee2aaSAndroid Build Coastguard WorkerSubject: [PATCH 104/113] Simplify how `Reader` tracks how many frames remain 5*c8dee2aaSAndroid Build Coastguard Worker to be decoded. 6*c8dee2aaSAndroid Build Coastguard Worker 7*c8dee2aaSAndroid Build Coastguard WorkerIn an earlier commit 278b1d4fc1da9cebdeb511d8b106d239155c35cc we 8*c8dee2aaSAndroid Build Coastguard Workerstopped using `Reader.next_frame` for deciding whether to call 9*c8dee2aaSAndroid Build Coastguard Worker`read_until_image_data` from `next_frame`. This commit goes one 10*c8dee2aaSAndroid Build Coastguard Workerstep further and removes the `next_frame` field entirely. 11*c8dee2aaSAndroid Build Coastguard Worker 12*c8dee2aaSAndroid Build Coastguard WorkerThere are no known cases where the previous code would result 13*c8dee2aaSAndroid Build Coastguard Workerin incorrect behavior, but this commit still seems desirable: 14*c8dee2aaSAndroid Build Coastguard Worker 15*c8dee2aaSAndroid Build Coastguard Worker* It simplifies the code 16*c8dee2aaSAndroid Build Coastguard Worker* It ensures that a single "end-of-IDAT/fdAT-sequence" event kind 17*c8dee2aaSAndroid Build Coastguard Worker controls both 1) `consumed_and_flushed` state, and 2) counting 18*c8dee2aaSAndroid Build Coastguard Worker remaining frames. (Before this commit `next_frame` would also be 19*c8dee2aaSAndroid Build Coastguard Worker mutated after a separate "fcTL-encountered" event. And also after 20*c8dee2aaSAndroid Build Coastguard Worker "end-of-IDAT/fdAT-sequence" but only from `next_frame` and not from 21*c8dee2aaSAndroid Build Coastguard Worker `next_row`.) 22*c8dee2aaSAndroid Build Coastguard Worker--- 23*c8dee2aaSAndroid Build Coastguard Worker src/decoder/mod.rs | 80 +++++++++++++++++----------------------------- 24*c8dee2aaSAndroid Build Coastguard Worker 1 file changed, 29 insertions(+), 51 deletions(-) 25*c8dee2aaSAndroid Build Coastguard Worker 26*c8dee2aaSAndroid Build Coastguard Workerdiff --git a/third_party/rust/chromium_crates_io/vendor/png-0.17.14/src/decoder/mod.rs b/third_party/rust/chromium_crates_io/vendor/png-0.17.14/src/decoder/mod.rs 27*c8dee2aaSAndroid Build Coastguard Workerindex 56570b3..d0a88e8 100644 28*c8dee2aaSAndroid Build Coastguard Worker--- a/third_party/rust/chromium_crates_io/vendor/png-0.17.14/src/decoder/mod.rs 29*c8dee2aaSAndroid Build Coastguard Worker+++ b/third_party/rust/chromium_crates_io/vendor/png-0.17.14/src/decoder/mod.rs 30*c8dee2aaSAndroid Build Coastguard Worker@@ -205,8 +205,7 @@ impl<R: Read> Decoder<R> { 31*c8dee2aaSAndroid Build Coastguard Worker decoder: self.read_decoder, 32*c8dee2aaSAndroid Build Coastguard Worker bpp: BytesPerPixel::One, 33*c8dee2aaSAndroid Build Coastguard Worker subframe: SubframeInfo::not_yet_init(), 34*c8dee2aaSAndroid Build Coastguard Worker- fctl_read: 0, 35*c8dee2aaSAndroid Build Coastguard Worker- next_frame: SubframeIdx::Initial, 36*c8dee2aaSAndroid Build Coastguard Worker+ remaining_frames: 0, // Temporary value - fixed below after reading `acTL` and `fcTL`. 37*c8dee2aaSAndroid Build Coastguard Worker data_stream: Vec::new(), 38*c8dee2aaSAndroid Build Coastguard Worker prev_start: 0, 39*c8dee2aaSAndroid Build Coastguard Worker current_start: 0, 40*c8dee2aaSAndroid Build Coastguard Worker@@ -234,6 +233,19 @@ impl<R: Read> Decoder<R> { 41*c8dee2aaSAndroid Build Coastguard Worker } 42*c8dee2aaSAndroid Build Coastguard Worker 43*c8dee2aaSAndroid Build Coastguard Worker reader.read_until_image_data()?; 44*c8dee2aaSAndroid Build Coastguard Worker+ 45*c8dee2aaSAndroid Build Coastguard Worker+ reader.remaining_frames = match reader.info().animation_control.as_ref() { 46*c8dee2aaSAndroid Build Coastguard Worker+ None => 1, // No `acTL` => only expecting `IDAT` frame. 47*c8dee2aaSAndroid Build Coastguard Worker+ Some(animation) => { 48*c8dee2aaSAndroid Build Coastguard Worker+ let mut num_frames = animation.num_frames as usize; 49*c8dee2aaSAndroid Build Coastguard Worker+ if reader.info().frame_control.is_none() { 50*c8dee2aaSAndroid Build Coastguard Worker+ // No `fcTL` before `IDAT` => `IDAT` is not part of the animation, but 51*c8dee2aaSAndroid Build Coastguard Worker+ // represents an *extra*, default frame for non-APNG-aware decoders. 52*c8dee2aaSAndroid Build Coastguard Worker+ num_frames += 1; 53*c8dee2aaSAndroid Build Coastguard Worker+ } 54*c8dee2aaSAndroid Build Coastguard Worker+ num_frames 55*c8dee2aaSAndroid Build Coastguard Worker+ } 56*c8dee2aaSAndroid Build Coastguard Worker+ }; 57*c8dee2aaSAndroid Build Coastguard Worker Ok(reader) 58*c8dee2aaSAndroid Build Coastguard Worker } 59*c8dee2aaSAndroid Build Coastguard Worker 60*c8dee2aaSAndroid Build Coastguard Worker@@ -349,11 +361,8 @@ pub struct Reader<R: Read> { 61*c8dee2aaSAndroid Build Coastguard Worker decoder: ReadDecoder<R>, 62*c8dee2aaSAndroid Build Coastguard Worker bpp: BytesPerPixel, 63*c8dee2aaSAndroid Build Coastguard Worker subframe: SubframeInfo, 64*c8dee2aaSAndroid Build Coastguard Worker- /// Number of frame control chunks read. 65*c8dee2aaSAndroid Build Coastguard Worker- /// By the APNG specification the total number must equal the count specified in the animation 66*c8dee2aaSAndroid Build Coastguard Worker- /// control chunk. The IDAT image _may_ have such a chunk applying to it. 67*c8dee2aaSAndroid Build Coastguard Worker- fctl_read: u32, 68*c8dee2aaSAndroid Build Coastguard Worker- next_frame: SubframeIdx, 69*c8dee2aaSAndroid Build Coastguard Worker+ /// How many frames remain to be decoded. Decremented after each `IDAT` or `fdAT` sequence. 70*c8dee2aaSAndroid Build Coastguard Worker+ remaining_frames: usize, 71*c8dee2aaSAndroid Build Coastguard Worker /// Vec containing the uncompressed image data currently being processed. 72*c8dee2aaSAndroid Build Coastguard Worker data_stream: Vec<u8>, 73*c8dee2aaSAndroid Build Coastguard Worker /// Index in `data_stream` where the previous row starts. 74*c8dee2aaSAndroid Build Coastguard Worker@@ -386,19 +395,6 @@ struct SubframeInfo { 75*c8dee2aaSAndroid Build Coastguard Worker consumed_and_flushed: bool, 76*c8dee2aaSAndroid Build Coastguard Worker } 77*c8dee2aaSAndroid Build Coastguard Worker 78*c8dee2aaSAndroid Build Coastguard Worker-/// Denote a frame as given by sequence numbers. 79*c8dee2aaSAndroid Build Coastguard Worker-#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 80*c8dee2aaSAndroid Build Coastguard Worker-enum SubframeIdx { 81*c8dee2aaSAndroid Build Coastguard Worker- /// The initial frame in an IDAT chunk without fcTL chunk applying to it. 82*c8dee2aaSAndroid Build Coastguard Worker- /// Note that this variant precedes `Some` as IDAT frames precede fdAT frames and all fdAT 83*c8dee2aaSAndroid Build Coastguard Worker- /// frames must have a fcTL applying to it. 84*c8dee2aaSAndroid Build Coastguard Worker- Initial, 85*c8dee2aaSAndroid Build Coastguard Worker- /// An IDAT frame with fcTL or an fdAT frame. 86*c8dee2aaSAndroid Build Coastguard Worker- Some(u32), 87*c8dee2aaSAndroid Build Coastguard Worker- /// The past-the-end index. 88*c8dee2aaSAndroid Build Coastguard Worker- End, 89*c8dee2aaSAndroid Build Coastguard Worker-} 90*c8dee2aaSAndroid Build Coastguard Worker- 91*c8dee2aaSAndroid Build Coastguard Worker impl<R: Read> Reader<R> { 92*c8dee2aaSAndroid Build Coastguard Worker /// Reads all meta data until the next frame data starts. 93*c8dee2aaSAndroid Build Coastguard Worker /// Requires IHDR before the IDAT and fcTL before fdAT. 94*c8dee2aaSAndroid Build Coastguard Worker@@ -414,14 +410,6 @@ impl<R: Read> Reader<R> { 95*c8dee2aaSAndroid Build Coastguard Worker match state { 96*c8dee2aaSAndroid Build Coastguard Worker Some(Decoded::ChunkBegin(_, chunk::IDAT)) 97*c8dee2aaSAndroid Build Coastguard Worker | Some(Decoded::ChunkBegin(_, chunk::fdAT)) => break, 98*c8dee2aaSAndroid Build Coastguard Worker- Some(Decoded::FrameControl(_)) => { 99*c8dee2aaSAndroid Build Coastguard Worker- // The next frame is the one to which this chunk applies. 100*c8dee2aaSAndroid Build Coastguard Worker- self.next_frame = SubframeIdx::Some(self.fctl_read); 101*c8dee2aaSAndroid Build Coastguard Worker- // TODO: what about overflow here? That would imply there are more fctl chunks 102*c8dee2aaSAndroid Build Coastguard Worker- // than can be specified in the animation control but also that we have read 103*c8dee2aaSAndroid Build Coastguard Worker- // several gigabytes of data. 104*c8dee2aaSAndroid Build Coastguard Worker- self.fctl_read += 1; 105*c8dee2aaSAndroid Build Coastguard Worker- } 106*c8dee2aaSAndroid Build Coastguard Worker None => { 107*c8dee2aaSAndroid Build Coastguard Worker return Err(DecodingError::Format( 108*c8dee2aaSAndroid Build Coastguard Worker FormatErrorInner::MissingImageData.into(), 109*c8dee2aaSAndroid Build Coastguard Worker@@ -473,7 +461,7 @@ impl<R: Read> Reader<R> { 110*c8dee2aaSAndroid Build Coastguard Worker /// Output lines will be written in row-major, packed matrix with width and height of the read 111*c8dee2aaSAndroid Build Coastguard Worker /// frame (or subframe), all samples are in big endian byte order where this matters. 112*c8dee2aaSAndroid Build Coastguard Worker pub fn next_frame(&mut self, buf: &mut [u8]) -> Result<OutputInfo, DecodingError> { 113*c8dee2aaSAndroid Build Coastguard Worker- if self.next_frame == SubframeIdx::End { 114*c8dee2aaSAndroid Build Coastguard Worker+ if self.remaining_frames == 0 { 115*c8dee2aaSAndroid Build Coastguard Worker return Err(DecodingError::Parameter( 116*c8dee2aaSAndroid Build Coastguard Worker ParameterErrorKind::PolledAfterEndOfImage.into(), 117*c8dee2aaSAndroid Build Coastguard Worker )); 118*c8dee2aaSAndroid Build Coastguard Worker@@ -534,37 +522,27 @@ impl<R: Read> Reader<R> { 119*c8dee2aaSAndroid Build Coastguard Worker // Advance over the rest of data for this (sub-)frame. 120*c8dee2aaSAndroid Build Coastguard Worker self.finish_decoding()?; 121*c8dee2aaSAndroid Build Coastguard Worker 122*c8dee2aaSAndroid Build Coastguard Worker- // Advance our state to expect the next frame. 123*c8dee2aaSAndroid Build Coastguard Worker- let past_end_subframe = self 124*c8dee2aaSAndroid Build Coastguard Worker- .info() 125*c8dee2aaSAndroid Build Coastguard Worker- .animation_control() 126*c8dee2aaSAndroid Build Coastguard Worker- .map(|ac| ac.num_frames) 127*c8dee2aaSAndroid Build Coastguard Worker- .unwrap_or(0); 128*c8dee2aaSAndroid Build Coastguard Worker- self.next_frame = match self.next_frame { 129*c8dee2aaSAndroid Build Coastguard Worker- SubframeIdx::End => unreachable!("Next frame called when already at image end"), 130*c8dee2aaSAndroid Build Coastguard Worker- // Reached the end of non-animated image. 131*c8dee2aaSAndroid Build Coastguard Worker- SubframeIdx::Initial if past_end_subframe == 0 => SubframeIdx::End, 132*c8dee2aaSAndroid Build Coastguard Worker- // An animated image, expecting first subframe. 133*c8dee2aaSAndroid Build Coastguard Worker- SubframeIdx::Initial => SubframeIdx::Some(0), 134*c8dee2aaSAndroid Build Coastguard Worker- // This was the last subframe, slightly fuzzy condition in case of programmer error. 135*c8dee2aaSAndroid Build Coastguard Worker- SubframeIdx::Some(idx) if past_end_subframe <= idx + 1 => SubframeIdx::End, 136*c8dee2aaSAndroid Build Coastguard Worker- // Expecting next subframe. 137*c8dee2aaSAndroid Build Coastguard Worker- SubframeIdx::Some(idx) => SubframeIdx::Some(idx + 1), 138*c8dee2aaSAndroid Build Coastguard Worker- }; 139*c8dee2aaSAndroid Build Coastguard Worker- 140*c8dee2aaSAndroid Build Coastguard Worker Ok(output_info) 141*c8dee2aaSAndroid Build Coastguard Worker } 142*c8dee2aaSAndroid Build Coastguard Worker 143*c8dee2aaSAndroid Build Coastguard Worker+ fn mark_subframe_as_consumed_and_flushed(&mut self) { 144*c8dee2aaSAndroid Build Coastguard Worker+ assert!(self.remaining_frames > 0); 145*c8dee2aaSAndroid Build Coastguard Worker+ self.remaining_frames -= 1; 146*c8dee2aaSAndroid Build Coastguard Worker+ 147*c8dee2aaSAndroid Build Coastguard Worker+ self.subframe.consumed_and_flushed = true; 148*c8dee2aaSAndroid Build Coastguard Worker+ } 149*c8dee2aaSAndroid Build Coastguard Worker+ 150*c8dee2aaSAndroid Build Coastguard Worker /// Advance over the rest of data for this (sub-)frame. 151*c8dee2aaSAndroid Build Coastguard Worker /// Called after decoding the last row of a frame. 152*c8dee2aaSAndroid Build Coastguard Worker fn finish_decoding(&mut self) -> Result<(), DecodingError> { 153*c8dee2aaSAndroid Build Coastguard Worker- // Double-check that all rows of this frame have been decoded. 154*c8dee2aaSAndroid Build Coastguard Worker+ // Double-check that all rows of this frame have been decoded (i.e. that the potential 155*c8dee2aaSAndroid Build Coastguard Worker+ // `finish_decoding` call below won't be discarding any data). 156*c8dee2aaSAndroid Build Coastguard Worker assert!(self.subframe.current_interlace_info.is_none()); 157*c8dee2aaSAndroid Build Coastguard Worker 158*c8dee2aaSAndroid Build Coastguard Worker // Discard the remaining data in the current sequence of `IDAT` or `fdAT` chunks. 159*c8dee2aaSAndroid Build Coastguard Worker if !self.subframe.consumed_and_flushed { 160*c8dee2aaSAndroid Build Coastguard Worker self.decoder.finish_decoding()?; 161*c8dee2aaSAndroid Build Coastguard Worker- self.subframe.consumed_and_flushed = true; 162*c8dee2aaSAndroid Build Coastguard Worker+ self.mark_subframe_as_consumed_and_flushed(); 163*c8dee2aaSAndroid Build Coastguard Worker } 164*c8dee2aaSAndroid Build Coastguard Worker 165*c8dee2aaSAndroid Build Coastguard Worker Ok(()) 166*c8dee2aaSAndroid Build Coastguard Worker@@ -617,7 +595,7 @@ impl<R: Read> Reader<R> { 167*c8dee2aaSAndroid Build Coastguard Worker /// Read the rest of the image and chunks and finish up, including text chunks or others 168*c8dee2aaSAndroid Build Coastguard Worker /// This will discard the rest of the image if the image is not read already with [`Reader::next_frame`], [`Reader::next_row`] or [`Reader::next_interlaced_row`] 169*c8dee2aaSAndroid Build Coastguard Worker pub fn finish(&mut self) -> Result<(), DecodingError> { 170*c8dee2aaSAndroid Build Coastguard Worker- self.next_frame = SubframeIdx::End; 171*c8dee2aaSAndroid Build Coastguard Worker+ self.remaining_frames = 0; 172*c8dee2aaSAndroid Build Coastguard Worker self.data_stream.clear(); 173*c8dee2aaSAndroid Build Coastguard Worker self.current_start = 0; 174*c8dee2aaSAndroid Build Coastguard Worker self.prev_start = 0; 175*c8dee2aaSAndroid Build Coastguard Worker@@ -729,7 +707,7 @@ impl<R: Read> Reader<R> { 176*c8dee2aaSAndroid Build Coastguard Worker 177*c8dee2aaSAndroid Build Coastguard Worker match self.decoder.decode_next(&mut self.data_stream)? { 178*c8dee2aaSAndroid Build Coastguard Worker Some(Decoded::ImageData) => (), 179*c8dee2aaSAndroid Build Coastguard Worker- Some(Decoded::ImageDataFlushed) => self.subframe.consumed_and_flushed = true, 180*c8dee2aaSAndroid Build Coastguard Worker+ Some(Decoded::ImageDataFlushed) => self.mark_subframe_as_consumed_and_flushed(), 181*c8dee2aaSAndroid Build Coastguard Worker _ => (), 182*c8dee2aaSAndroid Build Coastguard Worker } 183*c8dee2aaSAndroid Build Coastguard Worker } 184*c8dee2aaSAndroid Build Coastguard Worker-- 185*c8dee2aaSAndroid Build Coastguard Worker2.47.0.rc0.187.ge670bccf7e-goog 186*c8dee2aaSAndroid Build Coastguard Worker 187