Skip to content

Commit 74d0903

Browse files
committed
stash code
1 parent 14f8e58 commit 74d0903

File tree

1 file changed

+165
-18
lines changed

1 file changed

+165
-18
lines changed

src/lib2.zig

Lines changed: 165 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ const Allocator = std.mem.Allocator;
88

99
const Parser = parser.Parser;
1010

11+
const UTF8 = std.unicode.Utf8View;
12+
1113
const Writer = byte_writer.ByteWriter;
1214

1315
const AutoHashMap = std.AutoHashMap;
@@ -102,11 +104,16 @@ pub const BoundingBox = struct {
102104
}
103105
};
104106

107+
const GlyphInfo = struct {
108+
bbox: BoundingBox,
109+
is_composite: bool,
110+
};
111+
105112
pub const Glyph = struct {
106113
id: u16 = 0,
107114
advance_width: u16 = 0,
108115
left_side_bearing: i16 = 0,
109-
data: []const u8 = &[_]u8{},
116+
is_composite: bool = false,
110117
bbox: BoundingBox = BoundingBox.empty(),
111118
has_outline: bool = false,
112119
_initialized: bool = false,
@@ -120,6 +127,11 @@ pub const Glyph = struct {
120127
}
121128
};
122129

130+
pub const BuildSubsetterOptions = struct {
131+
modified_time: ?i64 = null,
132+
input_text: []const u8 = &[_]u8{},
133+
};
134+
123135
const Reader = struct {
124136
const Self = @This();
125137

@@ -201,34 +213,40 @@ const Reader = struct {
201213
const hmtx = hmtx_table.cast(table.Hmtx);
202214
const metrics = hmtx.get_metrics(gid);
203215

204-
const bbox = blk: {
205-
const loca_table = self.t.parser.parsed_tables.loca.?;
206-
const loca = loca_table.cast(table.Loca);
216+
const loca_table = self.t.parser.parsed_tables.loca.?;
217+
const loca = loca_table.cast(table.Loca);
218+
const has_outline = loca.has_glyph_data(gid);
219+
220+
const glyph_info = if (has_outline) info: {
207221
const glyf_table = self.t.parser.parsed_tables.glyf.?;
208222
const glyf = glyf_table.cast(table.Glyf);
209223
const offset = loca.get_glyph_offset(gid).?;
210224
const parsed_glyf = try glyf.parse_glyph(offset);
211225
defer parsed_glyf.deinit();
212226
const header = parsed_glyf.get_header();
213-
break :blk BoundingBox{
227+
const bbox = BoundingBox{
214228
.x_min = header.x_min,
215229
.y_min = header.y_min,
216230
.x_max = header.x_max,
217231
.y_max = header.y_max,
218232
};
233+
const is_composite = header.is_composite();
234+
break :info GlyphInfo{
235+
.bbox = bbox,
236+
.is_composite = is_composite,
237+
};
238+
} else GlyphInfo{
239+
.bbox = BoundingBox.empty(),
240+
.is_composite = false,
219241
};
220242

221-
const has_outline = blk: {
222-
const loca_table = self.t.parser.parsed_tables.loca.?;
223-
const loca = loca_table.cast(table.Loca);
224-
break :blk loca.has_glyph_data(gid);
225-
};
226243
var glyh = Glyph{
227244
.id = gid,
228245
.advance_width = metrics.advance_width,
229246
.left_side_bearing = metrics.left_side_bearing,
230247
.has_outline = has_outline,
231-
.bbox = bbox,
248+
.bbox = glyph_info.bbox,
249+
.is_composite = glyph_info.is_composite,
232250
};
233251
glyh.mark_as_done();
234252
try self.glyph_cache.put(code_point, glyh);
@@ -243,9 +261,10 @@ const Subsetter = struct {
243261
allocator: Allocator,
244262
const Self = @This();
245263

246-
pub fn init(t: *ttf) Subsetter {
264+
pub fn init(t: *ttf) !Subsetter {
247265
return Self{
248266
.t = t,
267+
.r = try t.reader(),
249268
.allocator = t.allocator,
250269
};
251270
}
@@ -254,23 +273,151 @@ const Subsetter = struct {
254273

255274
}
256275

257-
pub fn build_subset(self: *Self) ![]u8 {
276+
pub fn build_subset(self: *Self, options: BuildSubsetterOptions) !void {
277+
var buffer = Writer(u8).init(self.allocator);
278+
errdefer buffer.deinit();
279+
var required_glyphs = AutoHashMap(u16, Glyph).init(self.allocator);
280+
defer required_glyphs.deinit();
281+
282+
var utf8_view = try UTF8.init(options.input_text);
283+
var iterator = utf8_view.iterator();
284+
285+
while (iterator.nextCodepoint()) |codepoint| {
286+
const glyph = try self.r.get_glyph_info(codepoint);
287+
if (glyph.id != 0) {
288+
try required_glyphs.put(glyph.id, glyph);
289+
}
290+
}
291+
try required_glyphs.put(0, Glyph{});
292+
try self.collect_glyph_ids_recursive(&required_glyphs);
293+
var glyph_ids = try self.allocator.alloc(u16, required_glyphs.count());
294+
defer self.allocator.free(glyph_ids);
295+
var iter = required_glyphs.iterator();
296+
var i: usize = 0;
297+
while (iter.next()) |entry| {
298+
glyph_ids[i] = entry.key_ptr.*;
299+
i += 1;
300+
}
301+
std.sort.heap(u16, glyph_ids, {}, std.sort.asc(u16));
302+
}
303+
304+
fn collect_glyph_ids_recursive(self: *Self, required_glyphs: *AutoHashMap(u16, Glyph)) !void {
305+
var new_glyphs = AutoHashMap(u16, Glyph).init(self.allocator);
306+
defer new_glyphs.deinit();
307+
308+
var iter = required_glyphs.iterator();
309+
while (iter.next()) |entry| {
310+
const glyph_id = entry.key_ptr.*;
311+
const glyph = entry.value_ptr.*;
312+
313+
if (glyph.is_composite) {
314+
const glyf_table = self.t.parser.parsed_tables.glyf.?;
315+
const glyf = glyf_table.cast(table.Glyf);
316+
const loca_table = self.t.parser.parsed_tables.loca.?;
317+
const loca = loca_table.cast(table.Loca);
318+
const glyph_offset = loca.get_glyph_offset(glyph_id).?;
319+
var parsed_glyph = try glyf.parse_glyph(glyph_offset);
320+
defer parsed_glyph.deinit();
321+
const composite_glyph = parsed_glyph.composite;
322+
323+
for (composite_glyph.components) |component| {
324+
const component_glyph_id = component.glyph_index;
325+
if (!required_glyphs.contains(component_glyph_id)) {
326+
const component_glyph = try self.r.get_glyph_info(component_glyph_id);
327+
try new_glyphs.put(component_glyph_id, component_glyph);
328+
}
329+
}
330+
}
331+
}
332+
333+
if (new_glyphs.count() > 0) {
334+
var new_iter = new_glyphs.iterator();
335+
while (new_iter.next()) |entry| {
336+
try required_glyphs.put(entry.key_ptr.*, entry.value_ptr.*);
337+
}
338+
try self.collect_glyph_ids_recursive(required_glyphs);
339+
}
340+
}
341+
342+
fn build_name_table(self: *Self) []const u8 {
343+
var name_pos: usize = 0;
344+
345+
for (self.t.parser.table_records.items, 0..) |record, i| {
346+
if (record.tag == .name) {
347+
name_pos = i;
348+
break;
349+
}
350+
}
351+
352+
const name_table_offset = self.parser.table_records.items[name_pos].offset;
353+
const name_table_size = self.t.parser.table_records.items[name_pos].length;
354+
355+
const name_table = self.t.parser.buffer[name_table_offset .. name_table_offset + name_table_size];
356+
357+
return name_table;
358+
}
359+
360+
fn build_post_table(self: *Self, glyph_ids: []u16) ![]u8 {
361+
var post_table = self.t.parser.parsed_tables.post.?;
362+
const post = post_table.cast(table.Post);
363+
258364
var buffer = Writer(u8).init(self.allocator);
365+
259366
errdefer buffer.deinit();
367+
368+
try buffer.write(u32, post.version, .big);
369+
try buffer.write(i32, post.italic_angle, .big);
370+
try buffer.write(i16, post.underline_position, .big);
371+
try buffer.write(i16, post.underline_thickness, .big);
372+
try buffer.write(u32, post.is_fixed_pitch, .big);
373+
try buffer.write(u32, post.min_mem_type42, .big);
374+
try buffer.write(u32, post.max_mem_type42, .big);
375+
try buffer.write(u32, post.min_mem_type1, .big);
376+
try buffer.write(u32, post.max_mem_type1, .big);
377+
378+
if (post.v2_data) |_| {
379+
try buffer.write(u16, @intCast(glyph_ids.len), .big);
380+
381+
var has_custom_names = false;
382+
for (glyph_ids) |glyph_id| {
383+
if (post.get_glyph_index(glyph_id)) |glyph_index| {
384+
try buffer.write(u16, glyph_index, .big);
385+
if (glyph_index >= 258) {
386+
has_custom_names = true;
387+
}
388+
}
389+
}
390+
if (has_custom_names) {
391+
for (glyph_ids) |glyph_id| {
392+
if (post.get_glyph_index(glyph_id)) |glyph_index| {
393+
if (glyph_index >= 258) {
394+
if (post.get_glyph_name(glyph_id)) |glyph_name| {
395+
try buffer.write_u8(@intCast(glyph_name.len));
396+
try buffer.write_bytes(glyph_name);
397+
}
398+
}
399+
}
400+
}
401+
}
402+
}
403+
404+
return buffer.to_owned_slice();
260405
}
261406
};
262407

263408
test "ttf.zig" {
264409
const fs = std.fs;
265410
const allocator = std.testing.allocator;
266-
const font_file_path = fs.path.join(allocator, &.{ "./", "fonts", "sub5.ttf" }) catch unreachable;
411+
const font_file_path = fs.path.join(allocator, &.{ "./", "fonts", "LXGWBright-Light.ttf" }) catch unreachable;
267412
defer allocator.free(font_file_path);
268413
const file_content = try fs.cwd().readFileAlloc(allocator, font_file_path, std.math.maxInt(usize));
269414
defer allocator.free(file_content);
270415
var font = try ttf.init(allocator, file_content);
271416
defer font.deinit();
272-
var reader = try font.reader();
273-
const code_point: u32 = 'a';
274-
const e = try reader.get_glyph_info(code_point);
275-
std.debug.print("glyph: {any}\n", .{e});
417+
var subbsetter = try font.subsetter();
418+
try subbsetter.build_subset(BuildSubsetterOptions{ .input_text = "绪方理奈" });
419+
// var reader = try font.reader();
420+
// const code_point: u32 = 'a';
421+
// const e = try reader.get_glyph_info(code_point);
422+
// std.debug.print("glyph: {any}\n", .{e});
276423
}

0 commit comments

Comments
 (0)