Skip to documentation
SLOP

tiny.gui.paint.command

Reference tiny.gui paint command

Defined in paint.

API (31)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

No direct callersNo direct callspaintcommand
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsprivate sourcelib.gui.src.paint.command.Recorderappendtest sourcelib.gui.src.paint.commandtest: CommandBuffer keeps a linear gr...private sourcelib.gui.src.paint.text.GlyphCommandWriterdrawGlyphprivate sourcelib.gui.src.paint.text.GlyphCommandWriterfillRectpaint.commandemptypaint.CommandBufferappend
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallstest sourcelib.gui.src.paint.accytest: Accy compositor matches recorde...test sourcelib.gui.src.paint.commandtest: CommandBuffer captures visual w...test sourcelib.gui.src.paint.commandtest: CommandBuffer records normalize...test sourcelib.gui.src.paint.commandtest: CommandBuffer reports allocatio...test sourcelib.gui.src.paint.commandtest: CommandBuffer scales chrome geo...test sourcelib.gui.src.paint.commandtest: CommandBuffer warmed frames nee...private sourcelib.gui.src.paint.command.Recorderinitpaint.CommandBufferappendFrame
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsprivate sourcelib.gui.src.paint.command.RecorderendFragmenttest sourcelib.gui.src.paint.texttest: warmed identical styled text me...test sourcelib.gui.src.paint.texttest: warmed mixed metric measure pla...private sourcelib.gui.src.paint.command.CommandBuffercoveredCommandCountprivate sourcelib.gui.src.paint.commandfragmentBoundspaint.CommandBuffercommitFragment
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callstest sourcelib.gui.src.paint.commandtest: CommandBuffer captures visual w...test sourcelib.gui.src.paint.commandtest: CommandBuffer keeps a linear gr...test sourcelib.gui.src.paint.commandtest: CommandBuffer records normalize...test sourcelib.gui.src.paint.commandtest: CommandBuffer reports allocatio...test sourcelib.gui.src.paint.commandtest: CommandBuffer scales chrome geo...test sourcelib.gui.src.paint.commandtest: CommandBuffer warmed frames nee...paint.CommandBufferdeinit
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callspaint.RetainedCommandspreparepaint.CommandBufferensureFragmentCapacity
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callstest sourcelib.gui.src.paint.commandtest: CommandBuffer captures visual w...test sourcelib.gui.src.paint.commandtest: CommandBuffer reports allocatio...test sourcelib.gui.src.paint.commandtest: CommandBuffer warmed frames nee...paint.RetainedCommandsdiffprivate sourcelib.gui.src.paint.retained.CommandsfragmentDamagepaint.CommandBufferfragmentItems
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.gui.src.paint.commandtest: CommandBuffer captures visual w...private sourcelib.gui.src.paint.command.CommandBuffercoveredCommandCountpaint.CommandBufferfragmentsComplete
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.gui.src.paint.commandtest: CommandBuffer captures visual w...test sourcelib.gui.src.paint.commandtest: CommandBuffer keeps a linear gr...test sourcelib.gui.src.paint.commandtest: CommandBuffer records normalize...test sourcelib.gui.src.paint.commandtest: CommandBuffer reports allocatio...test sourcelib.gui.src.paint.commandtest: CommandBuffer scales chrome geo...test sourcelib.gui.src.paint.commandtest: CommandBuffer warmed frames nee...paint.CommandBufferinit
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.gui.src.paint.accytest: Accy compositor matches recorde...test sourcelib.gui.src.paint.commandtest: CommandBuffer captures visual w...test sourcelib.gui.src.paint.commandtest: CommandBuffer keeps a linear gr...test sourcelib.gui.src.paint.commandtest: CommandBuffer records normalize...test sourcelib.gui.src.paint.commandtest: CommandBuffer reports allocatio...+18 morepaint.CommandBufferitems
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.gui.src.paint.commandtest: CommandBuffer warmed frames nee...test sourcelib.gui.src.paint.retainedtest: retained duplicate fragment ide...test sourcelib.gui.src.paint.texttest: multiline query geometry matche...paint.CommandBufferreset
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersprivate sourcelib.gui.src.paint.command.CommandBuffercoveredCommandCountpaint.CommandBufferrollback
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callstest sourcelib.gui.src.paint.commandtest: assignOrders preserves painter ...paint.commandassignOrders
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallspaint.commandvisibleBoundsprivate sourcelib.gui.src.paint.commandinsetpaint.commandbounds
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callspaint.CommandBufferappendprivate sourcelib.gui.src.paint.commandunionRectpaint.commandempty
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.gui.src.paint.command.RecorderbeginClippaint.commandvisibleBoundspaint.commandintersect
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate sourcelib.gui.src.paint.commandfragmentBoundsprivate sourcelib.gui.src.paint.retainedincludeCommandpaint.commandboundspaint.commandintersectpaint.commandvisibleBounds
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.gui.src.paint.retainedcommandDamageprivate sourcelib.gui.src.paint.retainedfragmentsEqualprivate sourcelib.gui.src.paint.retainedincludeChangedCommandspaint.commandvisuallyEqual
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/gui/src/paint/command.zig

