#ifndef MINIBIDI_H #define MINIBIDI_H /* * minibidi.h — standalone header for ESP32C3 BiDi calculations * * Derived from [mintty](https://github.com/mintty/mintty/) (Thomas Wolff, MIT licence). * Stripped of: Arabic shaping, box-drawing mirror, terminal dependencies, * GCC nested functions, VLAs, and non-Hebrew/English Unicode data. */ #include #include #include /* ── Basic types ─────────────────────────────────────────────────────── */ typedef uint8_t uchar; typedef uint32_t ucschar; /* Unicode codepoint; BMP-only content fits uint16_t but uint32_t is safer and ESP32C3 is 32-bit anyway */ /* ── Convenience macros ──────────────────────────────────────────────── */ #define lengthof(a) ((int)(sizeof(a) / sizeof(*(a)))) /* PuTTY/mintty switch-case style — kept for readability of algorithm */ #define when \ break; \ case #define otherwise \ break; \ default /* Maximum line length the algorithm will process. Adjust to your actual screen width. Stack cost = ~5×MAX bytes. */ #define BIDI_MAX_LINE 128 /* ── bidi_char ───────────────────────────────────────────────────────── */ /* origwc: the codepoint as it came from the epub text stream wc: working codepoint (may be replaced by mirrored form after do_bidi) index: original logical position, so the caller can reorder glyphs */ typedef struct { ucschar origwc; ucschar wc; uint16_t index; } bidi_char; /* ── Bidi character classes (UAX #9) ────────────────────────────────── */ enum { L, /* Left-to-Right */ LRE, /* Left-to-Right Embedding */ LRO, /* Left-to-Right Override */ R, /* Right-to-Left */ AL, /* Right-to-Left Arabic */ RLE, /* Right-to-Left Embedding */ RLO, /* Right-to-Left Override */ PDF, /* Pop Directional Format */ EN, /* European Number */ ES, /* European Number Separator */ ET, /* European Number Terminator */ AN, /* Arabic Number */ CS, /* Common Number Separator */ NSM, /* Non-Spacing Mark */ BN, /* Boundary Neutral */ B, /* Paragraph Separator */ S, /* Segment Separator */ WS, /* Whitespace */ ON, /* Other Neutrals */ /* Unicode 6.3 isolate types */ LRI, /* Left-to-Right Isolate */ RLI, /* Right-to-Left Isolate */ FSI, /* First Strong Isolate */ PDI, /* Pop Directional Isolate */ }; /* ── Public API ──────────────────────────────────────────────────────── */ /* * bidi_class(ch) * Returns the UAX#9 bidi class of Unicode codepoint ch. * Unknown characters return ON (correct per spec). */ uchar bidi_class(ucschar ch); /* * is_rtl_class(bc) * Returns true if bidi class bc can cause RTL reordering. * Use to fast-skip lines with no RTL content. */ bool is_rtl_class(uchar bc); /* * mirror(ch) * Returns the mirrored form of Unicode codepoint ch for UAX#9 rule L4. * If no mirror exists, returns ch unchanged. */ ucschar mirror(ucschar ch); /* * do_bidi(autodir, paragraphLevel, line, count) * * Applies UAX#9 Bidirectional Algorithm (rules P–L) to `line[0..count-1]`. * Reorders the array in-place; sets line[i].wc to the mirrored form where * required (rule L4). Returns the resolved paragraph level (0=LTR, 1=RTL), * or 0 if the line was left-to-right and no reordering was done. * * autodir: true → detect paragraph direction from content (P2/P3) * false → use paragraphLevel as-is * paragraphLevel: 0 = LTR, 1 = RTL. Ignored when autodir=true unless * the content has no strong type (used as fallback). * * count must be ≤ BIDI_MAX_LINE; lines longer than that are silently * truncated to BIDI_MAX_LINE before processing. */ int do_bidi(bool autodir, int paragraphLevel, bidi_char* line, int count); #endif /* MINIBIDI_H */