aboutsummaryrefslogtreecommitdiffstats
path: root/text/shape.h
blob: fdec7eedac5e7c5346488bdb0e4c84fba51761eb (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
#ifndef VEGA_SHAPE_H
#define VEGA_SHAPE_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

/* Shaping (docs/design/004-text.md): a run of characters (one script, one
 * direction) to glyphs and their positions, as HarfBuzz 10 shapes it with
 * its default, Arabic and Hebrew shapers, glyph for glyph and unit for unit.
 *
 * What a font's shaping needs travels in a symbol file (its shaping
 * section), written by the build tool:
 *   - plans, compiled from the font: per script and direction, which
 *     lookups run, in what order, on which glyphs (the feature masks);
 *   - the font's character map and advances;
 *   - its OpenType layout tables (GDEF, GSUB, GPOS) as they are: they are
 *     read in place, every read checked against the table's end, so a
 *     damaged table shapes wrong but never reads outside it.
 * Positions are in the font's units (VegaShaping.upem to an em).
 *
 * The section, little-endian:
 *   "VSHP", u32 size, u16 upem, u16 glyph_count,
 *   u32 cmap_count, u32 cmap_offset       (u32 code, u32 glyph; by code),
 *   u32 advances_offset                   (glyph_count u16),
 *   u32 offset, u32 size of GDEF, of GSUB and of GPOS (0 0 when absent),
 *   u32 plan_count, u32 plans_offset      (VEGA_PLAN_BYTES each),
 *   u32 step_count, u32 steps_offset      (8 bytes each),
 *   u32 offset, u32 size of the kern table (0 0 when absent),
 *   u32 extents_offset                    (glyph_count of i16 x_bearing,
 *                                          y_bearing, width, height; 0 when
 *                                          no plan positions marks without
 *                                          GPOS; x_bearing INT16_MIN: none),
 *   u32 0
 * Offsets are from the section's start. A plan:
 *   u32 script (ISO 15924 as a tag: 'Latn'), u8 direction, u8 native
 *   direction (of its script; 0 when it has none), u8 shaper, u8 flags,
 *   u32 global mask, u32 kern mask, u32 masks[VEGA_PLAN_MASKS], u32 first
 *   GSUB step, u32 GSUB steps, u32 first GPOS step, u32 GPOS steps.
 * A step, a lookup to run: u16 lookup index, u8 flags, u8 0, u32 mask. */
enum { VEGA_SHAPING_HEADER = 80, VEGA_PLAN_BYTES = 88, VEGA_STEP_BYTES = 8, VEGA_PLAN_MASKS = 14 };
enum { VEGA_SHAPE_LTR = 1, VEGA_SHAPE_RTL = 2 };
enum { VEGA_SHAPER_DEFAULT, VEGA_SHAPER_ARABIC, VEGA_SHAPER_HEBREW, VEGA_SHAPER_HANGUL };
/* Plan flags: GPOS runs; mark advances are zeroed after it (by GDEF); glyph
 * classes come from Unicode (the font has none); the font positions marks
 * (a 'mark' feature); automatic fractions; the kern table kerns; marks are
 * placed around their base without GPOS, and zeroing a mark's advance keeps
 * it where it was. */
enum { VEGA_PLAN_GPOS = 1, VEGA_PLAN_ZERO_MARKS = 2, VEGA_PLAN_GUESS_CLASSES = 4, VEGA_PLAN_GPOS_MARK = 8,
       VEGA_PLAN_FRACTIONS = 16, VEGA_PLAN_KERN = 32, VEGA_PLAN_FALLBACK_MARKS = 64, VEGA_PLAN_ADJUST_ZEROING = 128 };
/* The masks a plan names, for the features set glyph by glyph. */
enum { VEGA_MASK_ISOL, VEGA_MASK_FINA, VEGA_MASK_FIN2, VEGA_MASK_FIN3, VEGA_MASK_MEDI, VEGA_MASK_MED2,
       VEGA_MASK_INIT, VEGA_MASK_RTLM, VEGA_MASK_FRAC, VEGA_MASK_NUMR, VEGA_MASK_DNOM, VEGA_MASK_LJMO, VEGA_MASK_VJMO,
       VEGA_MASK_TJMO };
/* Step flags. */
enum { VEGA_STEP_AUTO_ZWNJ = 1, VEGA_STEP_AUTO_ZWJ = 2, VEGA_STEP_RANDOM = 4, VEGA_STEP_PER_SYLLABLE = 8 };

typedef struct { const unsigned char *p; uint32_t size; } VegaTable;
/* Which glyphs may be in a set, as three 64-bit patterns of glyph bits
 * (HarfBuzz's set digest): a glyph whose bits are not all there is not. */
typedef struct { uint64_t mask[3]; } VegaDigest;
typedef struct {
    uint16_t type; /* with extensions resolved */
    uint32_t at;
    VegaDigest digest; /* the glyphs it starts from */
} VegaSubtable;
typedef struct {
    uint16_t type, flags;
    uint32_t props;                 /* flags, and the mark filtering set in the high half */
    uint32_t first, count;          /* subtables */
    bool reverse;
    VegaDigest digest;              /* the glyphs its subtables start from */
} VegaLookup;
typedef struct {
    const unsigned char *bytes;
    size_t size;
    uint16_t upem, glyph_count;
    uint32_t cmap_count, plan_count;
    const unsigned char *cmap, *advances, *plans, *steps, *extents;
    VegaTable gdef, gsub, gpos, kern;
    uint32_t glyph_classes, attach_classes, mark_sets; /* in GDEF; 0 when absent */
    VegaLookup *lookups[2];         /* GSUB, GPOS */
    uint32_t lookup_count[2];
    VegaSubtable *subtables;
    uint16_t *bmp[256];             /* the character map's glyphs below U+10000, by page */
} VegaShaping;

/* Open a shaping section (kept, not copied); false with why. */
bool vega_shaping_open(VegaShaping *, const unsigned char *bytes, size_t size, char *error, size_t error_size);
void vega_shaping_close(VegaShaping *);
/* The font's glyph for a character, or 0. */
uint32_t vega_shaping_glyph(const VegaShaping *, uint32_t code);

/* A shaped glyph, as HarfBuzz gives it: in visual order (left to right),
 * cluster the index of the first character it came from; each glyph is
 * drawn at the pen plus its offset, then the pen moves by its advance. */
typedef struct {
    uint32_t glyph, cluster;
    int32_t x_advance, y_advance, x_offset, y_offset;
} VegaShaped;

/* The buffers shaping works in, kept from one run to the next. */
typedef struct VegaShaper VegaShaper;
VegaShaper *vega_shaper_new(void);
void vega_shaper_free(VegaShaper *);
/* Shape a run of count characters of script (an ISO 15924 tag, as
 * vega_script_code gives it) in direction (VEGA_SHAPE_LTR or _RTL) by the
 * plan compiled for them (or for Common, 'Zyyy', when there is none). The
 * glyphs (as many as returned) are the shaper's until its next run; -1
 * when there is no plan or no memory. */
long vega_shape(VegaShaper *, const VegaShaping *, const uint32_t *codes, size_t count, uint32_t script, int direction,
                const VegaShaped **out);
#endif