diff --git a/Makefile b/Makefile index a3e35d8..521c849 100644 --- a/Makefile +++ b/Makefile @@ -150,7 +150,7 @@ ifdef CONFIG_ALL_KMAPS endif ifdef CONFIG_UNICODE_JOIN - OBJS+= unicode_join.o arabic.o indic.o qfribidi.o + OBJS+= unicode_join.o arabic.o indic.o endif # more charsets if needed @@ -232,7 +232,7 @@ endif # TARGET_TINY SRCS:= $(OBJS:.o=.c) DEPENDS:= qe.h config.h config.mak charset.h color.h cutils.h display.h \ - qestyles.h qfribidi.h unicode_join.h util.h variables.h \ + qestyles.h unicode_join.h util.h variables.h \ wcwidth.h lang/clang.h DEPENDS:= $(addprefix $(DEPTH)/, $(DEPENDS)) @@ -361,14 +361,6 @@ $(BINDIR)/%$(EXE): tools/%.c $(cmd) mkdir -p $(dir $@) $(cmd) $(HOST_CC) $(HOST_CFLAGS) -o $@ $^ -# -# Test for bidir algorithm -# -$(BINDIR)/qfribidi$(EXE): qfribidi.c cutils.c - $(echo) CC -o $@ $^ - $(cmd) mkdir -p $(dir $@) - $(cmd) $(HOST_CC) $(HOST_CFLAGS) -DTEST -o $@ $^ - # # build ligature table # @@ -496,7 +488,7 @@ fbffonts.c: $(BINDIR)/fbftoqe$(EXE) $(FONTS) # html2png tool (XML/HTML/CSS2 renderer test tool) # OBJS1=html2png.o cutils.o util.o color.o display.o \ - arabic.o indic.o qfribidi.o unicode_join.o \ + arabic.o indic.o unicode_join.o \ charset.o charsetmore.o charsetjis.o \ libfbf.o fbfrender.o cfb.o fbffonts.o @@ -535,7 +527,7 @@ clean: rm -f qe-doc.aux qe-doc.info qe-doc.log qe-doc.pdf qe-doc.toc rm -rf *.dSYM *.gch .objs* .tobjs* .xobjs* bin rm -f *~ *.o *.a *.exe *_g *_debug TAGS gmon.out core *.exe.stackdump \ - qe tqe tqe1 xqe qfribidi kmaptoqe ligtoqe html2png cptoqe jistoqe \ + qe tqe tqe1 xqe kmaptoqe ligtoqe html2png cptoqe jistoqe \ fbftoqe fbffonts.c allmodules.txt basemodules.txt '.#'*[0-9] distclean: clean diff --git a/VERSION b/VERSION index 1772217..8ae03c1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.4.1g +5.4.2 diff --git a/arabic.c b/arabic.c index 387c356..dba3bb7 100644 --- a/arabic.c +++ b/arabic.c @@ -22,9 +22,6 @@ #include "cutils.h" #include "unicode_join.h" -/* define it if your font handle more ligatures than the minimum - required by unicode */ - typedef struct ArabicChar { unsigned short ch, isolated, final, medial, initial; } ArabicChar; @@ -206,9 +203,7 @@ static int arabic_is_transparent(char32_t ch) { } static const ArabicChar *arabic_find_char(char32_t ch) { - const ArabicChar *c; - - c = arabic_table; + const ArabicChar *c = arabic_table; while (c->ch != 0 && c->ch != ch) c++; return c; diff --git a/libqhtml/Makefile b/libqhtml/Makefile index 73b4c15..e72b443 100644 --- a/libqhtml/Makefile +++ b/libqhtml/Makefile @@ -1,7 +1,7 @@ # Libqhtml tiny HTML/CSS rendering library for QEmacs # # Copyright (c) 2000-2002 Fabrice Bellard. -# Copyright (c) 2000-2022 Charlie Gordon. +# Copyright (c) 2000-2023 Charlie Gordon. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -77,7 +77,7 @@ LIB= $(DEPTH)/.objs/$(TARGET_OS)-$(TARGET_ARCH)-$(CC)/libqhtml$(DEBUG_SUFFIX).a OBJS= css.o xmlparse.o cssparse.o html_style.o docbook_style.o DEPENDS:= config.h config.mak charset.h color.h cutils.h display.h \ - qfribidi.h unicode_join.h util.h + unicode_join.h util.h DEPENDS:= $(addprefix $(DEPTH)/, $(DEPENDS)) DEPENDS+= css.h cssid.h htmlent.h diff --git a/libqhtml/css.c b/libqhtml/css.c index f0c9e45..26cb059 100644 --- a/libqhtml/css.c +++ b/libqhtml/css.c @@ -2,7 +2,7 @@ * CSS core for qemacs. * * Copyright (c) 2000-2002 Fabrice Bellard. - * Copyright (c) 2007-2022 Charlie Gordon. + * Copyright (c) 2007-2023 Charlie Gordon. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1297,7 +1297,7 @@ typedef struct BidirAttrState { CSSContext *ctx; BidirTypeLink *list_end; BidirTypeLink *list_ptr; /* current type pointer */ - FriBidiCharType ltype; /* last type */ + BidirCharType ltype; /* last type */ int pos; /* current char position */ } BidirAttrState; @@ -1306,7 +1306,7 @@ static void bidir_compute_attributes_box(BidirAttrState *s, CSSBox *box) CSSState *props = box->props; int pos, offset; BidirTypeLink *p; - FriBidiCharType type, ltype; + BidirCharType type, ltype; NextCharFunc nextc = get_nextc(box); int bidi_mode; @@ -1322,14 +1322,14 @@ static void bidir_compute_attributes_box(BidirAttrState *s, CSSBox *box) if (props->unicode_bidi != CSS_UNICODE_BIDI_NORMAL) { if (props->unicode_bidi == CSS_UNICODE_BIDI_EMBED) { if (props->direction == CSS_DIRECTION_LTR) - type = FRIBIDI_TYPE_LRE; + type = BIDIR_TYPE_LRE; else - type = FRIBIDI_TYPE_RLE; + type = BIDIR_TYPE_RLE; } else { if (props->direction == CSS_DIRECTION_LTR) - type = FRIBIDI_TYPE_LRO; + type = BIDIR_TYPE_LRO; else - type = FRIBIDI_TYPE_RLO; + type = BIDIR_TYPE_RLO; } if (type != ltype && p < s->list_end) { p->type = type; @@ -1345,7 +1345,7 @@ static void bidir_compute_attributes_box(BidirAttrState *s, CSSBox *box) if (props->display == CSS_DISPLAY_INLINE_TABLE || props->display == CSS_DISPLAY_INLINE_BLOCK) { /* add a neutral type for images or inline tables */ - type = FRIBIDI_TYPE_ON; + type = BIDIR_TYPE_ON; if (type != ltype && p < s->list_end) { p->type = type; p->pos = pos; @@ -1363,9 +1363,9 @@ static void bidir_compute_attributes_box(BidirAttrState *s, CSSBox *box) char32_t c = nextc(box, &offset); pos++; if (bidi_mode == CSS_BIDI_MODE_TEST) - type = fribidi_get_type_test(c); + type = bidir_get_type_test(c); else - type = fribidi_get_type(c); + type = bidir_get_type(c); /* if not enough room, increment last link */ if (type != ltype && p < s->list_end) { p->type = type; @@ -1381,7 +1381,7 @@ static void bidir_compute_attributes_box(BidirAttrState *s, CSSBox *box) /* add end of bidi embed/override if needed */ if (props->unicode_bidi != CSS_UNICODE_BIDI_NORMAL) { - type = FRIBIDI_TYPE_PDF; + type = BIDIR_TYPE_PDF; if (type != ltype && p < s->list_end) { p->type = type; p->pos = pos; @@ -1409,7 +1409,7 @@ static int bidir_compute_attributes(CSSContext *ctx, BidirTypeLink *list_tab, in p = list_tab; /* Add the starting link */ - p->type = FRIBIDI_TYPE_SOT; + p->type = BIDIR_TYPE_SOT; p->len = 0; p->pos = 0; p++; @@ -1417,7 +1417,7 @@ static int bidir_compute_attributes(CSSContext *ctx, BidirTypeLink *list_tab, in s->ctx = ctx; s->list_end = list_tab + max_size - 1; s->list_ptr = p; - s->ltype = FRIBIDI_TYPE_SOT; + s->ltype = BIDIR_TYPE_SOT; s->pos = 0; for (box = first_box; box != NULL; box = box->next_inline) { @@ -1426,7 +1426,7 @@ static int bidir_compute_attributes(CSSContext *ctx, BidirTypeLink *list_tab, in /* Add the ending link */ p = s->list_ptr; - p->type = FRIBIDI_TYPE_EOT; + p->type = BIDIR_TYPE_EOT; p->len = 0; p->pos = s->pos; p++; @@ -1520,7 +1520,7 @@ static void bidir_end_inline(BidirComputeState *s) { BidirTypeLink embeds[RLE_EMBEDDINGS_SIZE]; int embedding_max_level; - FriBidiCharType base; + BidirCharType base; /* mark last box */ *s->pbox = NULL; @@ -1528,8 +1528,8 @@ static void bidir_end_inline(BidirComputeState *s) /* now we can do the bidir compute easily */ if (bidir_compute_attributes(s->ctx, embeds, RLE_EMBEDDINGS_SIZE, s->first_inline) > 2) { - base = FRIBIDI_TYPE_WL; - fribidi_analyse_string(embeds, &base, &embedding_max_level); + base = BIDIR_TYPE_WL; + bidir_analyze_string(embeds, &base, &embedding_max_level); #if 0 { BidirTypeLink *p; @@ -1537,7 +1537,7 @@ static void bidir_end_inline(BidirComputeState *s) printf("bidi_start:\n"); for (;;) { printf("type=%d pos=%d len=%d level=%d\n", p->type, p->pos, p->len, p->level); - if (p->type == FRIBIDI_TYPE_EOT) + if (p->type == BIDIR_TYPE_EOT) break; p++; } diff --git a/qe.c b/qe.c index 5189e1f..fd98367 100644 --- a/qe.c +++ b/qe.c @@ -2,7 +2,7 @@ * QEmacs, tiny but powerful multimode editor * * Copyright (c) 2000-2002 Fabrice Bellard. - * Copyright (c) 2000-2022 Charlie Gordon. + * Copyright (c) 2000-2023 Charlie Gordon. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -4260,26 +4260,26 @@ static int bidir_compute_attributes(BidirTypeLink *list_tab, int max_size, EditBuffer *b, int offset) { BidirTypeLink *p; - FriBidiCharType type, ltype; + BidirCharType type, ltype; int left, offset1; char32_t c; p = list_tab; /* Add the starting link */ - p->type = FRIBIDI_TYPE_SOT; + p->type = BIDIR_TYPE_SOT; p->len = 0; p->pos = 0; p++; left = max_size - 2; - ltype = FRIBIDI_TYPE_SOT; + ltype = BIDIR_TYPE_SOT; for (;;) { offset1 = offset; c = eb_nextc(b, offset, &offset); if (c == '\n') break; - type = fribidi_get_type(c); + type = bidir_get_type(c); /* if not enough room, increment last link */ if (type != ltype && left > 0) { p->type = type; @@ -4294,7 +4294,7 @@ static int bidir_compute_attributes(BidirTypeLink *list_tab, int max_size, } /* Add the ending link */ - p->type = FRIBIDI_TYPE_EOT; + p->type = BIDIR_TYPE_EOT; p->len = 0; p->pos = offset1; p++; @@ -4545,7 +4545,7 @@ int text_display_line(EditState *s, DisplayState *ds, int offset) int offset0, offset1, line_num, col_num; BidirTypeLink embeds[RLE_EMBEDDINGS_SIZE], *bd; int embedding_level, embedding_max_level; - FriBidiCharType base; + BidirCharType base; char32_t buf[COLORED_MAX_LINE_SIZE]; QETermStyle sbuf[COLORED_MAX_LINE_SIZE]; int char_index, colored_nb_chars; @@ -4564,11 +4564,11 @@ int text_display_line(EditState *s, DisplayState *ds, int offset) && bidir_compute_attributes(embeds, RLE_EMBEDDINGS_SIZE, s->b, offset) > 2) { - base = FRIBIDI_TYPE_WL; - fribidi_analyse_string(embeds, &base, &embedding_max_level); + base = BIDIR_TYPE_WL; + bidir_analyze_string(embeds, &base, &embedding_max_level); /* assure that base has only two possible values */ - if (base != FRIBIDI_TYPE_RTL) - base = FRIBIDI_TYPE_LTR; + if (base != BIDIR_TYPE_RTL) + base = BIDIR_TYPE_LTR; } else #endif { @@ -4576,7 +4576,7 @@ int text_display_line(EditState *s, DisplayState *ds, int offset) embedding_max_level = 0; embeds[1].level = 0; embeds[2].pos = 0x7fffffff; - base = FRIBIDI_TYPE_LTR; + base = BIDIR_TYPE_LTR; } display_bol_bidir(ds, base, embedding_max_level); diff --git a/qfribidi.c b/qfribidi.c deleted file mode 100644 index 0c4a2c5..0000000 --- a/qfribidi.c +++ /dev/null @@ -1,647 +0,0 @@ -/* - * FriBidi - Library of BiDi algorithm - * - * Copyright (C) 1999 Dov Grobgeld - * - * The optimizations to reduce the code size from 13 KB to 3 KB and - * the embed/override hack handling are - * Copyright (C) 2000 Fabrice Bellard. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. */ - -#include -#include -#include "cutils.h" -#include "unicode_join.h" - -//#define TEST -//#define DEBUG - -/*====================================================================== -// Mirrored characters include all the characters in the Unicode list -// that have been declared as being mirrored and that have a mirrored -// equivalent. -// -// There are lots of characters that are designed as being mirrored -// but do not have any mirrored glyph, e.g. the sign for there exist. -// Are these used in Arabic? That is are all the mathematical signs -// that are assigned to be mirrorable actually mirrored in Arabic? -// If that is the case, I'll change the below code to include also -// characters that mirror to themself. It will then be the responsibility -// of the display engine to actually mirror these. -//----------------------------------------------------------------------*/ - -/* The character (n & 0x7fff) is the mirror of (n & 0x7fff) +1 */ -/* except for AB <-> BB, 3C <-> 3E, 5B <-> 5D, 7B <-> 7D which have - their high order bit set */ -static const unsigned short mirror_table[] = { - 0x0028, 0x803C, 0x805B, 0x807B, 0x80AB, 0x2039, 0x2045, 0x207D, - 0x208D, 0x2264, 0x2266, 0x2268, 0x226A, 0x226E, 0x2270, 0x2272, - 0x2274, 0x22A2, 0x22C9, 0x22CB, 0x22D6, 0x22D8, 0x22DC, 0x22E6, - 0x22F0, 0x2308, 0x230A, 0x2329, 0x3008, 0x300A, 0x300C, 0x300E, - 0x3010, 0x3014, 0x3016, 0x3018, 0x301A, -}; - -/* - * Note: the first 256 bytes could be stored explicitely to optimize - * the speed. The table 'property_val' could be stored in 4 - * bits/symbol to reduce its size. - */ -// XXX: these tables are obsolete, complete rewrite is needed -static const unsigned short property_start[366] = { - 0x0000, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x001c, - 0x001f, 0x0020, 0x0021, 0x0023, 0x0026, 0x002b, 0x002c, 0x002d, - 0x002e, 0x002f, 0x0030, 0x003a, 0x003b, 0x0041, 0x005b, 0x0061, - 0x007b, 0x007f, 0x0085, 0x0086, 0x00a0, 0x00a1, 0x00a2, 0x00a6, - 0x00aa, 0x00ab, 0x00b0, 0x00b2, 0x00b4, 0x00b5, 0x00b6, 0x00b9, - 0x00ba, 0x00bb, 0x00c0, 0x00d7, 0x00d8, 0x00f7, 0x00f8, 0x02b9, - 0x02bb, 0x02c2, 0x02d0, 0x02d2, 0x02e0, 0x02e5, 0x02ee, 0x0300, - 0x0374, 0x037a, 0x037e, 0x0386, 0x0387, 0x0388, 0x0483, 0x048c, - 0x058a, 0x0591, 0x05be, 0x05bf, 0x05c0, 0x05c1, 0x05c3, 0x05c4, - 0x05d0, 0x0600, 0x061b, 0x064b, 0x0660, 0x066a, 0x066b, 0x066d, - 0x0670, 0x0671, 0x06d6, 0x06e5, 0x06e7, 0x06e9, 0x06ea, 0x06f0, - 0x06fa, 0x070f, 0x0710, 0x0711, 0x0712, 0x0730, 0x0780, 0x07a6, - 0x0800, 0x0900, 0x0903, 0x093c, 0x093d, 0x0941, 0x0949, 0x094d, - 0x0950, 0x0951, 0x0958, 0x0962, 0x0964, 0x0981, 0x0982, 0x09bc, - 0x09be, 0x09c1, 0x09c7, 0x09cd, 0x09d7, 0x09e2, 0x09e6, 0x09f2, - 0x09f4, 0x0a00, 0x0a05, 0x0a3c, 0x0a3e, 0x0a41, 0x0a59, 0x0a70, - 0x0a72, 0x0a81, 0x0a83, 0x0abc, 0x0abd, 0x0ac1, 0x0ac9, 0x0acd, - 0x0ad0, 0x0b00, 0x0b02, 0x0b3c, 0x0b3d, 0x0b3f, 0x0b40, 0x0b41, - 0x0b47, 0x0b4d, 0x0b57, 0x0b82, 0x0b83, 0x0bc0, 0x0bc1, 0x0bcd, - 0x0bd7, 0x0c3e, 0x0c41, 0x0c46, 0x0c60, 0x0cbf, 0x0cc0, 0x0cc6, - 0x0cc7, 0x0ccc, 0x0cd5, 0x0d41, 0x0d46, 0x0d4d, 0x0d57, 0x0dca, - 0x0dcf, 0x0dd2, 0x0dd8, 0x0e31, 0x0e32, 0x0e34, 0x0e3f, 0x0e40, - 0x0e47, 0x0e4f, 0x0eb1, 0x0eb2, 0x0eb4, 0x0ebd, 0x0ec8, 0x0ed0, - 0x0f18, 0x0f1a, 0x0f35, 0x0f36, 0x0f37, 0x0f38, 0x0f39, 0x0f3a, - 0x0f3e, 0x0f71, 0x0f7f, 0x0f80, 0x0f85, 0x0f86, 0x0f88, 0x0f90, - 0x0fbe, 0x0fc6, 0x0fc7, 0x102d, 0x1031, 0x1032, 0x1038, 0x1039, - 0x1040, 0x1058, 0x10a0, 0x1680, 0x1681, 0x169b, 0x16a0, 0x17b7, - 0x17be, 0x17c6, 0x17c7, 0x17c9, 0x17d4, 0x17db, 0x17dc, 0x1800, - 0x180b, 0x1810, 0x18a9, 0x1900, 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc2, - 0x1fcd, 0x1fd0, 0x1fdd, 0x1fe0, 0x1fed, 0x1ff2, 0x1ffd, 0x2000, - 0x200b, 0x200e, 0x200f, 0x2010, 0x2028, 0x2029, 0x202a, 0x202b, - 0x202c, 0x202d, 0x202e, 0x202f, 0x2030, 0x2035, 0x206a, 0x2070, - 0x207a, 0x207c, 0x207f, 0x2080, 0x208a, 0x208c, 0x20a0, 0x20d0, - 0x2100, 0x2102, 0x2103, 0x2107, 0x2108, 0x210a, 0x2114, 0x2115, - 0x2116, 0x2119, 0x211e, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, - 0x2129, 0x212a, 0x212e, 0x212f, 0x2132, 0x2133, 0x213a, 0x2160, - 0x2190, 0x2212, 0x2214, 0x2336, 0x237b, 0x2395, 0x2396, 0x2460, - 0x249c, 0x24ea, 0x2500, 0x2900, 0x2e00, 0x3000, 0x3001, 0x3005, - 0x3008, 0x3021, 0x302a, 0x3030, 0x3031, 0x3036, 0x3038, 0x303e, - 0x3041, 0x3099, 0x309b, 0x309d, 0x30fb, 0x30fc, 0xa490, 0xa500, - 0xfb1d, 0xfb1e, 0xfb1f, 0xfb29, 0xfb2a, 0xfb50, 0xfd3e, 0xfd50, - 0xfe00, 0xfe30, 0xfe50, 0xfe51, 0xfe52, 0xfe54, 0xfe55, 0xfe56, - 0xfe5f, 0xfe60, 0xfe62, 0xfe64, 0xfe69, 0xfe6b, 0xfe70, 0xfeff, - 0xff00, 0xff03, 0xff06, 0xff0b, 0xff0c, 0xff0d, 0xff0e, 0xff0f, - 0xff10, 0xff1a, 0xff1b, 0xff21, 0xff3b, 0xff41, 0xff5b, 0xff66, - 0xffe0, 0xffe2, 0xffe5, 0xffe8, 0xfff9, 0xfffc, -}; - -static const unsigned char property_val[366] = { - 0x0e, 0x0a, 0x09, 0x0a, 0x0b, 0x09, 0x0e, 0x09, - 0x0a, 0x0b, 0x0f, 0x06, 0x0f, 0x06, 0x08, 0x06, - 0x08, 0x05, 0x04, 0x08, 0x0f, 0x00, 0x0f, 0x00, - 0x0f, 0x0e, 0x09, 0x0e, 0x08, 0x0f, 0x06, 0x0f, - 0x00, 0x0f, 0x06, 0x04, 0x0f, 0x00, 0x0f, 0x04, - 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, - 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0d, - 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0d, 0x00, - 0x0f, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, - 0x01, 0x08, 0x0c, 0x0d, 0x07, 0x06, 0x07, 0x0c, - 0x0d, 0x0c, 0x0d, 0x0c, 0x0d, 0x0f, 0x0d, 0x04, - 0x0c, 0x0e, 0x0c, 0x0d, 0x0c, 0x0d, 0x0c, 0x0d, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x06, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x06, 0x00, - 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, - 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x0f, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, - 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x0d, - 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x0f, - 0x0e, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x0f, 0x00, - 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x0b, - 0x0e, 0x00, 0x01, 0x0f, 0x0b, 0x09, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x0b, 0x06, 0x0f, 0x0e, 0x04, - 0x06, 0x0f, 0x00, 0x04, 0x06, 0x0f, 0x06, 0x0d, - 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, - 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, - 0x0f, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x0f, 0x00, - 0x0f, 0x06, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x04, - 0x00, 0x04, 0x0f, 0x00, 0x0f, 0x0b, 0x0f, 0x00, - 0x0f, 0x00, 0x0d, 0x0f, 0x00, 0x0f, 0x00, 0x0f, - 0x00, 0x0d, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, - 0x01, 0x0d, 0x01, 0x06, 0x01, 0x0c, 0x0f, 0x0c, - 0x0d, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, - 0x06, 0x0f, 0x06, 0x0f, 0x06, 0x0f, 0x0c, 0x0e, - 0x0f, 0x06, 0x0f, 0x06, 0x08, 0x06, 0x08, 0x05, - 0x04, 0x08, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, - 0x06, 0x0f, 0x06, 0x0f, 0x0e, 0x0f, -}; - -FriBidiCharType fribidi_get_type(FriBidiChar ch) { -#if 1 // XXX: This caused an infinite loop in doc/DevCodingRules.html - /* use a binary lookup loop */ - // XXX: this is inefficient and slow - // should use multi-level indirect tables - int a = 0; - int b = countof(property_start); - while (b - a > 1) { - int m = (a + b) >> 1; - if (ch < property_start[m]) - b = m; - else - a = m; - } - return property_val[a]; -#else - int a, b, m, ch1; - -#if defined(TEST) || 0 - /* for testing only */ - if (ch >= 'A' && ch <= 'Z') - return FRIBIDI_TYPE_RTL; -#endif - - a = 0; - b = (sizeof(property_start) / 2) - 1; - while (a <= b) { - m = (a + b) >> 1; - ch1 = property_start[m]; - if (ch1 == ch) - goto found; - else if (ch1 > ch) { - b = m - 1; - } else { - a = m + 1; - } - } - m = a; - if (m > 0) - m--; - found: - return property_val[m]; -#endif -} - -/* version for test with ASCII chars */ -FriBidiCharType fribidi_get_type_test(FriBidiChar ch) { - if (ch >= 'A' && ch <= 'Z') - return FRIBIDI_TYPE_RTL; - else - return fribidi_get_type(ch); -} - -FriBidiChar -fribidi_get_mirror_char(FriBidiChar ch) -{ - int a, b, m, ch1, d, e; - - if (ch >= 0x8000) - return ch; - - a = 0; - b = (sizeof(mirror_table) / 2) - 1; - while (a <= b) { - m = (a + b) >> 1; - ch1 = mirror_table[m]; - if ((ch1 & 0x7fff) == ch) - goto found; - else if ((ch1 & 0x7fff) > ch) { - b = m - 1; - } else { - a = m + 1; - } - } - if (a > 0) - a--; - ch1 = mirror_table[a]; - found: - e = 1 + (ch1 >> 15); - ch1 = ch1 & 0x7fff; - /* special case */ - if (ch1 == 0xab) - e = 16; - d = ch - ch1; - if (d == 0) - return ch + e; - else if (d == e) - return ch - e; - else - return ch; -} - -/* Some convenience macros */ -#define RL_TYPE(list) (list)->type -#define RL_LEN(list) (list)->len -#define RL_POS(list) (list)->pos -#define RL_LEVEL(list) (list)->level - -static void compact_list(BidirTypeLink * list_tab) -{ - BidirTypeLink *p, *lp, *q; - int len; - FriBidiCharType type; - - p = list_tab; - q = list_tab; - for (;;) { - lp = p; - type = p->type; - len = p->len; - p++; - if (type == FRIBIDI_TYPE_NULL) { - /* nothing to do */ - } else if (type != FRIBIDI_TYPE_EOT) { - while (p->type == type) { - len += p->len; - p++; - } - q->type = type; - q->len = len; - q->pos = lp->pos; - q->level = lp->level; - q++; - } else { - q->type = FRIBIDI_TYPE_EOT; - q->pos = lp->pos; - q++; - break; - } - } -} - -/* Define a rule macro */ - -/* Rules for overriding current type */ -#define TYPE_RULE1(old_this, \ - new_this) \ - if (this_type == TYPE_ ## old_this) \ - RL_TYPE(pp) = FRIBIDI_TYPE_ ## new_this; \ - -/* Rules for current and previous type */ -#define TYPE_RULE2(old_prev, old_this, \ - new_prev, new_this) \ - if ( prev_type == FRIBIDI_TYPE_ ## old_prev \ - && this_type == FRIBIDI_TYPE_ ## old_this) \ - { \ - RL_TYPE(pp->prev) = FRIBIDI_TYPE_ ## new_prev; \ - RL_TYPE(pp) = FRIBIDI_TYPE_ ## new_this; \ - continue; \ - } - -/* A full rule that assigns all three types */ -#define TYPE_RULE(old_prev, old_this, old_next, \ - new_prev, new_this, new_next) \ - if ( prev_type == FRIBIDI_TYPE_ ## old_prev \ - && this_type == FRIBIDI_TYPE_ ## old_this \ - && next_type == FRIBIDI_TYPE_ ## old_next) \ - { \ - RL_TYPE(pp->prev) = FRIBIDI_TYPE_ ## new_prev; \ - RL_TYPE(pp) = FRIBIDI_TYPE_ ## new_this; \ - RL_TYPE(pp->next) = FRIBIDI_TYPE_ ## new_next; \ - continue; \ - } - -/* For optimization the following macro only assigns the center type */ -#define TYPE_RULE_C(old_prev, old_this, old_next, \ - new_this) \ - if ( prev_type == FRIBIDI_TYPE_ ## old_prev \ - && this_type == FRIBIDI_TYPE_ ## old_this \ - && next_type == FRIBIDI_TYPE_ ## old_next) \ - { \ - RL_TYPE(pp) = FRIBIDI_TYPE_ ## new_this; \ - continue; \ - } - -#ifdef DEBUG - -/*====================================================================== -// For debugging, define some macros for printing the types and the -// levels. -//----------------------------------------------------------------------*/ -static int type_to_char(int type) -{ - int ch; - - if (type == FRIBIDI_TYPE_R) - ch = 'R'; - else if (type == FRIBIDI_TYPE_L) - ch = 'L'; - else if (type == FRIBIDI_TYPE_E) - ch = 'E'; - else if (type == FRIBIDI_TYPE_EN) - ch = 'n'; - else if (type == FRIBIDI_TYPE_N) - ch = 'N'; - else - ch = '?'; - - return ch; -} - -static void print_types_re(BidirTypeLink * pp_tab, int level) -{ - BidirTypeLink *pp; - - for (pp = pp_tab + 1; pp->type != FRIBIDI_TYPE_EOT; pp++) { - printf("%d:%c(%d)[%d] ", RL_POS(pp), type_to_char(RL_TYPE(pp)), RL_LEN(pp), level ? RL_LEVEL(pp) : 0); - } - printf("\n"); -} - -#endif - -#define STACK_SIZE 64 - -/*====================================================================== -// This function should follow the Unicode specification closely! -// -// It is still lacking the support for and . -//----------------------------------------------------------------------*/ -void fribidi_analyse_string(BidirTypeLink * type_rl_list, - FriBidiCharType * pbase_dir, - int *pmax_level) -{ - int base_level, base_dir; - int max_level, level, override; - int last_strong; - BidirTypeLink *pp; - unsigned char stack_level[STACK_SIZE]; - unsigned char stack_override[STACK_SIZE]; - int stack_index; - - -#ifdef DEBUG - print_types_re(type_rl_list, 0); -#endif - - /* Find the base level */ - if (*pbase_dir == FRIBIDI_TYPE_L) { - base_dir = FRIBIDI_TYPE_L; - base_level = 0; - } else if (*pbase_dir == FRIBIDI_TYPE_R) { - base_dir = FRIBIDI_TYPE_R; - base_level = 1; - } - /* Search for first strong character and use its direction as base - direction */ - else { - base_level = 0; /* Default */ - base_dir = FRIBIDI_TYPE_N; - for (pp = type_rl_list; pp->type != FRIBIDI_TYPE_EOT; pp++) { - int type; - type = RL_TYPE(pp); - if (type == FRIBIDI_TYPE_R || - type == FRIBIDI_TYPE_RLE || - type == FRIBIDI_TYPE_RLO) { - base_level = 1; - base_dir = FRIBIDI_TYPE_R; - break; - } else if (type == FRIBIDI_TYPE_L || - type == FRIBIDI_TYPE_LRE || - type == FRIBIDI_TYPE_LRO) { - base_level = 0; - base_dir = FRIBIDI_TYPE_L; - break; - } - } - - /* If no strong base_dir was found, resort to the weak direction - * that was passed on input. - */ - if (base_dir == FRIBIDI_TYPE_N) { - if (*pbase_dir == FRIBIDI_TYPE_WR) { - base_dir = FRIBIDI_TYPE_RTL; - base_level = 1; - } else if (*pbase_dir == FRIBIDI_TYPE_WL) { - base_dir = FRIBIDI_TYPE_LTR; - base_level = 0; - } - } - } - - /* hack for RLE/LRE/RLO/LRO/PDF. It is not complete in case of - errors or with neutrals. Better take the latest version of - fribidi ? */ - level = base_level; - override = FRIBIDI_TYPE_N; - stack_index = 0; - for (pp = type_rl_list + 1; pp->type != FRIBIDI_TYPE_EOT; pp++) { - int type, i; - type = RL_TYPE(pp); - if (type == FRIBIDI_TYPE_LRE || - type == FRIBIDI_TYPE_RLE || - type == FRIBIDI_TYPE_LRO || - type == FRIBIDI_TYPE_RLO) { - for (i = 0; i < RL_LEN(pp); i++) { - if (stack_index < STACK_SIZE) { - /* push level & override */ - stack_level[stack_index] = level; - stack_override[stack_index] = override; - stack_index++; - /* compute new level */ - if (type == FRIBIDI_TYPE_LRE || - type == FRIBIDI_TYPE_LRO) { - level = (level + 2) & ~1; /* least greater even */ - } else { - level = (level + 1) | 1; /* least greater odd */ - } - /* compute new override */ - if (type == FRIBIDI_TYPE_LRO) - override = FRIBIDI_TYPE_L; - else if (type == FRIBIDI_TYPE_RLO) - override = FRIBIDI_TYPE_R; - else - override = FRIBIDI_TYPE_N; - } - } - RL_TYPE(pp) = FRIBIDI_TYPE_NULL; - } else if (type == FRIBIDI_TYPE_PDF) { - for (i = 0; i < RL_LEN(pp); i++) { - if (stack_index > 0) { - stack_index--; - /* pop level & override */ - level = stack_level[stack_index]; - override = stack_override[stack_index]; - } - } - RL_TYPE(pp) = FRIBIDI_TYPE_NULL; - } else { - RL_LEVEL(pp) = level; - /* if override defined, then modify type accordingly */ - if (override != FRIBIDI_TYPE_N) - RL_TYPE(pp) = override; - } - } - - compact_list(type_rl_list); - - /* 4. Resolving weak types */ - last_strong = base_dir; - for (pp = type_rl_list + 1; pp->type != FRIBIDI_TYPE_EOT; pp++) { - int prev_type = RL_TYPE(pp-1); - int this_type = RL_TYPE(pp); - int next_type = RL_TYPE(pp+1); - - /* Remember the last strong character */ - if (prev_type == FRIBIDI_TYPE_AL - || prev_type == FRIBIDI_TYPE_R - || prev_type == FRIBIDI_TYPE_L) - last_strong = prev_type; - - /* W1. NSM */ - if (this_type == FRIBIDI_TYPE_NSM) { - if (prev_type == FRIBIDI_TYPE_SOT) - RL_TYPE(pp) = FRIBIDI_TYPE_N; /* Will be resolved to base dir */ - else - RL_TYPE(pp) = prev_type; - } - /* W2: European numbers */ - if (this_type == FRIBIDI_TYPE_N - && last_strong == FRIBIDI_TYPE_AL) - RL_TYPE(pp) = FRIBIDI_TYPE_AN; - - /* W3: Change ALs to R - We have to do this for prev character as we would otherwise - interfer with the next last_strong which is FRIBIDI_TYPE_AL. - */ - if (prev_type == FRIBIDI_TYPE_AL) - RL_TYPE(pp-1) = FRIBIDI_TYPE_R; - - /* W4. A single european separator changes to a european number. - A single common separator between two numbers of the same type - changes to that type. - */ - if (RL_LEN(pp) == 1) { - TYPE_RULE_C(EN, ES, EN, EN); - TYPE_RULE_C(EN, CS, EN, EN); - TYPE_RULE_C(AN, CS, AN, AN); - } - /* W5. A sequence of European terminators adjacent to European - numbers changes to All European numbers. - */ - if (this_type == FRIBIDI_TYPE_ET) { - if (next_type == FRIBIDI_TYPE_EN - || prev_type == FRIBIDI_TYPE_EN) { - RL_TYPE(pp) = FRIBIDI_TYPE_EN; - } - } - /* This type may have been overriden */ - this_type = RL_TYPE(pp); - - /* W6. Otherwise change separators and terminators to other neutral */ - if (this_type == FRIBIDI_TYPE_ET - || this_type == FRIBIDI_TYPE_CS - || this_type == FRIBIDI_TYPE_ES) - RL_TYPE(pp) = FRIBIDI_TYPE_ON; - - /* W7. Change european numbers to L. */ - if (prev_type == FRIBIDI_TYPE_EN - && last_strong == FRIBIDI_TYPE_L) - RL_TYPE(pp-1) = FRIBIDI_TYPE_L; - } - - compact_list(type_rl_list); - - /* 5. Resolving Neutral Types */ - - /* We can now collapse all separators and other neutral types to - plain neutrals */ - for (pp = type_rl_list + 1; pp->type != FRIBIDI_TYPE_EOT; pp++) { - int this_type = RL_TYPE(pp); - - if (this_type == FRIBIDI_TYPE_WS - || this_type == FRIBIDI_TYPE_ON - || this_type == FRIBIDI_TYPE_ES - || this_type == FRIBIDI_TYPE_ET - || this_type == FRIBIDI_TYPE_CS - || this_type == FRIBIDI_TYPE_BN) - RL_TYPE(pp) = FRIBIDI_TYPE_N; - } - - compact_list(type_rl_list); - - for (pp = type_rl_list + 1; pp->type != FRIBIDI_TYPE_EOT; pp++) { - int prev_type = RL_TYPE(pp-1); - int this_type = RL_TYPE(pp); - int next_type = RL_TYPE(pp+1); - - if (this_type == FRIBIDI_TYPE_N) { /* optimization! */ - /* "European and arabic numbers are treated - as though they were R" */ - - if (prev_type == FRIBIDI_TYPE_EN || prev_type == FRIBIDI_TYPE_AN) - prev_type = FRIBIDI_TYPE_R; - - if (next_type == FRIBIDI_TYPE_EN || next_type == FRIBIDI_TYPE_AN) - next_type = FRIBIDI_TYPE_R; - - /* N1. */ - TYPE_RULE_C(R, N, R, R); - TYPE_RULE_C(L, N, L, L); - - /* N2. Any remaining neutrals takes the embedding direction */ - if (RL_TYPE(pp) == FRIBIDI_TYPE_N) - RL_TYPE(pp) = FRIBIDI_TYPE_E; - } - } - - compact_list(type_rl_list); - - /* 6. Resolving Implicit levels */ - max_level = base_level; - - for (pp = type_rl_list + 1; pp->type != FRIBIDI_TYPE_EOT; pp++) { - int this_type = RL_TYPE(pp); - - level = RL_LEVEL(pp); - if ((level & 1) == 0) { - /* Even */ - if (this_type == FRIBIDI_TYPE_R) - RL_LEVEL(pp) = level + 1; - else if (this_type == FRIBIDI_TYPE_AN) - RL_LEVEL(pp) = level + 2; - else if (RL_TYPE(pp-1) != FRIBIDI_TYPE_L && this_type == FRIBIDI_TYPE_EN) - RL_LEVEL(pp) = level + 2; - else - RL_LEVEL(pp) = level; - } else { - /* Odd */ - if (this_type == FRIBIDI_TYPE_L - || this_type == FRIBIDI_TYPE_AN - || this_type == FRIBIDI_TYPE_EN) - RL_LEVEL(pp) = level + 1; - else - RL_LEVEL(pp) = level; - } - - if (RL_LEVEL(pp) > max_level) - max_level = RL_LEVEL(pp); - } - - compact_list(type_rl_list); - - *pmax_level = max_level; - *pbase_dir = base_dir; -} diff --git a/qfribidi.h b/qfribidi.h deleted file mode 100644 index 162c613..0000000 --- a/qfribidi.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * FriBidi - Library of BiDi algorithm - * - * Copyright (C) 1999 Dov Grobgeld - * - * The optimizations to reduce the code size from 13 KB to 3 KB and - * the embed/override hack handling are - * Copyright (C) 2000 Fabrice Bellard. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef QFRIBIDI_H -#define QFRIBIDI_H - -typedef int FriBidiChar; - -typedef enum { - /* do not change the order of these constants since 'property_val' - depends on them */ - FRIBIDI_TYPE_LTR, /* Strong Left-to-Right */ - FRIBIDI_TYPE_RTL, /* Right-to-left characters */ - FRIBIDI_TYPE_WL, /* Weak left to right */ - FRIBIDI_TYPE_WR, /* Weak right to left */ - FRIBIDI_TYPE_EN, /* European Numeral */ - FRIBIDI_TYPE_ES, /* European number Separator */ - FRIBIDI_TYPE_ET, /* European number Terminator */ - FRIBIDI_TYPE_AN, /* Arabic Numeral */ - FRIBIDI_TYPE_CS, /* Common Separator */ - FRIBIDI_TYPE_BS, /* Block Separator */ - FRIBIDI_TYPE_SS, /* Segment Separator */ - FRIBIDI_TYPE_WS, /* Whitespace */ - FRIBIDI_TYPE_AL, /* Arabic Letter */ - FRIBIDI_TYPE_NSM, /* Non Spacing Mark */ - FRIBIDI_TYPE_BN, /* Boundary Neutral */ - FRIBIDI_TYPE_ON, /* Other Neutral */ - FRIBIDI_TYPE_LRE, /* Left-to-Right Embedding */ - FRIBIDI_TYPE_RLE, /* Right-to-Left Embedding */ - FRIBIDI_TYPE_PDF, /* Pop Directional Flag */ - FRIBIDI_TYPE_LRO, /* Left-to-Right Override */ - FRIBIDI_TYPE_RLO, /* Right-to-Left Override */ - - /* The following are only used internally */ - FRIBIDI_TYPE_SOT, - FRIBIDI_TYPE_EOT, - FRIBIDI_TYPE_N, - FRIBIDI_TYPE_E, - FRIBIDI_TYPE_CTL, /* Control units */ - FRIBIDI_TYPE_EO, /* Control units */ - FRIBIDI_TYPE_NULL, /* type record is to be deleted */ - FRIBIDI_TYPE_L = FRIBIDI_TYPE_LTR, - FRIBIDI_TYPE_R = FRIBIDI_TYPE_RTL, - FRIBIDI_TYPE_CM = FRIBIDI_TYPE_ON + 2, -} FriBidiCharType; - -/*====================================================================== -// Typedef for the run-length list. -//----------------------------------------------------------------------*/ -typedef struct BidirTypeLink { - FriBidiCharType type; - int pos; - int len; - int level; -} BidirTypeLink; - -FriBidiCharType fribidi_get_type(FriBidiChar ch); -FriBidiCharType fribidi_get_type_test(FriBidiChar ch); -FriBidiChar fribidi_get_mirror_char(FriBidiChar ch); - -void fribidi_analyse_string(BidirTypeLink *type_rl_list, - FriBidiCharType *pbase_dir, - int *pmax_level); -#endif /* QFRIBIDI_H */ diff --git a/unicode_join.c b/unicode_join.c index 819046d..522a219 100644 --- a/unicode_join.c +++ b/unicode_join.c @@ -286,12 +286,12 @@ static void bidi_reverse_buf(char32_t *str, int len) for (i = 0; i < len2; i++) { char32_t tmp = str[i]; - str[i] = fribidi_get_mirror_char(str[len - 1 - i]); - str[len - 1 - i] = fribidi_get_mirror_char(tmp); + str[i] = get_mirror_char(str[len - 1 - i]); + str[len - 1 - i] = get_mirror_char(tmp); } /* do not forget central char! */ if (len & 1) { - str[len2] = fribidi_get_mirror_char(str[len2]); + str[len2] = get_mirror_char(str[len2]); } } @@ -364,3 +364,929 @@ int unicode_to_glyphs(char32_t *dst, unsigned int *char_to_glyph_pos, } return len; } + +/* from BidiMirroring-15.0.0.txt + * Date: 2022-05-03, 18:47:00 GMT [KW, RP] + */ +static const unsigned short mirror_pairs[][2] = { + { 0x0028, 0x0029 }, // LEFT PARENTHESIS + { 0x0029, 0x0028 }, // RIGHT PARENTHESIS + { 0x003C, 0x003E }, // LESS-THAN SIGN + { 0x003E, 0x003C }, // GREATER-THAN SIGN + { 0x005B, 0x005D }, // LEFT SQUARE BRACKET + { 0x005D, 0x005B }, // RIGHT SQUARE BRACKET + { 0x007B, 0x007D }, // LEFT CURLY BRACKET + { 0x007D, 0x007B }, // RIGHT CURLY BRACKET + { 0x00AB, 0x00BB }, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + { 0x00BB, 0x00AB }, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + { 0x0F3A, 0x0F3B }, // TIBETAN MARK GUG RTAGS GYON + { 0x0F3B, 0x0F3A }, // TIBETAN MARK GUG RTAGS GYAS + { 0x0F3C, 0x0F3D }, // TIBETAN MARK ANG KHANG GYON + { 0x0F3D, 0x0F3C }, // TIBETAN MARK ANG KHANG GYAS + { 0x169B, 0x169C }, // OGHAM FEATHER MARK + { 0x169C, 0x169B }, // OGHAM REVERSED FEATHER MARK + { 0x2039, 0x203A }, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK + { 0x203A, 0x2039 }, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + { 0x2045, 0x2046 }, // LEFT SQUARE BRACKET WITH QUILL + { 0x2046, 0x2045 }, // RIGHT SQUARE BRACKET WITH QUILL + { 0x207D, 0x207E }, // SUPERSCRIPT LEFT PARENTHESIS + { 0x207E, 0x207D }, // SUPERSCRIPT RIGHT PARENTHESIS + { 0x208D, 0x208E }, // SUBSCRIPT LEFT PARENTHESIS + { 0x208E, 0x208D }, // SUBSCRIPT RIGHT PARENTHESIS + { 0x2208, 0x220B }, // ELEMENT OF + { 0x2209, 0x220C }, // [BEST FIT] NOT AN ELEMENT OF + { 0x220A, 0x220D }, // SMALL ELEMENT OF + { 0x220B, 0x2208 }, // CONTAINS AS MEMBER + { 0x220C, 0x2209 }, // [BEST FIT] DOES NOT CONTAIN AS MEMBER + { 0x220D, 0x220A }, // SMALL CONTAINS AS MEMBER + { 0x2215, 0x29F5 }, // DIVISION SLASH + { 0x221F, 0x2BFE }, // RIGHT ANGLE + { 0x2220, 0x29A3 }, // ANGLE + { 0x2221, 0x299B }, // MEASURED ANGLE + { 0x2222, 0x29A0 }, // SPHERICAL ANGLE + { 0x2224, 0x2AEE }, // DOES NOT DIVIDE + { 0x223C, 0x223D }, // TILDE OPERATOR + { 0x223D, 0x223C }, // REVERSED TILDE + { 0x2243, 0x22CD }, // ASYMPTOTICALLY EQUAL TO + { 0x2245, 0x224C }, // APPROXIMATELY EQUAL TO + { 0x224C, 0x2245 }, // ALL EQUAL TO + { 0x2252, 0x2253 }, // APPROXIMATELY EQUAL TO OR THE IMAGE OF + { 0x2253, 0x2252 }, // IMAGE OF OR APPROXIMATELY EQUAL TO + { 0x2254, 0x2255 }, // COLON EQUALS + { 0x2255, 0x2254 }, // EQUALS COLON + { 0x2264, 0x2265 }, // LESS-THAN OR EQUAL TO + { 0x2265, 0x2264 }, // GREATER-THAN OR EQUAL TO + { 0x2266, 0x2267 }, // LESS-THAN OVER EQUAL TO + { 0x2267, 0x2266 }, // GREATER-THAN OVER EQUAL TO + { 0x2268, 0x2269 }, // [BEST FIT] LESS-THAN BUT NOT EQUAL TO + { 0x2269, 0x2268 }, // [BEST FIT] GREATER-THAN BUT NOT EQUAL TO + { 0x226A, 0x226B }, // MUCH LESS-THAN + { 0x226B, 0x226A }, // MUCH GREATER-THAN + { 0x226E, 0x226F }, // [BEST FIT] NOT LESS-THAN + { 0x226F, 0x226E }, // [BEST FIT] NOT GREATER-THAN + { 0x2270, 0x2271 }, // [BEST FIT] NEITHER LESS-THAN NOR EQUAL TO + { 0x2271, 0x2270 }, // [BEST FIT] NEITHER GREATER-THAN NOR EQUAL TO + { 0x2272, 0x2273 }, // [BEST FIT] LESS-THAN OR EQUIVALENT TO + { 0x2273, 0x2272 }, // [BEST FIT] GREATER-THAN OR EQUIVALENT TO + { 0x2274, 0x2275 }, // [BEST FIT] NEITHER LESS-THAN NOR EQUIVALENT TO + { 0x2275, 0x2274 }, // [BEST FIT] NEITHER GREATER-THAN NOR EQUIVALENT TO + { 0x2276, 0x2277 }, // LESS-THAN OR GREATER-THAN + { 0x2277, 0x2276 }, // GREATER-THAN OR LESS-THAN + { 0x2278, 0x2279 }, // [BEST FIT] NEITHER LESS-THAN NOR GREATER-THAN + { 0x2279, 0x2278 }, // [BEST FIT] NEITHER GREATER-THAN NOR LESS-THAN + { 0x227A, 0x227B }, // PRECEDES + { 0x227B, 0x227A }, // SUCCEEDS + { 0x227C, 0x227D }, // PRECEDES OR EQUAL TO + { 0x227D, 0x227C }, // SUCCEEDS OR EQUAL TO + { 0x227E, 0x227F }, // [BEST FIT] PRECEDES OR EQUIVALENT TO + { 0x227F, 0x227E }, // [BEST FIT] SUCCEEDS OR EQUIVALENT TO + { 0x2280, 0x2281 }, // [BEST FIT] DOES NOT PRECEDE + { 0x2281, 0x2280 }, // [BEST FIT] DOES NOT SUCCEED + { 0x2282, 0x2283 }, // SUBSET OF + { 0x2283, 0x2282 }, // SUPERSET OF + { 0x2284, 0x2285 }, // [BEST FIT] NOT A SUBSET OF + { 0x2285, 0x2284 }, // [BEST FIT] NOT A SUPERSET OF + { 0x2286, 0x2287 }, // SUBSET OF OR EQUAL TO + { 0x2287, 0x2286 }, // SUPERSET OF OR EQUAL TO + { 0x2288, 0x2289 }, // [BEST FIT] NEITHER A SUBSET OF NOR EQUAL TO + { 0x2289, 0x2288 }, // [BEST FIT] NEITHER A SUPERSET OF NOR EQUAL TO + { 0x228A, 0x228B }, // [BEST FIT] SUBSET OF WITH NOT EQUAL TO + { 0x228B, 0x228A }, // [BEST FIT] SUPERSET OF WITH NOT EQUAL TO + { 0x228F, 0x2290 }, // SQUARE IMAGE OF + { 0x2290, 0x228F }, // SQUARE ORIGINAL OF + { 0x2291, 0x2292 }, // SQUARE IMAGE OF OR EQUAL TO + { 0x2292, 0x2291 }, // SQUARE ORIGINAL OF OR EQUAL TO + { 0x2298, 0x29B8 }, // CIRCLED DIVISION SLASH + { 0x22A2, 0x22A3 }, // RIGHT TACK + { 0x22A3, 0x22A2 }, // LEFT TACK + { 0x22A6, 0x2ADE }, // ASSERTION + { 0x22A8, 0x2AE4 }, // TRUE + { 0x22A9, 0x2AE3 }, // FORCES + { 0x22AB, 0x2AE5 }, // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + { 0x22B0, 0x22B1 }, // PRECEDES UNDER RELATION + { 0x22B1, 0x22B0 }, // SUCCEEDS UNDER RELATION + { 0x22B2, 0x22B3 }, // NORMAL SUBGROUP OF + { 0x22B3, 0x22B2 }, // CONTAINS AS NORMAL SUBGROUP + { 0x22B4, 0x22B5 }, // NORMAL SUBGROUP OF OR EQUAL TO + { 0x22B5, 0x22B4 }, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + { 0x22B6, 0x22B7 }, // ORIGINAL OF + { 0x22B7, 0x22B6 }, // IMAGE OF + { 0x22B8, 0x27DC }, // MULTIMAP + { 0x22C9, 0x22CA }, // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT + { 0x22CA, 0x22C9 }, // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT + { 0x22CB, 0x22CC }, // LEFT SEMIDIRECT PRODUCT + { 0x22CC, 0x22CB }, // RIGHT SEMIDIRECT PRODUCT + { 0x22CD, 0x2243 }, // REVERSED TILDE EQUALS + { 0x22D0, 0x22D1 }, // DOUBLE SUBSET + { 0x22D1, 0x22D0 }, // DOUBLE SUPERSET + { 0x22D6, 0x22D7 }, // LESS-THAN WITH DOT + { 0x22D7, 0x22D6 }, // GREATER-THAN WITH DOT + { 0x22D8, 0x22D9 }, // VERY MUCH LESS-THAN + { 0x22D9, 0x22D8 }, // VERY MUCH GREATER-THAN + { 0x22DA, 0x22DB }, // LESS-THAN EQUAL TO OR GREATER-THAN + { 0x22DB, 0x22DA }, // GREATER-THAN EQUAL TO OR LESS-THAN + { 0x22DC, 0x22DD }, // EQUAL TO OR LESS-THAN + { 0x22DD, 0x22DC }, // EQUAL TO OR GREATER-THAN + { 0x22DE, 0x22DF }, // EQUAL TO OR PRECEDES + { 0x22DF, 0x22DE }, // EQUAL TO OR SUCCEEDS + { 0x22E0, 0x22E1 }, // [BEST FIT] DOES NOT PRECEDE OR EQUAL + { 0x22E1, 0x22E0 }, // [BEST FIT] DOES NOT SUCCEED OR EQUAL + { 0x22E2, 0x22E3 }, // [BEST FIT] NOT SQUARE IMAGE OF OR EQUAL TO + { 0x22E3, 0x22E2 }, // [BEST FIT] NOT SQUARE ORIGINAL OF OR EQUAL TO + { 0x22E4, 0x22E5 }, // [BEST FIT] SQUARE IMAGE OF OR NOT EQUAL TO + { 0x22E5, 0x22E4 }, // [BEST FIT] SQUARE ORIGINAL OF OR NOT EQUAL TO + { 0x22E6, 0x22E7 }, // [BEST FIT] LESS-THAN BUT NOT EQUIVALENT TO + { 0x22E7, 0x22E6 }, // [BEST FIT] GREATER-THAN BUT NOT EQUIVALENT TO + { 0x22E8, 0x22E9 }, // [BEST FIT] PRECEDES BUT NOT EQUIVALENT TO + { 0x22E9, 0x22E8 }, // [BEST FIT] SUCCEEDS BUT NOT EQUIVALENT TO + { 0x22EA, 0x22EB }, // [BEST FIT] NOT NORMAL SUBGROUP OF + { 0x22EB, 0x22EA }, // [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP + { 0x22EC, 0x22ED }, // [BEST FIT] NOT NORMAL SUBGROUP OF OR EQUAL TO + { 0x22ED, 0x22EC }, // [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + { 0x22F0, 0x22F1 }, // UP RIGHT DIAGONAL ELLIPSIS + { 0x22F1, 0x22F0 }, // DOWN RIGHT DIAGONAL ELLIPSIS + { 0x22F2, 0x22FA }, // ELEMENT OF WITH LONG HORIZONTAL STROKE + { 0x22F3, 0x22FB }, // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + { 0x22F4, 0x22FC }, // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + { 0x22F6, 0x22FD }, // ELEMENT OF WITH OVERBAR + { 0x22F7, 0x22FE }, // SMALL ELEMENT OF WITH OVERBAR + { 0x22FA, 0x22F2 }, // CONTAINS WITH LONG HORIZONTAL STROKE + { 0x22FB, 0x22F3 }, // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + { 0x22FC, 0x22F4 }, // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + { 0x22FD, 0x22F6 }, // CONTAINS WITH OVERBAR + { 0x22FE, 0x22F7 }, // SMALL CONTAINS WITH OVERBAR + { 0x2308, 0x2309 }, // LEFT CEILING + { 0x2309, 0x2308 }, // RIGHT CEILING + { 0x230A, 0x230B }, // LEFT FLOOR + { 0x230B, 0x230A }, // RIGHT FLOOR + { 0x2329, 0x232A }, // LEFT-POINTING ANGLE BRACKET + { 0x232A, 0x2329 }, // RIGHT-POINTING ANGLE BRACKET + { 0x2768, 0x2769 }, // MEDIUM LEFT PARENTHESIS ORNAMENT + { 0x2769, 0x2768 }, // MEDIUM RIGHT PARENTHESIS ORNAMENT + { 0x276A, 0x276B }, // MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT + { 0x276B, 0x276A }, // MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT + { 0x276C, 0x276D }, // MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT + { 0x276D, 0x276C }, // MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT + { 0x276E, 0x276F }, // HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT + { 0x276F, 0x276E }, // HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT + { 0x2770, 0x2771 }, // HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT + { 0x2771, 0x2770 }, // HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT + { 0x2772, 0x2773 }, // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT + { 0x2773, 0x2772 }, // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT + { 0x2774, 0x2775 }, // MEDIUM LEFT CURLY BRACKET ORNAMENT + { 0x2775, 0x2774 }, // MEDIUM RIGHT CURLY BRACKET ORNAMENT + { 0x27C3, 0x27C4 }, // OPEN SUBSET + { 0x27C4, 0x27C3 }, // OPEN SUPERSET + { 0x27C5, 0x27C6 }, // LEFT S-SHAPED BAG DELIMITER + { 0x27C6, 0x27C5 }, // RIGHT S-SHAPED BAG DELIMITER + { 0x27C8, 0x27C9 }, // REVERSE SOLIDUS PRECEDING SUBSET + { 0x27C9, 0x27C8 }, // SUPERSET PRECEDING SOLIDUS + { 0x27CB, 0x27CD }, // MATHEMATICAL RISING DIAGONAL + { 0x27CD, 0x27CB }, // MATHEMATICAL FALLING DIAGONAL + { 0x27D5, 0x27D6 }, // LEFT OUTER JOIN + { 0x27D6, 0x27D5 }, // RIGHT OUTER JOIN + { 0x27DC, 0x22B8 }, // LEFT MULTIMAP + { 0x27DD, 0x27DE }, // LONG RIGHT TACK + { 0x27DE, 0x27DD }, // LONG LEFT TACK + { 0x27E2, 0x27E3 }, // WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK + { 0x27E3, 0x27E2 }, // WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK + { 0x27E4, 0x27E5 }, // WHITE SQUARE WITH LEFTWARDS TICK + { 0x27E5, 0x27E4 }, // WHITE SQUARE WITH RIGHTWARDS TICK + { 0x27E6, 0x27E7 }, // MATHEMATICAL LEFT WHITE SQUARE BRACKET + { 0x27E7, 0x27E6 }, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET + { 0x27E8, 0x27E9 }, // MATHEMATICAL LEFT ANGLE BRACKET + { 0x27E9, 0x27E8 }, // MATHEMATICAL RIGHT ANGLE BRACKET + { 0x27EA, 0x27EB }, // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET + { 0x27EB, 0x27EA }, // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET + { 0x27EC, 0x27ED }, // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET + { 0x27ED, 0x27EC }, // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET + { 0x27EE, 0x27EF }, // MATHEMATICAL LEFT FLATTENED PARENTHESIS + { 0x27EF, 0x27EE }, // MATHEMATICAL RIGHT FLATTENED PARENTHESIS + { 0x2983, 0x2984 }, // LEFT WHITE CURLY BRACKET + { 0x2984, 0x2983 }, // RIGHT WHITE CURLY BRACKET + { 0x2985, 0x2986 }, // LEFT WHITE PARENTHESIS + { 0x2986, 0x2985 }, // RIGHT WHITE PARENTHESIS + { 0x2987, 0x2988 }, // Z NOTATION LEFT IMAGE BRACKET + { 0x2988, 0x2987 }, // Z NOTATION RIGHT IMAGE BRACKET + { 0x2989, 0x298A }, // Z NOTATION LEFT BINDING BRACKET + { 0x298A, 0x2989 }, // Z NOTATION RIGHT BINDING BRACKET + { 0x298B, 0x298C }, // LEFT SQUARE BRACKET WITH UNDERBAR + { 0x298C, 0x298B }, // RIGHT SQUARE BRACKET WITH UNDERBAR + { 0x298D, 0x2990 }, // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER + { 0x298E, 0x298F }, // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + { 0x298F, 0x298E }, // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + { 0x2990, 0x298D }, // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER + { 0x2991, 0x2992 }, // LEFT ANGLE BRACKET WITH DOT + { 0x2992, 0x2991 }, // RIGHT ANGLE BRACKET WITH DOT + { 0x2993, 0x2994 }, // LEFT ARC LESS-THAN BRACKET + { 0x2994, 0x2993 }, // RIGHT ARC GREATER-THAN BRACKET + { 0x2995, 0x2996 }, // DOUBLE LEFT ARC GREATER-THAN BRACKET + { 0x2996, 0x2995 }, // DOUBLE RIGHT ARC LESS-THAN BRACKET + { 0x2997, 0x2998 }, // LEFT BLACK TORTOISE SHELL BRACKET + { 0x2998, 0x2997 }, // RIGHT BLACK TORTOISE SHELL BRACKET + { 0x299B, 0x2221 }, // MEASURED ANGLE OPENING LEFT + { 0x29A0, 0x2222 }, // SPHERICAL ANGLE OPENING LEFT + { 0x29A3, 0x2220 }, // REVERSED ANGLE + { 0x29A4, 0x29A5 }, // ANGLE WITH UNDERBAR + { 0x29A5, 0x29A4 }, // REVERSED ANGLE WITH UNDERBAR + { 0x29A8, 0x29A9 }, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT + { 0x29A9, 0x29A8 }, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT + { 0x29AA, 0x29AB }, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT + { 0x29AB, 0x29AA }, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT + { 0x29AC, 0x29AD }, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP + { 0x29AD, 0x29AC }, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP + { 0x29AE, 0x29AF }, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN + { 0x29AF, 0x29AE }, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN + { 0x29B8, 0x2298 }, // CIRCLED REVERSE SOLIDUS + { 0x29C0, 0x29C1 }, // CIRCLED LESS-THAN + { 0x29C1, 0x29C0 }, // CIRCLED GREATER-THAN + { 0x29C4, 0x29C5 }, // SQUARED RISING DIAGONAL SLASH + { 0x29C5, 0x29C4 }, // SQUARED FALLING DIAGONAL SLASH + { 0x29CF, 0x29D0 }, // LEFT TRIANGLE BESIDE VERTICAL BAR + { 0x29D0, 0x29CF }, // VERTICAL BAR BESIDE RIGHT TRIANGLE + { 0x29D1, 0x29D2 }, // BOWTIE WITH LEFT HALF BLACK + { 0x29D2, 0x29D1 }, // BOWTIE WITH RIGHT HALF BLACK + { 0x29D4, 0x29D5 }, // TIMES WITH LEFT HALF BLACK + { 0x29D5, 0x29D4 }, // TIMES WITH RIGHT HALF BLACK + { 0x29D8, 0x29D9 }, // LEFT WIGGLY FENCE + { 0x29D9, 0x29D8 }, // RIGHT WIGGLY FENCE + { 0x29DA, 0x29DB }, // LEFT DOUBLE WIGGLY FENCE + { 0x29DB, 0x29DA }, // RIGHT DOUBLE WIGGLY FENCE + { 0x29E8, 0x29E9 }, // DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK + { 0x29E9, 0x29E8 }, // DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK + { 0x29F5, 0x2215 }, // REVERSE SOLIDUS OPERATOR + { 0x29F8, 0x29F9 }, // BIG SOLIDUS + { 0x29F9, 0x29F8 }, // BIG REVERSE SOLIDUS + { 0x29FC, 0x29FD }, // LEFT-POINTING CURVED ANGLE BRACKET + { 0x29FD, 0x29FC }, // RIGHT-POINTING CURVED ANGLE BRACKET + { 0x2A2B, 0x2A2C }, // MINUS SIGN WITH FALLING DOTS + { 0x2A2C, 0x2A2B }, // MINUS SIGN WITH RISING DOTS + { 0x2A2D, 0x2A2E }, // PLUS SIGN IN LEFT HALF CIRCLE + { 0x2A2E, 0x2A2D }, // PLUS SIGN IN RIGHT HALF CIRCLE + { 0x2A34, 0x2A35 }, // MULTIPLICATION SIGN IN LEFT HALF CIRCLE + { 0x2A35, 0x2A34 }, // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE + { 0x2A3C, 0x2A3D }, // INTERIOR PRODUCT + { 0x2A3D, 0x2A3C }, // RIGHTHAND INTERIOR PRODUCT + { 0x2A64, 0x2A65 }, // Z NOTATION DOMAIN ANTIRESTRICTION + { 0x2A65, 0x2A64 }, // Z NOTATION RANGE ANTIRESTRICTION + { 0x2A79, 0x2A7A }, // LESS-THAN WITH CIRCLE INSIDE + { 0x2A7A, 0x2A79 }, // GREATER-THAN WITH CIRCLE INSIDE + { 0x2A7B, 0x2A7C }, // [BEST FIT] LESS-THAN WITH QUESTION MARK ABOVE + { 0x2A7C, 0x2A7B }, // [BEST FIT] GREATER-THAN WITH QUESTION MARK ABOVE + { 0x2A7D, 0x2A7E }, // LESS-THAN OR SLANTED EQUAL TO + { 0x2A7E, 0x2A7D }, // GREATER-THAN OR SLANTED EQUAL TO + { 0x2A7F, 0x2A80 }, // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + { 0x2A80, 0x2A7F }, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + { 0x2A81, 0x2A82 }, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + { 0x2A82, 0x2A81 }, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + { 0x2A83, 0x2A84 }, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT + { 0x2A84, 0x2A83 }, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT + { 0x2A85, 0x2A86 }, // [BEST FIT] LESS-THAN OR APPROXIMATE + { 0x2A86, 0x2A85 }, // [BEST FIT] GREATER-THAN OR APPROXIMATE + { 0x2A87, 0x2A88 }, // [BEST FIT] LESS-THAN AND SINGLE-LINE NOT EQUAL TO + { 0x2A88, 0x2A87 }, // [BEST FIT] GREATER-THAN AND SINGLE-LINE NOT EQUAL TO + { 0x2A89, 0x2A8A }, // [BEST FIT] LESS-THAN AND NOT APPROXIMATE + { 0x2A8A, 0x2A89 }, // [BEST FIT] GREATER-THAN AND NOT APPROXIMATE + { 0x2A8B, 0x2A8C }, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN + { 0x2A8C, 0x2A8B }, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN + { 0x2A8D, 0x2A8E }, // [BEST FIT] LESS-THAN ABOVE SIMILAR OR EQUAL + { 0x2A8E, 0x2A8D }, // [BEST FIT] GREATER-THAN ABOVE SIMILAR OR EQUAL + { 0x2A8F, 0x2A90 }, // [BEST FIT] LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN + { 0x2A90, 0x2A8F }, // [BEST FIT] GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN + { 0x2A91, 0x2A92 }, // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL + { 0x2A92, 0x2A91 }, // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL + { 0x2A93, 0x2A94 }, // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL + { 0x2A94, 0x2A93 }, // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL + { 0x2A95, 0x2A96 }, // SLANTED EQUAL TO OR LESS-THAN + { 0x2A96, 0x2A95 }, // SLANTED EQUAL TO OR GREATER-THAN + { 0x2A97, 0x2A98 }, // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE + { 0x2A98, 0x2A97 }, // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE + { 0x2A99, 0x2A9A }, // DOUBLE-LINE EQUAL TO OR LESS-THAN + { 0x2A9A, 0x2A99 }, // DOUBLE-LINE EQUAL TO OR GREATER-THAN + { 0x2A9B, 0x2A9C }, // DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN + { 0x2A9C, 0x2A9B }, // DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN + { 0x2A9D, 0x2A9E }, // [BEST FIT] SIMILAR OR LESS-THAN + { 0x2A9E, 0x2A9D }, // [BEST FIT] SIMILAR OR GREATER-THAN + { 0x2A9F, 0x2AA0 }, // [BEST FIT] SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN + { 0x2AA0, 0x2A9F }, // [BEST FIT] SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN + { 0x2AA1, 0x2AA2 }, // DOUBLE NESTED LESS-THAN + { 0x2AA2, 0x2AA1 }, // DOUBLE NESTED GREATER-THAN + { 0x2AA6, 0x2AA7 }, // LESS-THAN CLOSED BY CURVE + { 0x2AA7, 0x2AA6 }, // GREATER-THAN CLOSED BY CURVE + { 0x2AA8, 0x2AA9 }, // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + { 0x2AA9, 0x2AA8 }, // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + { 0x2AAA, 0x2AAB }, // SMALLER THAN + { 0x2AAB, 0x2AAA }, // LARGER THAN + { 0x2AAC, 0x2AAD }, // SMALLER THAN OR EQUAL TO + { 0x2AAD, 0x2AAC }, // LARGER THAN OR EQUAL TO + { 0x2AAF, 0x2AB0 }, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + { 0x2AB0, 0x2AAF }, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + { 0x2AB1, 0x2AB2 }, // [BEST FIT] PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO + { 0x2AB2, 0x2AB1 }, // [BEST FIT] SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO + { 0x2AB3, 0x2AB4 }, // PRECEDES ABOVE EQUALS SIGN + { 0x2AB4, 0x2AB3 }, // SUCCEEDS ABOVE EQUALS SIGN + { 0x2AB5, 0x2AB6 }, // [BEST FIT] PRECEDES ABOVE NOT EQUAL TO + { 0x2AB6, 0x2AB5 }, // [BEST FIT] SUCCEEDS ABOVE NOT EQUAL TO + { 0x2AB7, 0x2AB8 }, // [BEST FIT] PRECEDES ABOVE ALMOST EQUAL TO + { 0x2AB8, 0x2AB7 }, // [BEST FIT] SUCCEEDS ABOVE ALMOST EQUAL TO + { 0x2AB9, 0x2ABA }, // [BEST FIT] PRECEDES ABOVE NOT ALMOST EQUAL TO + { 0x2ABA, 0x2AB9 }, // [BEST FIT] SUCCEEDS ABOVE NOT ALMOST EQUAL TO + { 0x2ABB, 0x2ABC }, // DOUBLE PRECEDES + { 0x2ABC, 0x2ABB }, // DOUBLE SUCCEEDS + { 0x2ABD, 0x2ABE }, // SUBSET WITH DOT + { 0x2ABE, 0x2ABD }, // SUPERSET WITH DOT + { 0x2ABF, 0x2AC0 }, // SUBSET WITH PLUS SIGN BELOW + { 0x2AC0, 0x2ABF }, // SUPERSET WITH PLUS SIGN BELOW + { 0x2AC1, 0x2AC2 }, // SUBSET WITH MULTIPLICATION SIGN BELOW + { 0x2AC2, 0x2AC1 }, // SUPERSET WITH MULTIPLICATION SIGN BELOW + { 0x2AC3, 0x2AC4 }, // SUBSET OF OR EQUAL TO WITH DOT ABOVE + { 0x2AC4, 0x2AC3 }, // SUPERSET OF OR EQUAL TO WITH DOT ABOVE + { 0x2AC5, 0x2AC6 }, // SUBSET OF ABOVE EQUALS SIGN + { 0x2AC6, 0x2AC5 }, // SUPERSET OF ABOVE EQUALS SIGN + { 0x2AC7, 0x2AC8 }, // [BEST FIT] SUBSET OF ABOVE TILDE OPERATOR + { 0x2AC8, 0x2AC7 }, // [BEST FIT] SUPERSET OF ABOVE TILDE OPERATOR + { 0x2AC9, 0x2ACA }, // [BEST FIT] SUBSET OF ABOVE ALMOST EQUAL TO + { 0x2ACA, 0x2AC9 }, // [BEST FIT] SUPERSET OF ABOVE ALMOST EQUAL TO + { 0x2ACB, 0x2ACC }, // [BEST FIT] SUBSET OF ABOVE NOT EQUAL TO + { 0x2ACC, 0x2ACB }, // [BEST FIT] SUPERSET OF ABOVE NOT EQUAL TO + { 0x2ACD, 0x2ACE }, // SQUARE LEFT OPEN BOX OPERATOR + { 0x2ACE, 0x2ACD }, // SQUARE RIGHT OPEN BOX OPERATOR + { 0x2ACF, 0x2AD0 }, // CLOSED SUBSET + { 0x2AD0, 0x2ACF }, // CLOSED SUPERSET + { 0x2AD1, 0x2AD2 }, // CLOSED SUBSET OR EQUAL TO + { 0x2AD2, 0x2AD1 }, // CLOSED SUPERSET OR EQUAL TO + { 0x2AD3, 0x2AD4 }, // SUBSET ABOVE SUPERSET + { 0x2AD4, 0x2AD3 }, // SUPERSET ABOVE SUBSET + { 0x2AD5, 0x2AD6 }, // SUBSET ABOVE SUBSET + { 0x2AD6, 0x2AD5 }, // SUPERSET ABOVE SUPERSET + { 0x2ADE, 0x22A6 }, // SHORT LEFT TACK + { 0x2AE3, 0x22A9 }, // DOUBLE VERTICAL BAR LEFT TURNSTILE + { 0x2AE4, 0x22A8 }, // VERTICAL BAR DOUBLE LEFT TURNSTILE + { 0x2AE5, 0x22AB }, // DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE + { 0x2AEC, 0x2AED }, // DOUBLE STROKE NOT SIGN + { 0x2AED, 0x2AEC }, // REVERSED DOUBLE STROKE NOT SIGN + { 0x2AEE, 0x2224 }, // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH + { 0x2AF7, 0x2AF8 }, // TRIPLE NESTED LESS-THAN + { 0x2AF8, 0x2AF7 }, // TRIPLE NESTED GREATER-THAN + { 0x2AF9, 0x2AFA }, // DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO + { 0x2AFA, 0x2AF9 }, // DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO + { 0x2BFE, 0x221F }, // REVERSED RIGHT ANGLE + { 0x2E02, 0x2E03 }, // LEFT SUBSTITUTION BRACKET + { 0x2E03, 0x2E02 }, // RIGHT SUBSTITUTION BRACKET + { 0x2E04, 0x2E05 }, // LEFT DOTTED SUBSTITUTION BRACKET + { 0x2E05, 0x2E04 }, // RIGHT DOTTED SUBSTITUTION BRACKET + { 0x2E09, 0x2E0A }, // LEFT TRANSPOSITION BRACKET + { 0x2E0A, 0x2E09 }, // RIGHT TRANSPOSITION BRACKET + { 0x2E0C, 0x2E0D }, // LEFT RAISED OMISSION BRACKET + { 0x2E0D, 0x2E0C }, // RIGHT RAISED OMISSION BRACKET + { 0x2E1C, 0x2E1D }, // LEFT LOW PARAPHRASE BRACKET + { 0x2E1D, 0x2E1C }, // RIGHT LOW PARAPHRASE BRACKET + { 0x2E20, 0x2E21 }, // LEFT VERTICAL BAR WITH QUILL + { 0x2E21, 0x2E20 }, // RIGHT VERTICAL BAR WITH QUILL + { 0x2E22, 0x2E23 }, // TOP LEFT HALF BRACKET + { 0x2E23, 0x2E22 }, // TOP RIGHT HALF BRACKET + { 0x2E24, 0x2E25 }, // BOTTOM LEFT HALF BRACKET + { 0x2E25, 0x2E24 }, // BOTTOM RIGHT HALF BRACKET + { 0x2E26, 0x2E27 }, // LEFT SIDEWAYS U BRACKET + { 0x2E27, 0x2E26 }, // RIGHT SIDEWAYS U BRACKET + { 0x2E28, 0x2E29 }, // LEFT DOUBLE PARENTHESIS + { 0x2E29, 0x2E28 }, // RIGHT DOUBLE PARENTHESIS + { 0x2E55, 0x2E56 }, // LEFT SQUARE BRACKET WITH STROKE + { 0x2E56, 0x2E55 }, // RIGHT SQUARE BRACKET WITH STROKE + { 0x2E57, 0x2E58 }, // LEFT SQUARE BRACKET WITH DOUBLE STROKE + { 0x2E58, 0x2E57 }, // RIGHT SQUARE BRACKET WITH DOUBLE STROKE + { 0x2E59, 0x2E5A }, // TOP HALF LEFT PARENTHESIS + { 0x2E5A, 0x2E59 }, // TOP HALF RIGHT PARENTHESIS + { 0x2E5B, 0x2E5C }, // BOTTOM HALF LEFT PARENTHESIS + { 0x2E5C, 0x2E5B }, // BOTTOM HALF RIGHT PARENTHESIS + { 0x3008, 0x3009 }, // LEFT ANGLE BRACKET + { 0x3009, 0x3008 }, // RIGHT ANGLE BRACKET + { 0x300A, 0x300B }, // LEFT DOUBLE ANGLE BRACKET + { 0x300B, 0x300A }, // RIGHT DOUBLE ANGLE BRACKET + { 0x300C, 0x300D }, // [BEST FIT] LEFT CORNER BRACKET + { 0x300D, 0x300C }, // [BEST FIT] RIGHT CORNER BRACKET + { 0x300E, 0x300F }, // [BEST FIT] LEFT WHITE CORNER BRACKET + { 0x300F, 0x300E }, // [BEST FIT] RIGHT WHITE CORNER BRACKET + { 0x3010, 0x3011 }, // LEFT BLACK LENTICULAR BRACKET + { 0x3011, 0x3010 }, // RIGHT BLACK LENTICULAR BRACKET + { 0x3014, 0x3015 }, // LEFT TORTOISE SHELL BRACKET + { 0x3015, 0x3014 }, // RIGHT TORTOISE SHELL BRACKET + { 0x3016, 0x3017 }, // LEFT WHITE LENTICULAR BRACKET + { 0x3017, 0x3016 }, // RIGHT WHITE LENTICULAR BRACKET + { 0x3018, 0x3019 }, // LEFT WHITE TORTOISE SHELL BRACKET + { 0x3019, 0x3018 }, // RIGHT WHITE TORTOISE SHELL BRACKET + { 0x301A, 0x301B }, // LEFT WHITE SQUARE BRACKET + { 0x301B, 0x301A }, // RIGHT WHITE SQUARE BRACKET + { 0xFE59, 0xFE5A }, // SMALL LEFT PARENTHESIS + { 0xFE5A, 0xFE59 }, // SMALL RIGHT PARENTHESIS + { 0xFE5B, 0xFE5C }, // SMALL LEFT CURLY BRACKET + { 0xFE5C, 0xFE5B }, // SMALL RIGHT CURLY BRACKET + { 0xFE5D, 0xFE5E }, // SMALL LEFT TORTOISE SHELL BRACKET + { 0xFE5E, 0xFE5D }, // SMALL RIGHT TORTOISE SHELL BRACKET + { 0xFE64, 0xFE65 }, // SMALL LESS-THAN SIGN + { 0xFE65, 0xFE64 }, // SMALL GREATER-THAN SIGN + { 0xFF08, 0xFF09 }, // FULLWIDTH LEFT PARENTHESIS + { 0xFF09, 0xFF08 }, // FULLWIDTH RIGHT PARENTHESIS + { 0xFF1C, 0xFF1E }, // FULLWIDTH LESS-THAN SIGN + { 0xFF1E, 0xFF1C }, // FULLWIDTH GREATER-THAN SIGN + { 0xFF3B, 0xFF3D }, // FULLWIDTH LEFT SQUARE BRACKET + { 0xFF3D, 0xFF3B }, // FULLWIDTH RIGHT SQUARE BRACKET + { 0xFF5B, 0xFF5D }, // FULLWIDTH LEFT CURLY BRACKET + { 0xFF5D, 0xFF5B }, // FULLWIDTH RIGHT CURLY BRACKET + { 0xFF5F, 0xFF60 }, // FULLWIDTH LEFT WHITE PARENTHESIS + { 0xFF60, 0xFF5F }, // FULLWIDTH RIGHT WHITE PARENTHESIS + { 0xFF62, 0xFF63 }, // [BEST FIT] HALFWIDTH LEFT CORNER BRACKET + { 0xFF63, 0xFF62 }, // [BEST FIT] HALFWIDTH RIGHT CORNER BRACKET + { 0xFFFF, 0xFFFF }, // Boundary +}; + +char32_t get_mirror_char(char32_t c) { + const unsigned short (*pp)[2] = mirror_pairs; + size_t a = 0, b = sizeof(mirror_pairs) / sizeof(mirror_pairs[0]); + + //while (a + 1 < b) { + // generate branchless code + int i; + for (i = 0; i < 9; i++) { + size_t m = (a + b) / 2; + if (pp[m][0] > c) + b = m; + else + a = m; + } + return (c == pp[a][0]) ? pp[a][1] : c; +} + +/* Bidirectional algorithm should be rewritten. + Heavily modified version from early code by Dov Grobgeld + */ + +// XXX: these tables are obsolete, complete rewrite is needed +static const unsigned short bidir_char_type_start[366] = { + 0x0000, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x001c, + 0x001f, 0x0020, 0x0021, 0x0023, 0x0026, 0x002b, 0x002c, 0x002d, + 0x002e, 0x002f, 0x0030, 0x003a, 0x003b, 0x0041, 0x005b, 0x0061, + 0x007b, 0x007f, 0x0085, 0x0086, 0x00a0, 0x00a1, 0x00a2, 0x00a6, + 0x00aa, 0x00ab, 0x00b0, 0x00b2, 0x00b4, 0x00b5, 0x00b6, 0x00b9, + 0x00ba, 0x00bb, 0x00c0, 0x00d7, 0x00d8, 0x00f7, 0x00f8, 0x02b9, + 0x02bb, 0x02c2, 0x02d0, 0x02d2, 0x02e0, 0x02e5, 0x02ee, 0x0300, + 0x0374, 0x037a, 0x037e, 0x0386, 0x0387, 0x0388, 0x0483, 0x048c, + 0x058a, 0x0591, 0x05be, 0x05bf, 0x05c0, 0x05c1, 0x05c3, 0x05c4, + 0x05d0, 0x0600, 0x061b, 0x064b, 0x0660, 0x066a, 0x066b, 0x066d, + 0x0670, 0x0671, 0x06d6, 0x06e5, 0x06e7, 0x06e9, 0x06ea, 0x06f0, + 0x06fa, 0x070f, 0x0710, 0x0711, 0x0712, 0x0730, 0x0780, 0x07a6, + 0x0800, 0x0900, 0x0903, 0x093c, 0x093d, 0x0941, 0x0949, 0x094d, + 0x0950, 0x0951, 0x0958, 0x0962, 0x0964, 0x0981, 0x0982, 0x09bc, + 0x09be, 0x09c1, 0x09c7, 0x09cd, 0x09d7, 0x09e2, 0x09e6, 0x09f2, + 0x09f4, 0x0a00, 0x0a05, 0x0a3c, 0x0a3e, 0x0a41, 0x0a59, 0x0a70, + 0x0a72, 0x0a81, 0x0a83, 0x0abc, 0x0abd, 0x0ac1, 0x0ac9, 0x0acd, + 0x0ad0, 0x0b00, 0x0b02, 0x0b3c, 0x0b3d, 0x0b3f, 0x0b40, 0x0b41, + 0x0b47, 0x0b4d, 0x0b57, 0x0b82, 0x0b83, 0x0bc0, 0x0bc1, 0x0bcd, + 0x0bd7, 0x0c3e, 0x0c41, 0x0c46, 0x0c60, 0x0cbf, 0x0cc0, 0x0cc6, + 0x0cc7, 0x0ccc, 0x0cd5, 0x0d41, 0x0d46, 0x0d4d, 0x0d57, 0x0dca, + 0x0dcf, 0x0dd2, 0x0dd8, 0x0e31, 0x0e32, 0x0e34, 0x0e3f, 0x0e40, + 0x0e47, 0x0e4f, 0x0eb1, 0x0eb2, 0x0eb4, 0x0ebd, 0x0ec8, 0x0ed0, + 0x0f18, 0x0f1a, 0x0f35, 0x0f36, 0x0f37, 0x0f38, 0x0f39, 0x0f3a, + 0x0f3e, 0x0f71, 0x0f7f, 0x0f80, 0x0f85, 0x0f86, 0x0f88, 0x0f90, + 0x0fbe, 0x0fc6, 0x0fc7, 0x102d, 0x1031, 0x1032, 0x1038, 0x1039, + 0x1040, 0x1058, 0x10a0, 0x1680, 0x1681, 0x169b, 0x16a0, 0x17b7, + 0x17be, 0x17c6, 0x17c7, 0x17c9, 0x17d4, 0x17db, 0x17dc, 0x1800, + 0x180b, 0x1810, 0x18a9, 0x1900, 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc2, + 0x1fcd, 0x1fd0, 0x1fdd, 0x1fe0, 0x1fed, 0x1ff2, 0x1ffd, 0x2000, + 0x200b, 0x200e, 0x200f, 0x2010, 0x2028, 0x2029, 0x202a, 0x202b, + 0x202c, 0x202d, 0x202e, 0x202f, 0x2030, 0x2035, 0x206a, 0x2070, + 0x207a, 0x207c, 0x207f, 0x2080, 0x208a, 0x208c, 0x20a0, 0x20d0, + 0x2100, 0x2102, 0x2103, 0x2107, 0x2108, 0x210a, 0x2114, 0x2115, + 0x2116, 0x2119, 0x211e, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, + 0x2129, 0x212a, 0x212e, 0x212f, 0x2132, 0x2133, 0x213a, 0x2160, + 0x2190, 0x2212, 0x2214, 0x2336, 0x237b, 0x2395, 0x2396, 0x2460, + 0x249c, 0x24ea, 0x2500, 0x2900, 0x2e00, 0x3000, 0x3001, 0x3005, + 0x3008, 0x3021, 0x302a, 0x3030, 0x3031, 0x3036, 0x3038, 0x303e, + 0x3041, 0x3099, 0x309b, 0x309d, 0x30fb, 0x30fc, 0xa490, 0xa500, + 0xfb1d, 0xfb1e, 0xfb1f, 0xfb29, 0xfb2a, 0xfb50, 0xfd3e, 0xfd50, + 0xfe00, 0xfe30, 0xfe50, 0xfe51, 0xfe52, 0xfe54, 0xfe55, 0xfe56, + 0xfe5f, 0xfe60, 0xfe62, 0xfe64, 0xfe69, 0xfe6b, 0xfe70, 0xfeff, + 0xff00, 0xff03, 0xff06, 0xff0b, 0xff0c, 0xff0d, 0xff0e, 0xff0f, + 0xff10, 0xff1a, 0xff1b, 0xff21, 0xff3b, 0xff41, 0xff5b, 0xff66, + 0xffe0, 0xffe2, 0xffe5, 0xffe8, 0xfff9, 0xfffc, +}; + +#define LTR BIDIR_TYPE_LTR /* Strong Left-to-Right */ +#define RTL BIDIR_TYPE_RTL /* Right-to-left characters */ +#define WL BIDIR_TYPE_WL /* Weak left to right */ +#define WR BIDIR_TYPE_WR /* Weak right to left */ +#define EN BIDIR_TYPE_EN /* European Numeral */ +#define ES BIDIR_TYPE_ES /* European number Separator */ +#define ET BIDIR_TYPE_ET /* European number Terminator */ +#define AN BIDIR_TYPE_AN /* Arabic Numeral */ +#define CS BIDIR_TYPE_CS /* Common Separator */ +#define BS BIDIR_TYPE_BS /* Block Separator */ +#define SS BIDIR_TYPE_SS /* Segment Separator */ +#define WS BIDIR_TYPE_WS /* Whitespace */ +#define AL BIDIR_TYPE_AL /* Arabic Letter */ +#define NSM BIDIR_TYPE_NSM /* Non Spacing Mark */ +#define BN BIDIR_TYPE_BN /* Boundary Neutral */ +#define ON BIDIR_TYPE_ON /* Other Neutral */ +#define LRE BIDIR_TYPE_LRE /* Left-to-Right Embedding */ +#define RLE BIDIR_TYPE_RLE /* Right-to-Left Embedding */ +#define PDF BIDIR_TYPE_PDF /* Pop Directional Flag */ +#define LRO BIDIR_TYPE_LRO /* Left-to-Right Override */ +#define RLO BIDIR_TYPE_RLO /* Right-to-Left Override */ + +static const unsigned char bidir_char_type_val[366] = { + BN, SS, BS, SS, WS, BS, BN, BS, SS, WS, ON, ET, ON, ET, CS, ET, + CS, ES, EN, CS, ON, LTR, ON, LTR, ON, BN, BS, BN, CS, ON, ET, ON, + LTR, ON, ET, EN, ON, LTR, ON, EN, LTR, ON, LTR, ON, LTR, ON, LTR, ON, + LTR, ON, LTR, ON, LTR, ON, LTR, NSM, ON, LTR, ON, LTR, ON, LTR, NSM, LTR, + ON, NSM, RTL, NSM, RTL, NSM, RTL, NSM, RTL, CS, AL, NSM, AN, ET, AN, AL, + NSM, AL, NSM, AL, NSM, ON, NSM, EN, AL, BN, AL, NSM, AL, NSM, AL, NSM, + LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, + LTR, NSM, LTR, NSM, LTR, NSM, LTR, ET, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, + LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, + LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, + LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, ET, LTR, + NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, ON, + LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, LTR, NSM, + LTR, NSM, LTR, WS, LTR, ON, LTR, NSM, LTR, NSM, LTR, NSM, LTR, ET, LTR, ON, + BN, LTR, NSM, LTR, ON, LTR, ON, LTR, ON, LTR, ON, LTR, ON, LTR, ON, WS, + BN, LTR, RTL, ON, WS, BS, LRE, RLE, PDF, LRO, RLO, WS, ET, ON, BN, EN, + ET, ON, LTR, EN, ET, ON, ET, NSM, ON, LTR, ON, LTR, ON, LTR, ON, LTR, + ON, LTR, ON, LTR, ON, LTR, ON, LTR, ON, LTR, ET, LTR, ON, LTR, ON, LTR, + ON, ET, ON, LTR, ON, LTR, ON, EN, LTR, EN, ON, LTR, ON, WS, ON, LTR, + ON, LTR, NSM, ON, LTR, ON, LTR, ON, LTR, NSM, ON, LTR, ON, LTR, ON, LTR, + RTL, NSM, RTL, ET, RTL, AL, ON, AL, NSM, ON, CS, ON, CS, ON, CS, ON, + ET, ON, ET, ON, ET, ON, AL, BN, ON, ET, ON, ET, CS, ET, CS, ES, + EN, CS, ON, LTR, ON, LTR, ON, LTR, ET, ON, ET, ON, BN, ON, +}; + +BidirCharType bidir_get_type(char32_t ch) { + /* use a binary lookup loop */ + size_t a = 0; + size_t b = countof(bidir_char_type_start); + //while (b - a > 1) { + int i; + for (i = 0; i < 9; i++) { + size_t m = (a + b) >> 1; + if (ch < bidir_char_type_start[m]) + b = m; + else + a = m; + } + return bidir_char_type_val[a]; +} + +/* version for test with ASCII chars */ +BidirCharType bidir_get_type_test(char32_t ch) { + if (ch >= 'A' && ch <= 'Z') + return BIDIR_TYPE_RTL; + else + return bidir_get_type(ch); +} + +/* Some convenience macros */ +#define RL_TYPE(list) (list)->type +#define RL_LEN(list) (list)->len +#define RL_POS(list) (list)->pos +#define RL_LEVEL(list) (list)->level + +static void compact_list(BidirTypeLink *list_tab) { + BidirTypeLink *p = list_tab; + BidirTypeLink *q = list_tab; + for (;;) { + BidirCharType type = p->type; + *q = *p++; + if (type == BIDIR_TYPE_EOT) + break; + if (type != BIDIR_TYPE_DEL) { + while (p->type == type) { + q->len += p->len; + p++; + } + q++; + } + } +} + +/* Define a rule macro */ + +/* Rules for overriding current type */ +#define TYPE_RULE1(old_this, new_this) \ + if (this_type == TYPE_ ## old_this) \ + RL_TYPE(pp) = BIDIR_TYPE_ ## new_this; \ + +/* Rules for current and previous type */ +#define TYPE_RULE2(old_prev, old_this, \ + new_prev, new_this) \ + if (prev_type == BIDIR_TYPE_ ## old_prev \ + && this_type == BIDIR_TYPE_ ## old_this) { \ + RL_TYPE(pp-1) = BIDIR_TYPE_ ## new_prev; \ + RL_TYPE(pp) = BIDIR_TYPE_ ## new_this; \ + continue; \ + } + +/* A full rule that assigns all three types */ +#define TYPE_RULE(old_prev, old_this, old_next, \ + new_prev, new_this, new_next) \ + if (prev_type == BIDIR_TYPE_ ## old_prev \ + && this_type == BIDIR_TYPE_ ## old_this \ + && next_type == BIDIR_TYPE_ ## old_next) { \ + RL_TYPE(pp-1) = BIDIR_TYPE_ ## new_prev; \ + RL_TYPE(pp) = BIDIR_TYPE_ ## new_this; \ + RL_TYPE(pp+2) = BIDIR_TYPE_ ## new_next; \ + continue; \ + } + +/* For optimization the following macro only assigns the center type */ +#define TYPE_RULE_C(old_prev, old_this, old_next, \ + new_this) \ + if (prev_type == BIDIR_TYPE_ ## old_prev \ + && this_type == BIDIR_TYPE_ ## old_this \ + && next_type == BIDIR_TYPE_ ## old_next) { \ + RL_TYPE(pp) = BIDIR_TYPE_ ## new_this; \ + continue; \ + } + +#ifdef DEBUG + +/*====================================================================== +// For debugging, define some macros for printing the types and the +// levels. +//----------------------------------------------------------------------*/ +static int type_to_char(int type) { + switch (type) { + case BIDIR_TYPE_R: return 'R'; + case BIDIR_TYPE_L: return 'L'; + case BIDIR_TYPE_E: return 'E'; + case BIDIR_TYPE_EN: return 'n'; + case BIDIR_TYPE_N: return 'N'; + default: return '?'; +} + +static void print_types_re(const BidirTypeLink *pp, int level) { + for (pp++; pp->type != BIDIR_TYPE_EOT; pp++) { + printf("%d:%c(%d)[%d] ", RL_POS(pp), type_to_char(RL_TYPE(pp)), RL_LEN(pp), level ? RL_LEVEL(pp) : 0); + } + printf("\n"); +} + +#endif + +#define STACK_SIZE 64 + +#define ONE_OF_2(t,a,b) ((1L << (t)) & ((1L << (a)) | (1L << (b)))) +#define ONE_OF_3(t,a,b,c) \ + ((1L << (t)) & ((1L << (a)) | (1L << (b)) | (1L << (c)))) +#define ONE_OF_4(t,a,b,c,d) \ + ((1L << (t)) & ((1L << (a)) | (1L << (b)) | (1L << (c)) | (1L << (d)))) +#define ONE_OF_6(t,a,b,c,d,e,f) \ + ((1L << (t)) & ((1L << (a)) | (1L << (b)) | (1L << (c)) | \ + (1L << (d)) | (1L << (e)) | (1L << (f)))) + +/*====================================================================== +// This function should follow the Unicode specification closely! +// +// It is still lacking the support for and . +//----------------------------------------------------------------------*/ +void bidir_analyze_string(BidirTypeLink *type_rl_list, + BidirCharType *pbase_dir, + int *pmax_level) +{ + int base_level, base_dir; + int max_level, level, override; + int last_strong; + BidirTypeLink *pp; + unsigned char stack_level[STACK_SIZE]; + unsigned char stack_override[STACK_SIZE]; + int stack_index; + +#ifdef DEBUG + print_types_re(type_rl_list, 0); +#endif + + /* Find the base level */ + if (*pbase_dir == BIDIR_TYPE_L) { + base_dir = BIDIR_TYPE_L; + base_level = 0; + } else + if (*pbase_dir == BIDIR_TYPE_R) { + base_dir = BIDIR_TYPE_R; + base_level = 1; + } else { + /* Search for first strong character and use its direction as base + direction */ + base_level = 0; /* Default */ + base_dir = BIDIR_TYPE_N; + for (pp = type_rl_list; pp->type != BIDIR_TYPE_EOT; pp++) { + int type; + type = RL_TYPE(pp); + if (ONE_OF_3(type, BIDIR_TYPE_R, BIDIR_TYPE_RLE, BIDIR_TYPE_RLO)) { + base_level = 1; + base_dir = BIDIR_TYPE_R; + break; + } else + if (ONE_OF_3(type, BIDIR_TYPE_L, BIDIR_TYPE_LRE, BIDIR_TYPE_LRO)) { + base_level = 0; + base_dir = BIDIR_TYPE_L; + break; + } + } + + /* If no strong base_dir was found, resort to the weak direction + * that was passed on input. + */ + if (base_dir == BIDIR_TYPE_N) { + if (*pbase_dir == BIDIR_TYPE_WR) { + base_dir = BIDIR_TYPE_RTL; + base_level = 1; + } else + if (*pbase_dir == BIDIR_TYPE_WL) { + base_dir = BIDIR_TYPE_LTR; + base_level = 0; + } + } + } + + /* hack for RLE/LRE/RLO/LRO/PDF. It is not complete in case of + errors or with neutrals. Need more work. */ + level = base_level; + override = BIDIR_TYPE_N; + stack_index = 0; + for (pp = type_rl_list + 1; pp->type != BIDIR_TYPE_EOT; pp++) { + int type, i; + type = RL_TYPE(pp); + if (ONE_OF_4(type, BIDIR_TYPE_LRE, BIDIR_TYPE_RLE, BIDIR_TYPE_LRO, BIDIR_TYPE_RLO)) { + for (i = 0; i < RL_LEN(pp); i++) { + if (stack_index < STACK_SIZE) { + /* push level & override */ + stack_level[stack_index] = level; + stack_override[stack_index] = override; + stack_index++; + /* compute new level */ + if (ONE_OF_2(type, BIDIR_TYPE_LRE, BIDIR_TYPE_LRO)) { + level = (level + 2) & ~1; /* least greater even */ + } else { + level = (level + 1) | 1; /* least greater odd */ + } + /* compute new override */ + if (type == BIDIR_TYPE_LRO) + override = BIDIR_TYPE_L; + else + if (type == BIDIR_TYPE_RLO) + override = BIDIR_TYPE_R; + else + override = BIDIR_TYPE_N; + } + } + RL_TYPE(pp) = BIDIR_TYPE_DEL; + } else if (type == BIDIR_TYPE_PDF) { + for (i = 0; i < RL_LEN(pp); i++) { + if (stack_index > 0) { + stack_index--; + /* pop level & override */ + level = stack_level[stack_index]; + override = stack_override[stack_index]; + } + } + RL_TYPE(pp) = BIDIR_TYPE_DEL; + } else { + RL_LEVEL(pp) = level; + /* if override defined, then modify type accordingly */ + if (override != BIDIR_TYPE_N) + RL_TYPE(pp) = override; + } + } + + compact_list(type_rl_list); + + /* 4. Resolving weak types */ + last_strong = base_dir; + for (pp = type_rl_list + 1; pp->type != BIDIR_TYPE_EOT; pp++) { + int prev_type = RL_TYPE(pp-1); + int this_type = RL_TYPE(pp); + int next_type = RL_TYPE(pp+1); + + /* Remember the last strong character */ + if (ONE_OF_3(prev_type, BIDIR_TYPE_AL, BIDIR_TYPE_R, BIDIR_TYPE_L)) + last_strong = prev_type; + + /* W1. NSM */ + if (this_type == BIDIR_TYPE_NSM) { + if (prev_type == BIDIR_TYPE_SOT) + RL_TYPE(pp) = BIDIR_TYPE_N; /* Will be resolved to base dir */ + else + RL_TYPE(pp) = prev_type; + } + /* W2: European numbers */ + if (this_type == BIDIR_TYPE_N && last_strong == BIDIR_TYPE_AL) + RL_TYPE(pp) = BIDIR_TYPE_AN; + + /* W3: Change ALs to R + We have to do this for prev character as we would otherwise + interfer with the next last_strong which is BIDIR_TYPE_AL. + */ + if (prev_type == BIDIR_TYPE_AL) + RL_TYPE(pp-1) = BIDIR_TYPE_R; + + /* W4. A single european separator changes to a european number. + A single common separator between two numbers of the same type + changes to that type. + */ + if (RL_LEN(pp) == 1 && prev_type == next_type) { + TYPE_RULE_C(EN, ES, EN, EN); + TYPE_RULE_C(EN, CS, EN, EN); + TYPE_RULE_C(AN, CS, AN, AN); + } + /* W5. A sequence of European terminators adjacent to European + numbers changes to All European numbers. + */ + if (this_type == BIDIR_TYPE_ET) { + if (next_type == BIDIR_TYPE_EN || prev_type == BIDIR_TYPE_EN) { + RL_TYPE(pp) = BIDIR_TYPE_EN; + } + } + /* This type may have been overriden */ + this_type = RL_TYPE(pp); + + /* W6. Otherwise change separators and terminators to other neutral */ + if (ONE_OF_3(this_type, BIDIR_TYPE_ET, BIDIR_TYPE_CS, BIDIR_TYPE_ES)) + RL_TYPE(pp) = BIDIR_TYPE_ON; + + /* W7. Change european numbers to L. */ + if (prev_type == BIDIR_TYPE_EN && last_strong == BIDIR_TYPE_L) + RL_TYPE(pp-1) = BIDIR_TYPE_L; + } + + compact_list(type_rl_list); + + /* 5. Resolving Neutral Types */ + + /* We can now collapse all separators and other neutral types to + plain neutrals */ + for (pp = type_rl_list + 1; pp->type != BIDIR_TYPE_EOT; pp++) { + int this_type = RL_TYPE(pp); + if (ONE_OF_6(this_type, BIDIR_TYPE_WS, BIDIR_TYPE_ON, BIDIR_TYPE_ES, + BIDIR_TYPE_ET, BIDIR_TYPE_CS, BIDIR_TYPE_BN)) { + RL_TYPE(pp) = BIDIR_TYPE_N; + } + } + + compact_list(type_rl_list); + + for (pp = type_rl_list + 1; pp->type != BIDIR_TYPE_EOT; pp++) { + if (RL_TYPE(pp) == BIDIR_TYPE_N) { /* optimization! */ + int prev_type = RL_TYPE(pp-1); + int next_type = RL_TYPE(pp+1); + + /* "European and arabic numbers are treated + as though they were R" */ + + /* N1. */ + if (prev_type == BIDIR_TYPE_L && next_type == BIDIR_TYPE_L) + RL_TYPE(pp) = BIDIR_TYPE_L; + else + if (ONE_OF_3(prev_type, BIDIR_TYPE_EN, BIDIR_TYPE_AN, BIDIR_TYPE_R) + && ONE_OF_3(next_type, BIDIR_TYPE_EN, BIDIR_TYPE_AN, BIDIR_TYPE_R)) + RL_TYPE(pp) = BIDIR_TYPE_R; + else + /* N2. Any remaining neutrals takes the embedding direction */ + if (RL_TYPE(pp) == BIDIR_TYPE_N) + RL_TYPE(pp) = BIDIR_TYPE_E; + } + } + + compact_list(type_rl_list); + + /* 6. Resolving Implicit levels */ + max_level = base_level; + + for (pp = type_rl_list + 1; pp->type != BIDIR_TYPE_EOT; pp++) { + int this_type = RL_TYPE(pp); + + level = RL_LEVEL(pp); + if ((level & 1) == 0) { + /* Even */ + if (this_type == BIDIR_TYPE_R) + RL_LEVEL(pp) = level + 1; + else if (this_type == BIDIR_TYPE_AN) + RL_LEVEL(pp) = level + 2; + else if (RL_TYPE(pp-1) != BIDIR_TYPE_L && this_type == BIDIR_TYPE_EN) + RL_LEVEL(pp) = level + 2; + else + RL_LEVEL(pp) = level; + } else { + /* Odd */ + if (ONE_OF_3(this_type, BIDIR_TYPE_L, BIDIR_TYPE_AN, BIDIR_TYPE_EN)) + RL_LEVEL(pp) = level + 1; + else + RL_LEVEL(pp) = level; + } + + if (RL_LEVEL(pp) > max_level) + max_level = RL_LEVEL(pp); + } + + compact_list(type_rl_list); + + *pmax_level = max_level; + *pbase_dir = base_dir; +} diff --git a/unicode_join.h b/unicode_join.h index dd44f42..1ad041e 100644 --- a/unicode_join.h +++ b/unicode_join.h @@ -31,13 +31,63 @@ int unicode_to_glyphs(char32_t *dst, unsigned int *char_to_glyph_pos, int dst_size, char32_t *src, int src_size, int reverse); +char32_t get_mirror_char(char32_t c); + +// XXX: should rewrite this part +typedef enum { + BIDIR_TYPE_LTR, /* Strong Left-to-Right */ + BIDIR_TYPE_RTL, /* Right-to-left characters */ + BIDIR_TYPE_WL, /* Weak left to right */ + BIDIR_TYPE_WR, /* Weak right to left */ + BIDIR_TYPE_EN, /* European Numeral */ + BIDIR_TYPE_ES, /* European number Separator */ + BIDIR_TYPE_ET, /* European number Terminator */ + BIDIR_TYPE_AN, /* Arabic Numeral */ + BIDIR_TYPE_CS, /* Common Separator */ + BIDIR_TYPE_BS, /* Block Separator */ + BIDIR_TYPE_SS, /* Segment Separator */ + BIDIR_TYPE_WS, /* Whitespace */ + BIDIR_TYPE_AL, /* Arabic Letter */ + BIDIR_TYPE_NSM, /* Non Spacing Mark */ + BIDIR_TYPE_BN, /* Boundary Neutral */ + BIDIR_TYPE_ON, /* Other Neutral */ + BIDIR_TYPE_LRE, /* Left-to-Right Embedding */ + BIDIR_TYPE_RLE, /* Right-to-Left Embedding */ + BIDIR_TYPE_PDF, /* Pop Directional Flag */ + BIDIR_TYPE_LRO, /* Left-to-Right Override */ + BIDIR_TYPE_RLO, /* Right-to-Left Override */ + + /* The following are only used internally */ + BIDIR_TYPE_SOT, + BIDIR_TYPE_EOT, + BIDIR_TYPE_N, + BIDIR_TYPE_E, + BIDIR_TYPE_CTL, /* Control units */ + BIDIR_TYPE_EO, /* Control units */ + BIDIR_TYPE_DEL, /* type record is to be deleted */ + BIDIR_TYPE_L = BIDIR_TYPE_LTR, + BIDIR_TYPE_R = BIDIR_TYPE_RTL, + BIDIR_TYPE_CM = BIDIR_TYPE_ON + 2, +} BidirCharType; + +typedef struct BidirTypeLink { + BidirCharType type; + int pos; + int len; + int level; +} BidirTypeLink; + +BidirCharType bidir_get_type(char32_t ch); +BidirCharType bidir_get_type_test(char32_t ch); + +void bidir_analyze_string(BidirTypeLink *type_rl_list, + BidirCharType *pbase_dir, + int *pmax_level); + /* arabic.c */ int arabic_join(char32_t *line, unsigned int *ctog, int len); /* indic.c */ int devanagari_log2vis(char32_t *str, unsigned int *ctog, int len); -// XXX: should rewrite this part -#include "qfribidi.h" - #endif /* UNICODE_JOIN_H */