| // Copyright 2020 The Wuffs Authors. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| pri func decoder.filter_and_swizzle!(dst: ptr base.pixel_buffer, workbuf: slice base.u8) base.status, | |
| choosy, | |
| { | |
| var dst_pixfmt : base.pixel_format | |
| var dst_bits_per_pixel : base.u32[..= 256] | |
| var dst_bytes_per_pixel : base.u64[..= 32] | |
| var dst_bytes_per_row0 : base.u64 | |
| var dst_bytes_per_row1 : base.u64 | |
| var dst_palette : slice base.u8 | |
| var tab : table base.u8 | |
| var y : base.u32 | |
| var dst : slice base.u8 | |
| var filter : base.u8 | |
| var curr_row : slice base.u8 | |
| var prev_row : slice base.u8 | |
| // TODO: the dst_pixfmt variable shouldn't be necessary. We should be able | |
| // to chain the two calls: "args.dst.pixel_format().bits_per_pixel()". | |
| dst_pixfmt = args.dst.pixel_format() | |
| dst_bits_per_pixel = dst_pixfmt.bits_per_pixel() | |
| if (dst_bits_per_pixel & 7) <> 0 { | |
| return base."#unsupported option" | |
| } | |
| dst_bytes_per_pixel = (dst_bits_per_pixel / 8) as base.u64 | |
| dst_bytes_per_row0 = (this.frame_rect_x0 as base.u64) * dst_bytes_per_pixel | |
| dst_bytes_per_row1 = (this.frame_rect_x1 as base.u64) * dst_bytes_per_pixel | |
| dst_palette = args.dst.palette_or_else(fallback: this.dst_palette[..]) | |
| tab = args.dst.plane(p: 0) | |
| if dst_bytes_per_row1 < tab.width() { | |
| tab = tab.subtable( | |
| min_incl_x: 0, | |
| min_incl_y: 0, | |
| max_incl_x: dst_bytes_per_row1, | |
| max_incl_y: tab.height()) | |
| } | |
| if dst_bytes_per_row0 < tab.width() { | |
| tab = tab.subtable( | |
| min_incl_x: dst_bytes_per_row0, | |
| min_incl_y: 0, | |
| max_incl_x: tab.width(), | |
| max_incl_y: tab.height()) | |
| } else { | |
| tab = tab.subtable( | |
| min_incl_x: 0, | |
| min_incl_y: 0, | |
| max_incl_x: 0, | |
| max_incl_y: 0) | |
| } | |
| y = this.frame_rect_y0 | |
| while y < this.frame_rect_y1 { | |
| assert y < 0x00FF_FFFF via "a < b: a < c; c <= b"(c: this.frame_rect_y1) | |
| dst = tab.row_u32(y: y) | |
| if 1 > args.workbuf.length() { | |
| return "#internal error: inconsistent workbuf length" | |
| } | |
| filter = args.workbuf[0] | |
| args.workbuf = args.workbuf[1 ..] | |
| if this.pass_bytes_per_row > args.workbuf.length() { | |
| return "#internal error: inconsistent workbuf length" | |
| } | |
| curr_row = args.workbuf[.. this.pass_bytes_per_row] | |
| args.workbuf = args.workbuf[this.pass_bytes_per_row ..] | |
| if filter == 0 { | |
| // No-op. | |
| } else if filter == 1 { | |
| this.filter_1!(curr: curr_row) | |
| } else if filter == 2 { | |
| this.filter_2!(curr: curr_row, prev: prev_row) | |
| } else if filter == 3 { | |
| this.filter_3!(curr: curr_row, prev: prev_row) | |
| } else if filter == 4 { | |
| this.filter_4!(curr: curr_row, prev: prev_row) | |
| } else { | |
| return "#bad filter" | |
| } | |
| this.swizzler.swizzle_interleaved_from_slice!( | |
| dst: dst, | |
| dst_palette: dst_palette, | |
| src: curr_row) | |
| prev_row = curr_row | |
| y += 1 | |
| } endwhile | |
| return ok | |
| } |