Skip to content

Commit 6aed883

Browse files
committed
feat: add woff impl
1 parent 511af82 commit 6aed883

File tree

6 files changed

+116
-37
lines changed

6 files changed

+116
-37
lines changed

src/table.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
const std = @import("std");
2-
const reader = @import("./byte_read.zig");
32

43
const Allocator = std.mem.Allocator;
54

src/unit_tests.zig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@ comptime {
44
_ = @import("table/mod.zig");
55
_ = @import("./lib.zig");
66
_ = @import("./byte_writer.zig");
7-
_ = @import("./woff/woff_v1.zig");
8-
_ = @import("./woff/woff_v2.zig");
7+
_ = @import("woff/mod.zig");
98
}

src/woff/impl.zig

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
const std = @import("std");
2+
3+
const Allocator = std.mem.Allocator;
4+
5+
const Woff = @This();
6+
7+
ptr: *anyopaque,
8+
9+
vtable: *const VTable,
10+
11+
pub const VTable = struct {
12+
as_woff: *const fn (*anyopaque) anyerror![]u8,
13+
};
14+
15+
pub fn as_woff(self: Woff) anyerror![]u8 {
16+
return self.vtable.as_woff(self.ptr);
17+
}
18+
19+
pub fn cast(self: Woff, comptime T: type) *T {
20+
return @ptrCast(@alignCast(self.ptr));
21+
}
22+
23+
pub const Compressor = *const fn (allocator: Allocator, data: []const u8) anyerror![]u8;
24+
25+
pub const Error = error{
26+
InvalidSfntVersion,
27+
CompressionFailed,
28+
};

src/woff/mod.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
pub const woff_v1 = @import("./woff_v1.zig");
22
pub const woff_v2 = @import("./woff_v2.zig");
3+
pub const woff_impl = @import("./impl.zig");
4+
5+
test {
6+
_ = woff_v1;
7+
_ = woff_v2;
8+
}

src/woff/woff_v1.zig

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
const std = @import("std");
22
const reader = @import("../byte_read.zig");
33
const mod = @import("../parser.zig");
4-
const Allocator = std.mem.Allocator;
54
const Head = @import("../table/head.zig");
65
const byte_writer = @import("../byte_writer.zig");
6+
const Impl = @import("./impl.zig");
77

88
const zlib = std.compress.zlib;
99
const fs = std.fs;
10+
const Allocator = std.mem.Allocator;
1011

