// Copyright 2026 International Digital Economy Academy
//
// 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
//
// http://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.
let max_paint_depth : Int = 64
fn resolve_offset(base : Int, rel : Int, data : BytesView) -> Result[Int, ColorError] {
let abs = base + rel
if abs < 0 || abs >= data.length() {
Err(UnexpectedEof)
} else {
Ok(abs)
}
}
fn parse_color_stop(
data : BytesView,
offset : Int,
has_var : Bool,
) -> Result[@paint.ColorStop, ColorError] {
let stop_offset = read_i16(data, offset)
let palette_index = read_u16_int(data, offset + 2)
let alpha = read_i16(data, offset + 4)
match (stop_offset, palette_index, alpha) {
(Err(err), _, _) => Err(err)
(_, Err(err), _) => Err(err)
(_, _, Err(err)) => Err(err)
(Ok(stop_offset), Ok(palette_index), Ok(alpha)) => {
let mut var_idx_base : @paint.VarIdx? = None
if has_var {
let var_idx = read_u32(data, offset + 6)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.ColorStop::{
offset: stop_offset,
palette_index,
alpha,
var_idx_base,
})
}
}
}
fn parse_color_line(
data : BytesView,
offset : Int,
has_var : Bool,
) -> Result[@paint.ColorLine, ColorError] {
let extend = read_u8_int(data, offset)
let count = read_u16_int(data, offset + 1)
match (extend, count) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(extend), Ok(count)) => {
if count < 0 {
return Err(InvalidFormat)
}
let stop_size = if has_var { 10 } else { 6 }
let stops_offset = offset + 3
if stops_offset + count * stop_size > data.length() {
return Err(UnexpectedEof)
}
let stops : Array[@paint.ColorStop] = []
for i in 0.. return Err(err)
Ok(value) => stops.push(value)
}
}
Ok(@paint.ColorLine::{ extend, stops })
}
}
}
fn parse_affine(
data : BytesView,
offset : Int,
has_var : Bool,
) -> Result[@paint.Affine2x3, ColorError] {
let xx = read_i32(data, offset)
let yx = read_i32(data, offset + 4)
let xy = read_i32(data, offset + 8)
let yy = read_i32(data, offset + 12)
let dx = read_i32(data, offset + 16)
let dy = read_i32(data, offset + 20)
match (xx, yx, xy, yy, dx, dy) {
(Err(err), _, _, _, _, _) => Err(err)
(_, Err(err), _, _, _, _) => Err(err)
(_, _, Err(err), _, _, _) => Err(err)
(_, _, _, Err(err), _, _) => Err(err)
(_, _, _, _, Err(err), _) => Err(err)
(_, _, _, _, _, Err(err)) => Err(err)
(Ok(xx), Ok(yx), Ok(xy), Ok(yy), Ok(dx), Ok(dy)) => {
let mut var_idx_base : @paint.VarIdx? = None
if has_var {
let var_idx = read_u32(data, offset + 24)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Affine2x3::{ xx, yx, xy, yy, dx, dy, var_idx_base })
}
}
}
fn parse_paint(
data : BytesView,
offset : Int,
depth : Int,
) -> Result[@paint.Paint, ColorError] {
if depth <= 0 {
return Err(InvalidFormat)
}
let format = read_u8_int(data, offset)
match format {
Err(err) => Err(err)
Ok(format) =>
match format {
1 => {
let num_layers = read_u8_int(data, offset + 1)
let first_layer_index = read_u32_int(data, offset + 2)
match (num_layers, first_layer_index) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(num_layers), Ok(first_layer_index)) =>
Ok(@paint.Paint::ColrLayers(first_layer_index, num_layers))
}
}
2 | 3 => {
let palette_index = read_u16_int(data, offset + 1)
let alpha = read_i16(data, offset + 3)
match (palette_index, alpha) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(palette_index), Ok(alpha)) => {
let mut var_idx_base : @paint.VarIdx? = None
if format == 3 {
let var_idx = read_u32(data, offset + 5)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::Solid(palette_index, alpha, var_idx_base))
}
}
}
4 | 5 => {
let color_line_offset = read_u24_int(data, offset + 1)
let x0 = read_i16(data, offset + 4)
let y0 = read_i16(data, offset + 6)
let x1 = read_i16(data, offset + 8)
let y1 = read_i16(data, offset + 10)
let x2 = read_i16(data, offset + 12)
let y2 = read_i16(data, offset + 14)
match (color_line_offset, x0, y0, x1, y1, x2, y2) {
(Err(err), _, _, _, _, _, _) => Err(err)
(_, Err(err), _, _, _, _, _) => Err(err)
(_, _, Err(err), _, _, _, _) => Err(err)
(_, _, _, Err(err), _, _, _) => Err(err)
(_, _, _, _, Err(err), _, _) => Err(err)
(_, _, _, _, _, Err(err), _) => Err(err)
(_, _, _, _, _, _, Err(err)) => Err(err)
(Ok(color_line_offset), Ok(x0), Ok(y0), Ok(x1), Ok(y1), Ok(x2), Ok(y2)) => {
let line_offset = match resolve_offset(offset, color_line_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let color_line = parse_color_line(data, line_offset, format == 5)
let color_line = match color_line {
Err(err) => return Err(err)
Ok(value) => value
}
let mut var_idx_base : @paint.VarIdx? = None
if format == 5 {
let var_idx = read_u32(data, offset + 16)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::LinearGradient(
color_line,
x0,
y0,
x1,
y1,
x2,
y2,
var_idx_base,
))
}
}
}
6 | 7 => {
let color_line_offset = read_u24_int(data, offset + 1)
let x0 = read_i16(data, offset + 4)
let y0 = read_i16(data, offset + 6)
let r0 = read_u16_int(data, offset + 8)
let x1 = read_i16(data, offset + 10)
let y1 = read_i16(data, offset + 12)
let r1 = read_u16_int(data, offset + 14)
match (color_line_offset, x0, y0, r0, x1, y1, r1) {
(Err(err), _, _, _, _, _, _) => Err(err)
(_, Err(err), _, _, _, _, _) => Err(err)
(_, _, Err(err), _, _, _, _) => Err(err)
(_, _, _, Err(err), _, _, _) => Err(err)
(_, _, _, _, Err(err), _, _) => Err(err)
(_, _, _, _, _, Err(err), _) => Err(err)
(_, _, _, _, _, _, Err(err)) => Err(err)
(Ok(color_line_offset), Ok(x0), Ok(y0), Ok(r0), Ok(x1), Ok(y1), Ok(r1)) => {
let line_offset = match resolve_offset(offset, color_line_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let color_line = parse_color_line(data, line_offset, format == 7)
let color_line = match color_line {
Err(err) => return Err(err)
Ok(value) => value
}
let mut var_idx_base : @paint.VarIdx? = None
if format == 7 {
let var_idx = read_u32(data, offset + 16)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::RadialGradient(
color_line,
x0,
y0,
r0,
x1,
y1,
r1,
var_idx_base,
))
}
}
}
8 | 9 => {
let color_line_offset = read_u24_int(data, offset + 1)
let center_x = read_i16(data, offset + 4)
let center_y = read_i16(data, offset + 6)
let start_angle = read_i16(data, offset + 8)
let end_angle = read_i16(data, offset + 10)
match (color_line_offset, center_x, center_y, start_angle, end_angle) {
(Err(err), _, _, _, _) => Err(err)
(_, Err(err), _, _, _) => Err(err)
(_, _, Err(err), _, _) => Err(err)
(_, _, _, Err(err), _) => Err(err)
(_, _, _, _, Err(err)) => Err(err)
(Ok(color_line_offset), Ok(center_x), Ok(center_y), Ok(start_angle), Ok(end_angle)) => {
let line_offset = match resolve_offset(offset, color_line_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let color_line = parse_color_line(data, line_offset, format == 9)
let color_line = match color_line {
Err(err) => return Err(err)
Ok(value) => value
}
let mut var_idx_base : @paint.VarIdx? = None
if format == 9 {
let var_idx = read_u32(data, offset + 12)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::SweepGradient(
color_line,
center_x,
center_y,
start_angle,
end_angle,
var_idx_base,
))
}
}
}
10 => {
let paint_offset = read_u24_int(data, offset + 1)
let glyph_id = read_u16_int(data, offset + 4)
match (paint_offset, glyph_id) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(paint_offset), Ok(glyph_id)) => {
let child_offset = match resolve_offset(offset, paint_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let child = parse_paint(data, child_offset, depth - 1)
match child {
Err(err) => Err(err)
Ok(child) => Ok(@paint.Paint::Glyph(glyph_id, child))
}
}
}
}
11 => {
let glyph_id = read_u16_int(data, offset + 1)
match glyph_id {
Err(err) => Err(err)
Ok(glyph_id) => Ok(@paint.Paint::ColrGlyph(glyph_id))
}
}
12 | 13 => {
let src_offset = read_u24_int(data, offset + 1)
let transform_offset = read_u24_int(data, offset + 4)
match (src_offset, transform_offset) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(src_offset), Ok(transform_offset)) => {
let src_abs = match resolve_offset(offset, src_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let transform_abs = match resolve_offset(offset, transform_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let src = parse_paint(data, src_abs, depth - 1)
let src = match src {
Err(err) => return Err(err)
Ok(value) => value
}
let transform = parse_affine(data, transform_abs, format == 13)
let transform = match transform {
Err(err) => return Err(err)
Ok(value) => value
}
Ok(@paint.Paint::Transform(transform, src))
}
}
}
14 | 15 => {
let src_offset = read_u24_int(data, offset + 1)
let dx = read_i16(data, offset + 4)
let dy = read_i16(data, offset + 6)
match (src_offset, dx, dy) {
(Err(err), _, _) => Err(err)
(_, Err(err), _) => Err(err)
(_, _, Err(err)) => Err(err)
(Ok(src_offset), Ok(dx), Ok(dy)) => {
let src_abs = match resolve_offset(offset, src_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let src = parse_paint(data, src_abs, depth - 1)
let src = match src {
Err(err) => return Err(err)
Ok(value) => value
}
let mut var_idx_base : @paint.VarIdx? = None
if format == 15 {
let var_idx = read_u32(data, offset + 8)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::Translate(dx, dy, var_idx_base, src))
}
}
}
16 | 17 => {
let src_offset = read_u24_int(data, offset + 1)
let scale_x = read_i16(data, offset + 4)
let scale_y = read_i16(data, offset + 6)
match (src_offset, scale_x, scale_y) {
(Err(err), _, _) => Err(err)
(_, Err(err), _) => Err(err)
(_, _, Err(err)) => Err(err)
(Ok(src_offset), Ok(scale_x), Ok(scale_y)) => {
let src_abs = match resolve_offset(offset, src_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let src = parse_paint(data, src_abs, depth - 1)
let src = match src {
Err(err) => return Err(err)
Ok(value) => value
}
let mut var_idx_base : @paint.VarIdx? = None
if format == 17 {
let var_idx = read_u32(data, offset + 8)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::Scale(scale_x, scale_y, var_idx_base, src))
}
}
}
18 | 19 => {
let src_offset = read_u24_int(data, offset + 1)
let scale_x = read_i16(data, offset + 4)
let scale_y = read_i16(data, offset + 6)
let center_x = read_i16(data, offset + 8)
let center_y = read_i16(data, offset + 10)
match (src_offset, scale_x, scale_y, center_x, center_y) {
(Err(err), _, _, _, _) => Err(err)
(_, Err(err), _, _, _) => Err(err)
(_, _, Err(err), _, _) => Err(err)
(_, _, _, Err(err), _) => Err(err)
(_, _, _, _, Err(err)) => Err(err)
(Ok(src_offset), Ok(scale_x), Ok(scale_y), Ok(center_x), Ok(center_y)) => {
let src_abs = match resolve_offset(offset, src_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let src = parse_paint(data, src_abs, depth - 1)
let src = match src {
Err(err) => return Err(err)
Ok(value) => value
}
let mut var_idx_base : @paint.VarIdx? = None
if format == 19 {
let var_idx = read_u32(data, offset + 12)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::ScaleAroundCenter(
scale_x,
scale_y,
center_x,
center_y,
var_idx_base,
src,
))
}
}
}
20 | 21 => {
let src_offset = read_u24_int(data, offset + 1)
let scale = read_i16(data, offset + 4)
match (src_offset, scale) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(src_offset), Ok(scale)) => {
let src_abs = match resolve_offset(offset, src_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let src = parse_paint(data, src_abs, depth - 1)
let src = match src {
Err(err) => return Err(err)
Ok(value) => value
}
let mut var_idx_base : @paint.VarIdx? = None
if format == 21 {
let var_idx = read_u32(data, offset + 6)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::ScaleUniform(scale, var_idx_base, src))
}
}
}
22 | 23 => {
let src_offset = read_u24_int(data, offset + 1)
let scale = read_i16(data, offset + 4)
let center_x = read_i16(data, offset + 6)
let center_y = read_i16(data, offset + 8)
match (src_offset, scale, center_x, center_y) {
(Err(err), _, _, _) => Err(err)
(_, Err(err), _, _) => Err(err)
(_, _, Err(err), _) => Err(err)
(_, _, _, Err(err)) => Err(err)
(Ok(src_offset), Ok(scale), Ok(center_x), Ok(center_y)) => {
let src_abs = match resolve_offset(offset, src_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let src = parse_paint(data, src_abs, depth - 1)
let src = match src {
Err(err) => return Err(err)
Ok(value) => value
}
let mut var_idx_base : @paint.VarIdx? = None
if format == 23 {
let var_idx = read_u32(data, offset + 10)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::ScaleUniformAroundCenter(
scale,
center_x,
center_y,
var_idx_base,
src,
))
}
}
}
24 | 25 => {
let src_offset = read_u24_int(data, offset + 1)
let angle = read_i16(data, offset + 4)
match (src_offset, angle) {
(Err(err), _) => Err(err)
(_, Err(err)) => Err(err)
(Ok(src_offset), Ok(angle)) => {
let src_abs = match resolve_offset(offset, src_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let src = parse_paint(data, src_abs, depth - 1)
let src = match src {
Err(err) => return Err(err)
Ok(value) => value
}
let mut var_idx_base : @paint.VarIdx? = None
if format == 25 {
let var_idx = read_u32(data, offset + 6)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::Rotate(angle, var_idx_base, src))
}
}
}
26 | 27 => {
let src_offset = read_u24_int(data, offset + 1)
let angle = read_i16(data, offset + 4)
let center_x = read_i16(data, offset + 6)
let center_y = read_i16(data, offset + 8)
match (src_offset, angle, center_x, center_y) {
(Err(err), _, _, _) => Err(err)
(_, Err(err), _, _) => Err(err)
(_, _, Err(err), _) => Err(err)
(_, _, _, Err(err)) => Err(err)
(Ok(src_offset), Ok(angle), Ok(center_x), Ok(center_y)) => {
let src_abs = match resolve_offset(offset, src_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let src = parse_paint(data, src_abs, depth - 1)
let src = match src {
Err(err) => return Err(err)
Ok(value) => value
}
let mut var_idx_base : @paint.VarIdx? = None
if format == 27 {
let var_idx = read_u32(data, offset + 10)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::RotateAroundCenter(
angle,
center_x,
center_y,
var_idx_base,
src,
))
}
}
}
28 | 29 => {
let src_offset = read_u24_int(data, offset + 1)
let x_skew = read_i16(data, offset + 4)
let y_skew = read_i16(data, offset + 6)
match (src_offset, x_skew, y_skew) {
(Err(err), _, _) => Err(err)
(_, Err(err), _) => Err(err)
(_, _, Err(err)) => Err(err)
(Ok(src_offset), Ok(x_skew), Ok(y_skew)) => {
let src_abs = match resolve_offset(offset, src_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let src = parse_paint(data, src_abs, depth - 1)
let src = match src {
Err(err) => return Err(err)
Ok(value) => value
}
let mut var_idx_base : @paint.VarIdx? = None
if format == 29 {
let var_idx = read_u32(data, offset + 8)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::Skew(x_skew, y_skew, var_idx_base, src))
}
}
}
30 | 31 => {
let src_offset = read_u24_int(data, offset + 1)
let x_skew = read_i16(data, offset + 4)
let y_skew = read_i16(data, offset + 6)
let center_x = read_i16(data, offset + 8)
let center_y = read_i16(data, offset + 10)
match (src_offset, x_skew, y_skew, center_x, center_y) {
(Err(err), _, _, _, _) => Err(err)
(_, Err(err), _, _, _) => Err(err)
(_, _, Err(err), _, _) => Err(err)
(_, _, _, Err(err), _) => Err(err)
(_, _, _, _, Err(err)) => Err(err)
(Ok(src_offset), Ok(x_skew), Ok(y_skew), Ok(center_x), Ok(center_y)) => {
let src_abs = match resolve_offset(offset, src_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let src = parse_paint(data, src_abs, depth - 1)
let src = match src {
Err(err) => return Err(err)
Ok(value) => value
}
let mut var_idx_base : @paint.VarIdx? = None
if format == 31 {
let var_idx = read_u32(data, offset + 12)
match var_idx {
Err(err) => return Err(err)
Ok(value) => var_idx_base = Some(value)
}
}
Ok(@paint.Paint::SkewAroundCenter(
x_skew,
y_skew,
center_x,
center_y,
var_idx_base,
src,
))
}
}
}
32 => {
let src_offset = read_u24_int(data, offset + 1)
let mode = read_u8_int(data, offset + 4)
let backdrop_offset = read_u24_int(data, offset + 5)
match (src_offset, mode, backdrop_offset) {
(Err(err), _, _) => Err(err)
(_, Err(err), _) => Err(err)
(_, _, Err(err)) => Err(err)
(Ok(src_offset), Ok(mode), Ok(backdrop_offset)) => {
let src_abs = match resolve_offset(offset, src_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let backdrop_abs = match resolve_offset(offset, backdrop_offset, data) {
Err(err) => return Err(err)
Ok(value) => value
}
let src = parse_paint(data, src_abs, depth - 1)
let src = match src {
Err(err) => return Err(err)
Ok(value) => value
}
let backdrop = parse_paint(data, backdrop_abs, depth - 1)
match backdrop {
Err(err) => Err(err)
Ok(backdrop) => Ok(@paint.Paint::Composite(mode, src, backdrop))
}
}
}
}
_ => Err(InvalidFormat)
}
}
}
fn parse_paint_root(
data : BytesView,
offset : Int,
) -> Result[@paint.Paint, ColorError] {
parse_paint(data, offset, max_paint_depth)
}