summaryrefslogtreecommitdiff
path: root/src/font/opentype/head.zig
blob: b4ee3ffd440fa9aac13d812397b3664df3c4c807 (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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
const std = @import("std");
const assert = std.debug.assert;
const sfnt = @import("sfnt.zig");

/// Font Header Table
///
/// References:
/// - https://learn.microsoft.com/en-us/typography/opentype/spec/head
///
/// Field names are in camelCase to match names in spec.
pub const Head = extern struct {
    /// Major version number of the font header table — set to 1.
    majorVersion: sfnt.uint16 align(1),

    /// Minor version number of the font header table — set to 0.
    minorVersion: sfnt.uint16 align(1),

    /// Set by font manufacturer.
    fontRevision: sfnt.Fixed align(1),

    /// To compute: set it to 0, sum the entire font as uint32, then store
    /// 0xB1B0AFBA - sum. If the font is used as a component in a font
    /// collection file, the value of this field will be invalidated by
    /// changes to the file structure and font table directory, and must
    /// be ignored.
    checksumAdjustment: sfnt.uint32 align(1),

    /// Set to 0x5F0F3CF5.
    magicNumber: sfnt.uint32 align(1),

    /// Bit 0: Baseline for font at y=0.
    ///
    /// Bit 1: Left sidebearing point at x=0
    ///        (relevant only for TrueType rasterizers)
    ///
    /// Bit 2: Instructions may depend on point size.
    ///
    /// Bit 3: Force ppem to integer values for all internal scaler math; may
    ///        use fractional ppem sizes if this bit is clear. It is strongly
    ///        recommended that this be set in hinted fonts.
    ///
    /// Bit 4: Instructions may alter advance width
    ///        (the advance widths might not scale linearly).
    ///
    /// Bit 5: This bit is not used in OpenType, and should not be set in order
    ///        to ensure compatible behavior on all platforms. If set, it may
    ///        result in different behavior for vertical layout in some
    ///        platforms.
    ///
    ///        (See Apple’s specification for details
    ///        regarding behavior in Apple platforms.)
    ///
    /// Bits 6 – 10: These bits are not used in OpenType and should always be
    ///              cleared.
    ///
    ///              (See Apple’s specification for details
    ///              regarding legacy use in Apple platforms.)
    ///
    /// Bit 11: Font data is “lossless” as a result of having been
    ///         subjected to optimizing transformation and/or compression
    ///         (such as compression mechanisms defined by ISO/IEC 14496-18,
    ///         MicroType® Express, WOFF 2.0, or similar) where the original
    ///         font functionality and features are retained but the binary
    ///         compatibility between input and output font files is not
    ///         guaranteed. As a result of the applied transform, the DSIG
    ///         table may also be invalidated.
    ///
    /// Bit 12: Font converted (produce compatible metrics).
    ///
    /// Bit 13: Font optimized for ClearType®. Note, fonts that rely on embedded
    ///         bitmaps (EBDT) for rendering should not be considered optimized
    ///         for ClearType, and therefore should keep this bit cleared.
    ///
    /// Bit 14: Last Resort font. If set, indicates that the glyphs encoded in
    ///         the 'cmap' subtables are simply generic symbolic representations
    ///         of code point ranges and do not truly represent support for
    ///         those code points. If unset, indicates that the glyphs encoded
    ///         in the 'cmap' subtables represent proper support for those code
    ///         points.
    ///
    /// Bit 15: Reserved, set to 0.
    flags: sfnt.uint16 align(1),

    /// Set to a value from 16 to 16384. Any value in this range is valid.
    ///
    /// In fonts that have TrueType outlines, a power of 2 is recommended
    /// as this allows performance optimization in some rasterizers.
    unitsPerEm: sfnt.uint16 align(1),

    /// Number of seconds since 12:00 midnight that started
    /// January 1st, 1904, in GMT/UTC time zone.
    created: sfnt.LONGDATETIME align(1),

    /// Number of seconds since 12:00 midnight that started
    /// January 1st, 1904, in GMT/UTC time zone.
    modified: sfnt.LONGDATETIME align(1),

    /// Minimum x coordinate across all glyph bounding boxes.
    xMin: sfnt.int16 align(1),

    /// Minimum y coordinate across all glyph bounding boxes.
    yMin: sfnt.int16 align(1),

    /// Maximum x coordinate across all glyph bounding boxes.
    xMax: sfnt.int16 align(1),

    /// Maximum y coordinate across all glyph bounding boxes.
    yMax: sfnt.int16 align(1),

    /// Bit 0: Bold (if set to 1);
    /// Bit 1: Italic (if set to 1)
    /// Bit 2: Underline (if set to 1)
    /// Bit 3: Outline (if set to 1)
    /// Bit 4: Shadow (if set to 1)
    /// Bit 5: Condensed (if set to 1)
    /// Bit 6: Extended (if set to 1)
    /// Bits 7 – 15: Reserved (set to 0).
    macStyle: sfnt.uint16 align(1),

    /// Smallest readable size in pixels.
    lowestRecPPEM: sfnt.uint16 align(1),

    /// Deprecated (Set to 2).
    /// 0: Fully mixed directional glyphs;
    /// 1: Only strongly left to right;
    /// 2: Like 1 but also contains neutrals;
    /// -1: Only strongly right to left;
    /// -2: Like -1 but also contains neutrals.
    fontDirectionHint: sfnt.int16 align(1),

    /// 0 for short offsets (Offset16), 1 for long (Offset32).
    indexToLocFormat: sfnt.int16 align(1),

    /// 0 for current format.
    glyphDataFormat: sfnt.int16 align(1),

    /// Parse the table from raw data.
    pub fn init(data: []const u8) error{EndOfStream}!Head {
        var fbs = std.io.fixedBufferStream(data);
        const reader = fbs.reader();
        return try reader.readStructEndian(Head, .big);
    }
};

test "head" {
    const testing = std.testing;
    const alloc = testing.allocator;
    const test_font = @import("../embedded.zig").julia_mono;

    const font = try sfnt.SFNT.init(test_font, alloc);
    defer font.deinit(alloc);

    const table = font.getTable("head").?;

    const head = try Head.init(table);

    try testing.expectEqualDeep(
        Head{
            .majorVersion = 1,
            .minorVersion = 0,
            .fontRevision = sfnt.Fixed.from(0.05499267578125),
            .checksumAdjustment = 1007668681,
            .magicNumber = 1594834165,
            .flags = 7,
            .unitsPerEm = 2000,
            .created = 3797757830,
            .modified = 3797760444,
            .xMin = -1000,
            .yMin = -1058,
            .xMax = 3089,
            .yMax = 2400,
            .macStyle = 0,
            .lowestRecPPEM = 7,
            .fontDirectionHint = 2,
            .indexToLocFormat = 1,
            .glyphDataFormat = 0,
        },
        head,
    );
}