1112
const Parser = mod.Parser;
1213
const ByteWriter = byte_writer.ByteWriter;
@@ -18,12 +19,8 @@ pub const Woff = struct {
1819

1920
allocator: Allocator,
2021
parser: *Parser,
21-
compressor: *const fn (allocator: Allocator, data: []const u8) anyerror![]u8,
22+
compressor: Impl.Compressor,
2223

23-
pub const Error = error{
24-
InvalidSfntVersion,
25-
CompressionFailed,
26-
};
2724
pub const TableRecord = struct {
2825
tag: mod.TableTag,
2926
offset: u32,
@@ -36,16 +33,25 @@ pub const Woff = struct {
3633
pub fn init(
3734
allocator: Allocator,
3835
parser: *Parser,
39-
compressor: *const fn (allocator: Allocator, data: []const u8) anyerror![]u8,
40-
) Self {
41-
return Self{
36+
compressor: Impl.Compressor,
37+
) Impl {
38+
const self = allocator.create(Self) catch unreachable;
39+
self.* = Self{
4240
.allocator = allocator,
4341
.parser = parser,
4442
.compressor = compressor,
4543
};
44+
return Impl{
45+
.ptr = self,
46+
.vtable = &.{
47+
.as_woff = as_woff,
48+
},
49+
};
4650
}
4751

48-
pub fn as_woff(self: *Self) ![]u8 {
52+
fn as_woff(ptr: *anyopaque) ![]u8 {
53+
const self: *Self = @ptrCast(@alignCast(ptr));
54+
defer self.allocator.destroy(self);
4955
var buffer = ByteWriter(u8).init(self.allocator);
5056

5157
try self.parser.reader.seek_to(0);
@@ -159,23 +165,15 @@ pub const Woff = struct {
159165
}
160166
};
161167

162-
pub fn ttf_to_woff_v1(
163-
allocator: Allocator,
164-
data: []u8,
165-
compressor: *const fn (allocator: Allocator, data: []const u8) anyerror![]u8,
166-
) ![]u8 {
168+
pub fn ttf_to_woff_v1(allocator: Allocator, data: []u8, compressor: Impl.Compressor) ![]u8 {
167169
var parser = try Parser.init(allocator, data);
168170
defer parser.deinit();
169171
try parser.parse();
170172
var woff = Woff.init(allocator, &parser, compressor);
171173
return woff.as_woff();
172174
}
173175

174-
pub fn ttf_woff_v1_with_parser(
175-
allocator: Allocator,
176-
parser: *Parser,
177-
compressor: *const fn (allocator: Allocator, data: []const u8) anyerror![]u8,
178-
) ![]u8 {
176+
pub fn ttf_woff_v1_with_parser(allocator: Allocator, parser: *Parser, compressor: Impl.Compressor) ![]u8 {
179177
var woff = Woff.init(allocator, parser, compressor);
180178
return woff.as_woff();
181179
}
@@ -194,7 +192,6 @@ fn mock_compressor(allocator: Allocator, data: []const u8) ![]u8 {
194192

195193
test "woff " {
196194
const allocator = std.testing.allocator;
197-
198195
const font_file_path = fs.path.join(allocator, &.{ "./", "fonts", "LXGWBright-Light.ttf" }) catch unreachable;
199196
defer allocator.free(font_file_path);
200197

src/woff/woff_v2.zig

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,70 @@
1-
const std = @import("std");
21
const brotli = @import("brotli");
2+
const std = @import("std");
3+
const reader = @import("../byte_read.zig");
4+
const mod = @import("../parser.zig");
5+
const Head = @import("../table/head.zig");
6+
const byte_writer = @import("../byte_writer.zig");
7+
const Impl = @import("./impl.zig");
38

4-
test "brotli round-trip encode/decode" {
5-
const allocator = std.testing.allocator;
6-
const input = "hello, world! this is a test for brotli encoder/decoder.";
9+
const Allocator = std.mem.Allocator;
710

8-
var encoder = try brotli.Encoder.init(allocator, .{});
9-
defer encoder.deinit();
10-
const compressed = try encoder.encode(input);
11+
const Parser = mod.Parser;
12+
const ByteWriter = byte_writer.ByteWriter;
13+
14+
// https://www.w3.org/TR/WOFF2/
15+
pub const Woff = struct {
16+
const Self = @This();
17+
18+
allocator: Allocator,
19+
parser: *Parser,
20+
compressor: *const fn (allocator: Allocator, data: []const u8) anyerror![]u8,
21+
22+
pub fn init(
23+
allocator: Allocator,
24+
parser: *Parser,
25+
compressor: *const fn (allocator: Allocator, data: []const u8) anyerror![]u8,
26+
) Impl {
27+
const self = allocator.create(Self) catch unreachable;
28+
self.* = Self{
29+
.allocator = allocator,
30+
.parser = parser,
31+
.compressor = compressor,
32+
};
33+
return Impl{
34+
.ptr = self,
35+
.vtable = &.{
36+
.as_woff = as_woff,
37+
},
38+
};
39+
}
1140

12-
var decoder = try brotli.Decoder.init(allocator, .{});
13-
defer decoder.deinit();
14-
const decompressed = try decoder.decode(compressed);
41+
fn as_woff(ptr: *anyopaque) ![]u8 {
42+
const self: *Self = @ptrCast(@alignCast(ptr));
43+
defer self.allocator.destroy(self);
44+
var buffer = ByteWriter(u8).init(self.allocator);
45+
try buffer.write(u8, 1, .big);
1546

16-
try std.testing.expectEqualStrings(input, decompressed);
47+
return buffer.to_owned_slice();
48+
}
49+
};
1750

18-
allocator.free(compressed);
19-
allocator.free(decompressed);
51+
pub fn ttf_to_woff_v2(allocator: Allocator, data: []u8, compressor: Impl.Compressor) ![]u8 {
52+
var parser = try Parser.init(allocator, data);
53+
defer parser.deinit();
54+
try parser.parse();
55+
var woff = Woff.init(allocator, &parser, compressor);
56+
return woff.as_woff();
57+
}
58+
59+
pub fn ttf_woff_v2_with_parser(allocator: Allocator, parser: *Parser, compressor: Impl.Compressor) ![]u8 {
60+
var woff = Woff.init(allocator, parser, compressor);
61+
return woff.as_woff();
62+
}
63+
64+
// brotli mock
65+
fn mock_compressor(allocator: Allocator, data: []const u8) anyerror![]u8 {
66+
var encoder = try brotli.Encoder.init(allocator, .{});
67+
defer encoder.deinit();
68+
const compressed = try encoder.encode(data);
69+
return compressed;
2070
}

0 commit comments

Comments
 (0)