aboutsummaryrefslogtreecommitdiffstats
path: root/text/shape.h
diff options
context:
space:
mode:
Diffstat (limited to 'text/shape.h')
-rw-r--r--text/shape.h101
1 files changed, 101 insertions, 0 deletions
diff --git a/text/shape.h b/text/shape.h
new file mode 100644
index 0000000..5fe7c4e
--- /dev/null
+++ b/text/shape.h
@@ -0,0 +1,101 @@
+#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)
+ * 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 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 = 64, VEGA_PLAN_BYTES = 72, VEGA_STEP_BYTES = 8, VEGA_PLAN_MASKS = 11 };
+enum { VEGA_SHAPE_LTR = 1, VEGA_SHAPE_RTL = 2 };
+enum { VEGA_SHAPER_DEFAULT, VEGA_SHAPER_ARABIC, VEGA_SHAPER_HEBREW };
+/* Plan flags. */
+enum { VEGA_PLAN_GPOS = 1, VEGA_PLAN_ZERO_MARKS = 2, VEGA_PLAN_GUESS_CLASSES = 4, VEGA_PLAN_GPOS_MARK = 8,
+ VEGA_PLAN_FRACTIONS = 16 };
+/* 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 };
+/* 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;
+ VegaTable gdef, gsub, gpos;
+ 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