aboutsummaryrefslogtreecommitdiff
path: root/shared/font/metrics/metrics.zig
blob: 2ad3b3c41fc0ff70724b517dcd2203be24525ff0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//! Horizontal Metrics

const font = @import("shared").font;
const sfnt = @import("shared").sfnt;

const Face = font.types.face.Face;
const FontError = font.errors.font.FontError;
const GlyphMetrics = font.types.metrics.GlyphMetrics;
const Reader = sfnt.types.reader.Reader;

const LONG_METRIC_SIZE: usize = 4;

pub fn glyphMetrics(face: *const Face, glyph_id: u16) FontError!GlyphMetrics {
    if (glyph_id >= face.GlyphCount) {
        return FontError.GlyphOutOfRange;
    }
    if (face.LongMetricCount == 0) {
        return FontError.TableOutOfBounds;
    }

    var reader = Reader.initialize(face.Hmtx);

    if (glyph_id < face.LongMetricCount) {
        try reader.seek(@as(usize, glyph_id) * LONG_METRIC_SIZE);
        return GlyphMetrics{
            .AdvanceWidth = try reader.readU16(),
            .LeftSideBearing = try reader.readI16(),
        };
    }

    try reader.seek(@as(usize, face.LongMetricCount - 1) * LONG_METRIC_SIZE);
    const advance = try reader.readU16();

    const trailing = @as(usize, face.LongMetricCount) * LONG_METRIC_SIZE +
        @as(usize, glyph_id - face.LongMetricCount) * 2;
    try reader.seek(trailing);

    return GlyphMetrics{
        .AdvanceWidth = advance,
        .LeftSideBearing = try reader.readI16(),
    };
}

pub fn advanceWidth(face: *const Face, glyph_id: u16) FontError!u16 {
    const metrics = try glyphMetrics(face, glyph_id);
    return metrics.AdvanceWidth;
}