zig
const std = @import("std");const gui = @import("../root.zig");const Allocator = std.mem.Allocator;const Color = gui.model.UiColor;const Gradient = gui.model.UiLinearGradient;pub const Image = gui.model.UiImage;pub const ImageSet = gui.model.UiImageSet;const Point = gui.model.UiPoint;const Rect = gui.layout.Rect;pub const Kind = enum(u32) {    fill = 1,    stroke = 2,    image = 3,    shadow = 4,    glyph = 5,    linear_gradient = 6,};pub const Options = struct {    visual: gui.visual.Options = .{},    scale: f32 = 1,};pub const fragment_namespace_widget: u32 = 1;pub const fragment_namespace_layer: u32 = 2;pub const fragment_part_chrome: u32 = 1;pub const fragment_part_text: u32 = 2;pub const FragmentId = struct {    root_id: u64,    element_id: u64,    namespace: u32,    part: u32,};pub const Fragment = struct {    id: FragmentId,    command_start: u32,    command_count: u32,    bounds: Rect,};pub const Command = struct {    kind: Kind,    rect: Rect,    clip: Rect,    source: Rect = .{},    color: Color,    color_end: Color = .{},    gradient_start: Point = .{},    gradient_end: Point = .{},    radius: f32 = 0,    width: f32 = 0,    image_index: u32 = 0,    order: u32 = 0,};pub const CommandBuffer = struct {    pub const Error = Allocator.Error || error{        InvalidFragmentStart,        TooManyCommands,    };    allocator: Allocator,    commands: std.ArrayListUnmanaged(Command) = .empty,    fragments: std.ArrayListUnmanaged(Fragment) = .empty,    pub fn init(allocator: Allocator) CommandBuffer {        return .{ .allocator = allocator };    }    pub fn deinit(self: *CommandBuffer) void {        self.commands.deinit(self.allocator);        self.fragments.deinit(self.allocator);        self.* = undefined;    }    pub fn reset(self: *CommandBuffer) void {        self.commands.clearRetainingCapacity();        self.fragments.clearRetainingCapacity();    }    pub fn ensureCapacity(self: *CommandBuffer, capacity: usize) Allocator.Error!void {        try self.commands.ensureTotalCapacity(self.allocator, capacity);    }    pub fn ensureFragmentCapacity(        self: *CommandBuffer,        capacity: usize,    ) Allocator.Error!void {        try self.fragments.ensureTotalCapacity(self.allocator, capacity);    }    pub fn items(self: *const CommandBuffer) []const Command {        return self.commands.items;    }    pub fn fragmentItems(self: *const CommandBuffer) []const Fragment {        return self.fragments.items;    }    pub fn fragmentsComplete(self: *const CommandBuffer) bool {        return self.coveredCommandCount() == self.commands.items.len;    }    pub fn commitFragment(        self: *CommandBuffer,        id: FragmentId,        command_start: usize,    ) Error!void {        if (command_start != self.coveredCommandCount()) {            return error.InvalidFragmentStart;        }        if (command_start > self.commands.items.len) {            return error.InvalidFragmentStart;        }        const command_count = self.commands.items.len - command_start;        if (command_count == 0) return;        const start = std.math.cast(u32, command_start) orelse            return error.TooManyCommands;        const count = std.math.cast(u32, command_count) orelse            return error.TooManyCommands;        try self.fragments.append(self.allocator, .{            .id = id,            .command_start = start,            .command_count = count,            .bounds = fragmentBounds(self.commands.items[command_start..]),        });    }    pub fn appendFrame(        self: *CommandBuffer,        frame: gui.model.UiFrame,        root_id: u64,        target_width: u32,        target_height: u32,        options: Options,    ) Error!void {        const command_start = self.commands.items.len;        const fragment_start = self.fragments.items.len;        errdefer {            self.commands.shrinkRetainingCapacity(command_start);            self.fragments.shrinkRetainingCapacity(fragment_start);        }        var recorder = Recorder.init(self, .{            .x = 0,            .y = 0,            .width = @floatFromInt(target_width),            .height = @floatFromInt(target_height),        }, options.scale);        gui.visual.drawFrame(&recorder, frame, root_id, options.visual);        std.debug.assert(recorder.fragment_start == null);        if (recorder.failure) |failure| return failure;    }    pub fn append(self: *CommandBuffer, raw: Command) Allocator.Error!void {        if (raw.kind == .linear_gradient) {            if (raw.color.a == 0 and raw.color_end.a == 0) return;        } else if (raw.color.a == 0) return;        if (empty(raw.rect) or empty(raw.clip)) return;        var paint = raw;        paint.order = @intCast(self.commands.items.len);        try self.commands.append(self.allocator, paint);    }    pub fn rollback(self: *CommandBuffer, len: usize) void {        std.debug.assert(self.coveredCommandCount() <= len);        self.commands.shrinkRetainingCapacity(len);    }    fn coveredCommandCount(self: *const CommandBuffer) usize {        const last = if (self.fragments.items.len == 0)            return 0        else            self.fragments.items[self.fragments.items.len - 1];        return @as(usize, last.command_start) + last.command_count;    }};pub fn assignOrders(commands: []Command) void {    for (commands, 0..) |*paint, index| {        paint.order = @intCast(index);    }}pub fn bounds(paint: Command) Rect {    return switch (paint.kind) {        .shadow => inset(paint.rect, -@max(paint.width, 0)),        else => paint.rect,    };}pub fn visibleBounds(paint: Command) Rect {    return intersect(bounds(paint), paint.clip);}pub fn visuallyEqual(left: Command, right: Command) bool {    return left.kind == right.kind and        std.meta.eql(left.rect, right.rect) and        std.meta.eql(left.clip, right.clip) and        std.meta.eql(left.source, right.source) and        std.meta.eql(left.color, right.color) and        std.meta.eql(left.color_end, right.color_end) and        std.meta.eql(left.gradient_start, right.gradient_start) and        std.meta.eql(left.gradient_end, right.gradient_end) and        left.radius == right.radius and        left.width == right.width and        left.image_index == right.image_index;}const Recorder = struct {    buffer: *CommandBuffer,    clips: [2]Rect,    clip_depth: u8 = 1,    scale: f32 = 1,    failure: ?CommandBuffer.Error = null,    fragment_start: ?usize = null,    fragment_id: FragmentId = undefined,    fn init(buffer: *CommandBuffer, target: Rect, scale: f32) Recorder {        return .{            .buffer = buffer,            .clips = .{ target, undefined },            .scale = scale,        };    }    fn scaledRect(self: *const Recorder, rect: Rect) Rect {        return .{            .x = rect.x * self.scale,            .y = rect.y * self.scale,            .width = rect.width * self.scale,            .height = rect.height * self.scale,        };    }    fn scaledGradientPoint(self: *const Recorder, rect: Rect, point: Point, fallback: Point) Point {        const x_unit = finiteOr(point.x, fallback.x);        const y_unit = finiteOr(point.y, fallback.y);        const fallback_x = rect.x + rect.width * fallback.x;        const fallback_y = rect.y + rect.height * fallback.y;        return .{            .x = finiteOr(rect.x + rect.width * x_unit, fallback_x) * self.scale,            .y = finiteOr(rect.y + rect.height * y_unit, fallback_y) * self.scale,        };    }    pub fn beginClip(self: *Recorder, rect: Rect) void {        std.debug.assert(self.clip_depth < self.clips.len);        self.clips[self.clip_depth] = intersect(self.activeClip(), self.scaledRect(rect));        self.clip_depth += 1;    }    pub fn endClip(self: *Recorder) void {        if (self.clip_depth > 1) self.clip_depth -= 1;    }    pub fn beginWidgetFragment(        self: *Recorder,        root_id: u64,        widget_id: u64,    ) void {        if (self.failure != null) return;        std.debug.assert(self.fragment_start == null);        self.fragment_start = self.buffer.commands.items.len;        self.fragment_id = .{            .root_id = root_id,            .element_id = widget_id,            .namespace = fragment_namespace_widget,            .part = fragment_part_chrome,        };    }    pub fn endFragment(self: *Recorder) void {        if (self.failure != null) {            self.fragment_start = null;            return;        }        const start = self.fragment_start orelse unreachable;        self.fragment_start = null;        self.buffer.commitFragment(self.fragment_id, start) catch |failure| {            self.failure = failure;        };    }    pub fn fillRect(self: *Recorder, rect: Rect, color: Color) void {        self.append(.{            .kind = .fill,            .rect = self.scaledRect(rect),            .clip = self.activeClip(),            .color = color,        });    }    pub fn fillRoundedRect(self: *Recorder, rect: Rect, radius: f32, segments: u32, color: Color) void {        _ = segments;        self.append(.{            .kind = .fill,            .rect = self.scaledRect(rect),            .clip = self.activeClip(),            .color = color,            .radius = radius * self.scale,        });    }    pub fn fillLinearGradient(self: *Recorder, rect: Rect, radius: f32, segments: u32, gradient: Gradient) void {        _ = segments;        self.append(.{            .kind = .linear_gradient,            .rect = self.scaledRect(rect),            .clip = self.activeClip(),            .color = gradient.start_color,            .color_end = gradient.end_color,            .gradient_start = self.scaledGradientPoint(rect, gradient.start, .{}),            .gradient_end = self.scaledGradientPoint(rect, gradient.end, .{ .x = 1 }),            .radius = @max(radius, 0) * self.scale,        });    }    pub fn strokeRect(self: *Recorder, rect: Rect, width: f32, color: Color) void {        self.append(.{            .kind = .stroke,            .rect = self.scaledRect(rect),            .clip = self.activeClip(),            .color = color,            .width = width * self.scale,        });    }    pub fn strokeRoundedRect(self: *Recorder, rect: Rect, radius: f32, segments: u32, width: f32, color: Color) void {        _ = segments;        self.append(.{            .kind = .stroke,            .rect = self.scaledRect(rect),            .clip = self.activeClip(),            .color = color,            .radius = radius * self.scale,            .width = width * self.scale,        });    }    pub fn drawImage(self: *Recorder, rect: Rect, image_index: u32, source: Rect, opacity: u8) void {        self.append(.{            .kind = .image,            .rect = self.scaledRect(rect),            .clip = self.activeClip(),            .source = source,            .color = .{ .r = 255, .g = 255, .b = 255, .a = opacity },            .image_index = image_index,        });    }    pub fn drawGlyph(self: *Recorder, rect: Rect, image_index: u32, source: Rect, color: Color) void {        self.append(.{            .kind = .glyph,            .rect = self.scaledRect(rect),            .clip = self.activeClip(),            .source = source,            .color = color,            .image_index = image_index,        });    }    pub fn shadowRoundedRect(self: *Recorder, rect: Rect, radius: f32, blur_radius: f32, spread: f32, offset_x: f32, offset_y: f32, color: Color) void {        const expanded = @max(spread, 0);        self.append(.{            .kind = .shadow,            .rect = self.scaledRect(.{                .x = rect.x + offset_x - expanded,                .y = rect.y + offset_y - expanded,                .width = rect.width + expanded * 2,                .height = rect.height + expanded * 2,            }),            .clip = self.activeClip(),            .color = color,            .radius = @max(radius + expanded, 0) * self.scale,            .width = @max(blur_radius, 0) * self.scale,        });    }    fn append(self: *Recorder, raw: Command) void {        if (self.failure != null) return;        self.buffer.append(raw) catch |failure| {            self.failure = failure;        };    }    fn activeClip(self: *const Recorder) Rect {        return self.clips[self.clip_depth - 1];    }};fn finiteOr(value: f32, fallback: f32) f32 {    return if (std.math.isFinite(value)) value else fallback;}fn fragmentBounds(commands: []const Command) Rect {    std.debug.assert(commands.len != 0);    var result = visibleBounds(commands[0]);    for (commands[1..]) |paint| {        result = unionRect(result, visibleBounds(paint));    }    return result;}pub fn intersect(left: Rect, right: Rect) Rect {    const x0 = @max(left.x, right.x);    const y0 = @max(left.y, right.y);    const x1 = @min(left.x + left.width, right.x + right.width);    const y1 = @min(left.y + left.height, right.y + right.height);    return .{        .x = x0,        .y = y0,        .width = @max(x1 - x0, 0),        .height = @max(y1 - y0, 0),    };}fn unionRect(left: Rect, right: Rect) Rect {    if (empty(left)) return right;    if (empty(right)) return left;    const x0 = @min(left.x, right.x);    const y0 = @min(left.y, right.y);    const x1 = @max(left.x + left.width, right.x + right.width);    const y1 = @max(left.y + left.height, right.y + right.height);    return .{        .x = x0,        .y = y0,        .width = x1 - x0,        .height = y1 - y0,    };}pub fn empty(rect: Rect) bool {    return rect.width <= 0 or rect.height <= 0;}fn inset(rect: Rect, value: f32) Rect {    return .{        .x = rect.x + value,        .y = rect.y + value,        .width = @max(rect.width - value * 2, 0),        .height = @max(rect.height - value * 2, 0),    };}test "CommandBuffer captures visual widget chrome commands" {    const allocator = std.testing.allocator;    const child = [_]gui.model.UiNode{.{        .widget_id = 2,        .kind = .button,        .paint = .{            .background = .{ .r = 200, .g = 10, .b = 20, .a = 255 },            .border = .{ .r = 0, .g = 0, .b = 0, .a = 255 },            .border_width = 1,            .shadow = .{                .color = .{ .r = 0, .g = 0, .b = 0, .a = 80 },                .offset_y = 1,                .blur_radius = 2,            },        },        .size = .{ .width = 12, .height = 8 },    }};    const surface = gui.model.UiSurfaceTree{        .available_size = .{ .width = 32, .height = 16 },        .root = .{            .widget_id = 1,            .children = child[0..],        },    };    var frame_workspace = gui.frame.Workspace.init(allocator);    defer frame_workspace.deinit();    const frame = try frame_workspace.buildSurface(&surface, .{});    var commands = CommandBuffer.init(allocator);    defer commands.deinit();    try commands.appendFrame(frame, 1, 32, 16, .{});    try std.testing.expect(commands.items().len >= 3);    try std.testing.expectEqual(Kind.shadow, commands.items()[0].kind);    try std.testing.expectEqual(Kind.fill, commands.items()[1].kind);    try std.testing.expectEqual(@as(u32, 0), commands.items()[0].order);    try std.testing.expectEqual(@as(u32, 1), commands.items()[1].order);    try std.testing.expect(commands.fragmentsComplete());    try std.testing.expectEqual(@as(usize, 1), commands.fragmentItems().len);    const fragment = commands.fragmentItems()[0];    try std.testing.expectEqual(FragmentId{        .root_id = 1,        .element_id = 2,        .namespace = fragment_namespace_widget,        .part = fragment_part_chrome,    }, fragment.id);    try std.testing.expectEqual(        Rect{ .width = 14, .height = 11 },        fragment.bounds,    );}test "CommandBuffer scales chrome geometry to device pixels" {    const allocator = std.testing.allocator;    const child = [_]gui.model.UiNode{.{        .widget_id = 2,        .kind = .button,        .paint = .{            .background = .{ .r = 200, .g = 10, .b = 20, .a = 255 },            .border = .{ .r = 0, .g = 0, .b = 0, .a = 255 },            .border_width = 1,            .corner_roundness = 3,        },        .size = .{ .width = 12, .height = 8 },    }};    const surface = gui.model.UiSurfaceTree{        .available_size = .{ .width = 32, .height = 16 },        .root = .{            .widget_id = 1,            .children = child[0..],        },    };    var frame_workspace = gui.frame.Workspace.init(allocator);    defer frame_workspace.deinit();    const frame = try frame_workspace.buildSurface(&surface, .{});    var logical = CommandBuffer.init(allocator);    defer logical.deinit();    try logical.appendFrame(frame, 1, 32, 16, .{});    var device = CommandBuffer.init(allocator);    defer device.deinit();    try device.appendFrame(frame, 1, 64, 32, .{ .scale = 2 });    try std.testing.expectEqual(logical.items().len, device.items().len);    for (logical.items(), device.items()) |one, two| {        try std.testing.expectEqual(one.kind, two.kind);        try std.testing.expectEqual(one.rect.x * 2, two.rect.x);        try std.testing.expectEqual(one.rect.y * 2, two.rect.y);        try std.testing.expectEqual(one.rect.width * 2, two.rect.width);        try std.testing.expectEqual(one.rect.height * 2, two.rect.height);        try std.testing.expectEqual(one.radius * 2, two.radius);        try std.testing.expectEqual(one.width * 2, two.width);        try std.testing.expectEqual(one.source.x, two.source.x);        try std.testing.expectEqual(one.source.width, two.source.width);    }}test "CommandBuffer records normalized linear gradient endpoints in device pixels" {    const gradient = gui.model.UiLinearGradient{        .start = .{ .x = 0.25, .y = 0.5 },        .end = .{ .x = 0.75, .y = 1 },        .start_color = .{ .r = 12, .g = 24, .b = 48, .a = 220 },        .end_color = .{ .r = 80, .g = 120, .b = 220, .a = 160 },    };    const child = [_]gui.model.UiNode{.{        .widget_id = 2,        .kind = .container,        .paint = .{            .linear_gradient = gradient,            .corner_roundness = 3,        },        .size = .{ .width = 12, .height = 8 },    }};    const surface = gui.model.UiSurfaceTree{        .available_size = .{ .width = 32, .height = 16 },        .root = .{ .widget_id = 1, .children = &child },    };    var frame_workspace = gui.frame.Workspace.init(std.testing.allocator);    defer frame_workspace.deinit();    const frame = try frame_workspace.buildSurface(&surface, .{});    var logical = CommandBuffer.init(std.testing.allocator);    defer logical.deinit();    try logical.appendFrame(frame, 1, 32, 16, .{});    var device = CommandBuffer.init(std.testing.allocator);    defer device.deinit();    try device.appendFrame(frame, 1, 64, 32, .{ .scale = 2 });    try std.testing.expectEqual(@as(usize, 1), logical.items().len);    const one = logical.items()[0];    const two = device.items()[0];    try std.testing.expectEqual(Kind.linear_gradient, one.kind);    try std.testing.expectEqual(gradient.start_color, one.color);    try std.testing.expectEqual(gradient.end_color, one.color_end);    try std.testing.expectEqual(Point{ .x = 3, .y = 4 }, one.gradient_start);    try std.testing.expectEqual(Point{ .x = 9, .y = 8 }, one.gradient_end);    try std.testing.expectEqual(Point{ .x = 6, .y = 8 }, two.gradient_start);    try std.testing.expectEqual(Point{ .x = 18, .y = 16 }, two.gradient_end);    try std.testing.expectEqual(@as(f32, 6), two.radius);}test "CommandBuffer keeps a linear gradient with transparent start color" {    var commands = CommandBuffer.init(std.testing.allocator);    defer commands.deinit();    try commands.append(.{        .kind = .linear_gradient,        .rect = .{ .width = 8, .height = 8 },        .clip = .{ .width = 8, .height = 8 },        .color = .{ .a = 0 },        .color_end = .{ .r = 40, .g = 80, .b = 120, .a = 255 },        .gradient_end = .{ .x = 8 },    });    try std.testing.expectEqual(@as(usize, 1), commands.items().len);}test "assignOrders preserves painter order" {    var commands = [_]Command{        .{            .kind = .fill,            .rect = .{ .x = 0, .y = 0, .width = 8, .height = 8 },            .clip = .{ .x = 0, .y = 0, .width = 20, .height = 20 },            .color = .{ .a = 255 },        },        .{            .kind = .fill,            .rect = .{ .x = 10, .y = 0, .width = 4, .height = 4 },            .clip = .{ .x = 0, .y = 0, .width = 20, .height = 20 },            .color = .{ .a = 255 },        },        .{            .kind = .fill,            .rect = .{ .x = 1, .y = 1, .width = 3, .height = 3 },            .clip = .{ .x = 0, .y = 0, .width = 20, .height = 20 },            .color = .{ .a = 255 },        },        .{            .kind = .shadow,            .rect = .{ .x = 12, .y = 1, .width = 2, .height = 2 },            .clip = .{ .x = 0, .y = 0, .width = 20, .height = 20 },            .color = .{ .a = 255 },            .width = 2,        },    };    assignOrders(commands[0..]);    try std.testing.expectEqual(@as(u32, 0), commands[0].order);    try std.testing.expectEqual(@as(u32, 1), commands[1].order);    try std.testing.expectEqual(@as(u32, 2), commands[2].order);    try std.testing.expectEqual(@as(u32, 3), commands[3].order);}test "CommandBuffer warmed frames need no backing allocation" {    const child = [_]gui.model.UiNode{.{        .widget_id = 2,        .size = .{ .width = 8, .height = 8 },        .paint = .{ .linear_gradient = .{            .start = .{ .x = 0.125, .y = 0.25 },            .end = .{ .x = 0.875, .y = 0.75 },            .start_color = .{ .r = 20, .g = 30, .b = 40, .a = 255 },            .end_color = .{ .r = 70, .g = 90, .b = 120, .a = 255 },        } },    }};    const surface = gui.model.UiSurfaceTree{        .available_size = .{ .width = 16, .height = 16 },        .root = .{ .widget_id = 1, .children = child[0..] },    };    var frame_workspace = gui.frame.Workspace.init(std.testing.allocator);    defer frame_workspace.deinit();    const frame = try frame_workspace.buildSurface(&surface, .{});    var failing = std.testing.FailingAllocator.init(std.testing.allocator, .{});    var commands = CommandBuffer.init(failing.allocator());    defer commands.deinit();    try commands.appendFrame(frame, 1, 16, 16, .{});    const storage = commands.items().ptr;    const fragment_storage = commands.fragmentItems().ptr;    failing.fail_index = failing.alloc_index;    failing.resize_fail_index = failing.resize_index;    for (0..8) |_| {        commands.reset();        try commands.appendFrame(frame, 1, 16, 16, .{});        try std.testing.expectEqual(@as(usize, 1), commands.items().len);        try std.testing.expectEqual(@as(usize, 1), commands.fragmentItems().len);        try std.testing.expectEqual(storage, commands.items().ptr);        try std.testing.expectEqual(fragment_storage, commands.fragmentItems().ptr);    }    try std.testing.expect(!failing.has_induced_failure);}test "CommandBuffer reports allocation failure and rolls back" {    const child = [_]gui.model.UiNode{.{        .widget_id = 2,        .size = .{ .width = 8, .height = 8 },        .paint = .{ .background = .{ .r = 20, .g = 30, .b = 40, .a = 255 } },    }};    const surface = gui.model.UiSurfaceTree{        .available_size = .{ .width = 16, .height = 16 },        .root = .{ .widget_id = 1, .children = child[0..] },    };    var frame_workspace = gui.frame.Workspace.init(std.testing.allocator);    defer frame_workspace.deinit();    const frame = try frame_workspace.buildSurface(&surface, .{});    var failing = std.testing.FailingAllocator.init(std.testing.allocator, .{ .fail_index = 0 });    var commands = CommandBuffer.init(failing.allocator());    defer commands.deinit();    try std.testing.expectError(error.OutOfMemory, commands.appendFrame(frame, 1, 16, 16, .{}));    try std.testing.expectEqual(@as(usize, 0), commands.items().len);    try std.testing.expectEqual(@as(usize, 0), commands.fragmentItems().len);    failing.fail_index = std.math.maxInt(usize);    try commands.appendFrame(frame, 1, 16, 16, .{});    try std.testing.expectEqual(@as(usize, 1), commands.items().len);    try std.testing.expectEqual(@as(usize, 1), commands.fragmentItems().len);}

Source: lib/gui/src/paint/root.zig:2

zig
pub const command = @import("command.zig");

Complete caller list for paint.CommandBuffer.items

23 direct callers.

Audit

Definitions32
Public names52
Members31
Version26.7.0
Revisiondaab053ee433