diff options
Diffstat (limited to 'text/grapheme.c')
| -rw-r--r-- | text/grapheme.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/text/grapheme.c b/text/grapheme.c new file mode 100644 index 0000000..b2eb136 --- /dev/null +++ b/text/grapheme.c @@ -0,0 +1,45 @@ +/* Grapheme clusters (UAX #29, Unicode 15.1): text/text.h. One pass, the + * rules in order; three pieces of state for the rules that look further + * back than one character (GB9c, GB11, GB12-13). */ +#include "text.h" + +void vega_graphemes(const uint32_t *codes, size_t count, uint8_t *breaks) { + breaks[0] = count > 0; /* GB1 */ + /* conjunct: 1 after a consonant and extends, 2 once a linker came too + * (GB9c); pictograph: 1 after a pictograph and extends, 2 after its ZWJ + * (GB11); regional: indicators in a row (GB12, GB13). */ + unsigned conjunct = 0, pictograph = 0, regional = 0, before = 0; + for (size_t i = 0; i < count; ++i) { + uint8_t property = vega_grapheme(codes[i]); + unsigned now = property & 15, incb = property >> 4; + bool pictographic = vega_extended_pictographic(codes[i]); + if (i) { + bool join; + if (before == VEGA_GCB_CR && now == VEGA_GCB_LF) join = true; /* GB3 */ + else if (before == VEGA_GCB_CONTROL || before == VEGA_GCB_CR || before == VEGA_GCB_LF) join = false; /* GB4 */ + else if (now == VEGA_GCB_CONTROL || now == VEGA_GCB_CR || now == VEGA_GCB_LF) join = false; /* GB5 */ + else if (before == VEGA_GCB_L && (now == VEGA_GCB_L || now == VEGA_GCB_V || now == VEGA_GCB_LV || now == VEGA_GCB_LVT)) + join = true; /* GB6 */ + else if ((before == VEGA_GCB_LV || before == VEGA_GCB_V) && (now == VEGA_GCB_V || now == VEGA_GCB_T)) + join = true; /* GB7 */ + else if ((before == VEGA_GCB_LVT || before == VEGA_GCB_T) && now == VEGA_GCB_T) join = true; /* GB8 */ + else if (now == VEGA_GCB_EXTEND || now == VEGA_GCB_ZWJ) join = true; /* GB9 */ + else if (now == VEGA_GCB_SPACING_MARK) join = true; /* GB9a */ + else if (before == VEGA_GCB_PREPEND) join = true; /* GB9b */ + else if (conjunct == 2 && incb == VEGA_INCB_CONSONANT) join = true; /* GB9c */ + else if (pictograph == 2 && pictographic) join = true; /* GB11 */ + else if (before == VEGA_GCB_RI && now == VEGA_GCB_RI && regional % 2) join = true; /* GB12, GB13 */ + else join = false; /* GB999 */ + breaks[i] = !join; + } + conjunct = incb == VEGA_INCB_CONSONANT ? 1 + : conjunct && incb == VEGA_INCB_LINKER ? 2 + : conjunct && incb == VEGA_INCB_EXTEND ? conjunct : 0; + pictograph = pictographic ? 1 + : pictograph == 1 && now == VEGA_GCB_EXTEND ? 1 + : pictograph == 1 && now == VEGA_GCB_ZWJ ? 2 : 0; + regional = now == VEGA_GCB_RI ? regional + 1 : 0; + before = now; + } + breaks[count] = count > 0; /* GB2 */ +} |
