blob: 9397ad9387211bc78e511fc1e89a1f9079189966 [file] [log] [blame]
// 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
}