diff --git a/build.zig b/build.zig index 24a58d14c..c788e6e2e 100644 --- a/build.zig +++ b/build.zig @@ -12,6 +12,7 @@ const libuv = @import("pkg/libuv/build.zig"); const libpng = @import("pkg/libpng/build.zig"); const macos = @import("pkg/macos/build.zig"); const objc = @import("pkg/objc/build.zig"); +const pixman = @import("pkg/pixman/build.zig"); const stb_image_resize = @import("pkg/stb_image_resize/build.zig"); const utf8proc = @import("pkg/utf8proc/build.zig"); const zlib = @import("pkg/zlib/build.zig"); @@ -307,6 +308,10 @@ fn addDeps( }); system_sdk.include(b, harfbuzz_step, .{}); + // Pixman + const pixman_step = try pixman.link(b, step, .{}); + _ = pixman_step; + // Libuv const libuv_step = try libuv.link(b, step); system_sdk.include(b, libuv_step, .{}); diff --git a/pkg/pixman/build.zig b/pkg/pixman/build.zig index bb5be82dd..2ec6a0da6 100644 --- a/pkg/pixman/build.zig +++ b/pkg/pixman/build.zig @@ -22,10 +22,10 @@ pub const Options = struct {}; pub fn build(b: *std.build.Builder) !void { const target = b.standardTargetOptions(.{}); const mode = b.standardReleaseOptions(); - _ = target; - _ = mode; const tests = b.addTestExe("pixman-test", "main.zig"); + tests.setBuildMode(mode); + tests.setTarget(target); _ = try link(b, tests, .{}); tests.install(); diff --git a/pkg/pixman/c.zig b/pkg/pixman/c.zig new file mode 100644 index 000000000..04972bc40 --- /dev/null +++ b/pkg/pixman/c.zig @@ -0,0 +1,3 @@ +pub usingnamespace @cImport({ + @cInclude("pixman.h"); +}); diff --git a/pkg/pixman/format.zig b/pkg/pixman/format.zig new file mode 100644 index 000000000..ef949509c --- /dev/null +++ b/pkg/pixman/format.zig @@ -0,0 +1,109 @@ +const std = @import("std"); +const c = @import("c.zig"); +const pixman = @import("main.zig"); + +pub const FormatCode = enum(c_uint) { + // 128bpp formats + rgba_float = c.PIXMAN_FORMAT_BYTE(128, c.PIXMAN_TYPE_RGBA_FLOAT, 32, 32, 32, 32), + + // 96bpp formats + rgb_float = c.PIXMAN_FORMAT_BYTE(96, c.PIXMAN_TYPE_RGBA_FLOAT, 0, 32, 32, 32), + + // 32bpp formats + a8r8g8b8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ARGB, 8, 8, 8, 8), + x8r8g8b8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ARGB, 0, 8, 8, 8), + a8b8g8r8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ABGR, 8, 8, 8, 8), + x8b8g8r8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ABGR, 0, 8, 8, 8), + b8g8r8a8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_BGRA, 8, 8, 8, 8), + b8g8r8x8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_BGRA, 0, 8, 8, 8), + r8g8b8a8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_RGBA, 8, 8, 8, 8), + r8g8b8x8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_RGBA, 0, 8, 8, 8), + x14r6g6b6 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ARGB, 0, 6, 6, 6), + x2r10g10b10 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ARGB, 0, 10, 10, 10), + a2r10g10b10 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ARGB, 2, 10, 10, 10), + x2b10g10r10 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ABGR, 0, 10, 10, 10), + a2b10g10r10 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ABGR, 2, 10, 10, 10), + + // sRGB formats + a8r8g8b8_sRGB = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ARGB_SRGB, 8, 8, 8, 8), + r8g8b8_sRGB = c.PIXMAN_FORMAT(24, c.PIXMAN_TYPE_ARGB_SRGB, 0, 8, 8, 8), + + // 24bpp formats + r8g8b8 = c.PIXMAN_FORMAT(24, c.PIXMAN_TYPE_ARGB, 0, 8, 8, 8), + b8g8r8 = c.PIXMAN_FORMAT(24, c.PIXMAN_TYPE_ABGR, 0, 8, 8, 8), + + // 16bpp formats + r5g6b5 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ARGB, 0, 5, 6, 5), + b5g6r5 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ABGR, 0, 5, 6, 5), + + a1r5g5b5 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ARGB, 1, 5, 5, 5), + x1r5g5b5 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ARGB, 0, 5, 5, 5), + a1b5g5r5 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ABGR, 1, 5, 5, 5), + x1b5g5r5 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ABGR, 0, 5, 5, 5), + a4r4g4b4 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ARGB, 4, 4, 4, 4), + x4r4g4b4 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ARGB, 0, 4, 4, 4), + a4b4g4r4 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ABGR, 4, 4, 4, 4), + x4b4g4r4 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ABGR, 0, 4, 4, 4), + + // 8bpp formats + a8 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_A, 8, 0, 0, 0), + r3g3b2 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_ARGB, 0, 3, 3, 2), + b2g3r3 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_ABGR, 0, 3, 3, 2), + a2r2g2b2 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_ARGB, 2, 2, 2, 2), + a2b2g2r2 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_ABGR, 2, 2, 2, 2), + + c8 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_COLOR, 0, 0, 0, 0), + g8 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_GRAY, 0, 0, 0, 0), + + x4a4 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_A, 4, 0, 0, 0), + + // c8/g8 equivalent + // x4c4 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_COLOR, 0, 0, 0, 0), + // x4g4 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_GRAY, 0, 0, 0, 0), + + // 4bpp formats + a4 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_A, 4, 0, 0, 0), + r1g2b1 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_ARGB, 0, 1, 2, 1), + b1g2r1 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_ABGR, 0, 1, 2, 1), + a1r1g1b1 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_ARGB, 1, 1, 1, 1), + a1b1g1r1 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_ABGR, 1, 1, 1, 1), + + c4 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_COLOR, 0, 0, 0, 0), + g4 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_GRAY, 0, 0, 0, 0), + + // 1bpp formats + a1 = c.PIXMAN_FORMAT(1, c.PIXMAN_TYPE_A, 1, 0, 0, 0), + + g1 = c.PIXMAN_FORMAT(1, c.PIXMAN_TYPE_GRAY, 0, 0, 0, 0), + + // YUV formats + yuy2 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_YUY2, 0, 0, 0, 0), + yv12 = c.PIXMAN_FORMAT(12, c.PIXMAN_TYPE_YV12, 0, 0, 0, 0), + + pub inline fn bpp(self: FormatCode) u32 { + return self.reshift(24, 8); + } + + /// Calculates a valid stride for the bpp and width. Based on Cairo. + pub fn strideForWidth(self: FormatCode, width: u32) c_int { + const alignment = @sizeOf(u32); + const val = @intCast(c_int, (self.bpp() * width + 7) / 8); + return val + (alignment - 1) & -alignment; + } + + // Converted from pixman.h + fn reshift(self: FormatCode, ofs: u5, num: u5) u32 { + const val = @enumToInt(self); + const v1 = val >> ofs; + const v2 = @as(c_uint, 1) << num; + const v3 = @intCast(u5, val >> 22); + return ((v1 & (v2 - 1)) << (v3 & 3)); + } +}; + +test "bpp" { + const testing = std.testing; + + try testing.expectEqual(@as(u32, 1), FormatCode.g1.bpp()); + try testing.expectEqual(@as(u32, 4), FormatCode.g4.bpp()); +} diff --git a/pkg/pixman/image.zig b/pkg/pixman/image.zig new file mode 100644 index 000000000..967701e17 --- /dev/null +++ b/pkg/pixman/image.zig @@ -0,0 +1,38 @@ +const std = @import("std"); +const c = @import("c.zig"); +const pixman = @import("main.zig"); + +pub const Image = opaque { + pub inline fn createBitsNoClear( + format: pixman.FormatCode, + width: c_int, + height: c_int, + bits: [*]u32, + stride: c_int, + ) ?*Image { + return @ptrCast(?*Image, c.pixman_image_create_bits_no_clear( + @enumToInt(format), + width, + height, + bits, + stride, + )); + } + + pub inline fn unref(self: *Image) bool { + return c.pixman_image_unref(@ptrCast(*c.pixman_image_t, self)) == 1; + } +}; + +test "create and destroy" { + const testing = std.testing; + + const width = 10; + const height = 10; + const format: pixman.FormatCode = .g1; + const stride = format.strideForWidth(width); + var bits: [width * height]u32 = undefined; + const img = Image.createBitsNoClear(.g1, width, height, &bits, stride); + try testing.expect(img != null); + try testing.expect(img.?.unref()); +} diff --git a/pkg/pixman/main.zig b/pkg/pixman/main.zig index c12b911fb..c14cb5c6c 100644 --- a/pkg/pixman/main.zig +++ b/pkg/pixman/main.zig @@ -1,4 +1,7 @@ const std = @import("std"); +pub const c = @import("c.zig"); +pub usingnamespace @import("format.zig"); +pub usingnamespace @import("image.zig"); test { std.testing.refAllDecls(@This());