From: simon Date: Sat, 22 May 2004 10:36:50 +0000 (+0000) Subject: At last! After much delay, much faffing back and forth, and much X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/commitdiff_plain/f0fccd51c27b5cbe8990e625a7bdcf9972142d1f At last! After much delay, much faffing back and forth, and much enhancement and fiddling, I have now massaged Arabeyes' first patch into a form I'm happy to check in. Phew. git-svn-id: svn://svn.tartarus.org/sgt/putty@4236 cda61777-01e9-0310-a592-d414129be87e --- diff --git a/Recipe b/Recipe index 8cbc841e..e2811cc9 100644 --- a/Recipe +++ b/Recipe @@ -166,13 +166,16 @@ install-strip: # names. A line beginning `+' is assumed to continue the previous # line. +# Terminal emulator and its (platform-independent) dependencies. +TERMINAL = terminal wcwidth ldiscucs logging tree234 minibidi + + config dialog + # GUI front end and terminal emulator (putty, puttytel). -GUITERM = window windlg winctrls terminal sizetip wcwidth unicode ldiscucs - + logging printing winutils dialog config wincfg tree234 +GUITERM = TERMINAL window windlg winctrls sizetip unicode printing + + winutils wincfg # Same thing on Unix. -UXTERM = pterm config uxcfg dialog gtkdlg gtkcols gtkpanel tree234 - + terminal wcwidth uxucs ldiscucs logging uxprint xkeysym +UXTERM = TERMINAL pterm uxcfg gtkdlg gtkcols gtkpanel uxucs uxprint xkeysym # Non-SSH back ends (putty, puttytel, plink). NONSSH = telnet raw rlogin ldisc diff --git a/config.c b/config.c index 68aaee74..de3a6132 100644 --- a/config.c +++ b/config.c @@ -1037,6 +1037,12 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, ctrl_checkbox(s, "Disable remote-controlled character set configuration", 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler, I(offsetof(Config,no_remote_charset))); + ctrl_checkbox(s, "Disable Arabic text shaping", + 'l', HELPCTX(no_help), dlg_stdcheckbox_handler, + I(offsetof(Config, arabicshaping))); + ctrl_checkbox(s, "Disable bidirectional text display", + 'j', HELPCTX(no_help), dlg_stdcheckbox_handler, + I(offsetof(Config, bidi))); /* * The Window panel. diff --git a/doc/config.but b/doc/config.but index 9dc8ae18..503f9663 100644 --- a/doc/config.but +++ b/doc/config.but @@ -1,4 +1,4 @@ -\versionid $Id: config.but,v 1.77 2004/04/24 20:05:03 jacob Exp $ +\versionid $Id: config.but,v 1.78 2004/05/22 10:36:50 simon Exp $ \C{config} Configuring PuTTY @@ -822,6 +822,47 @@ If you find that accented characters are not showing up the way you expect them to, particularly if you're running BitchX, you could try disabling the remote character set configuration commands. +\S{config-features-shaping} Disabling Arabic text shaping + +\cfg{winhelp-topic}{features.arabicshaping} + +PuTTY supports shaping of Arabic text, which means that if your +server sends text written in the basic Unicode Arabic alphabet then +it will convert it to the correct display forms before printing it +on the screen. + +If you are using full-screen software which was not expecting this +to happen (especially if you are not an Arabic speaker and you +unexpectedly find yourself dealing with Arabic text files in +applications which are not Arabic-aware), you might find that the +display becomes corrupted. By ticking this box, you can disable +Arabic text shaping so that PuTTY displays precisely the characters +it is told to display. + +You may also find you need to disable bidirectional text display; +see \S{config-features-bidi}. + +\S{config-features-bidi} Disabling bidirectional text display + +\cfg{winhelp-topic}{features.bidi} + +PuTTY supports bidirectional text display, which means that if your +server sends text written in a language which is usually displayed +from right to left (such as Arabic or Hebrew) then PuTTY will +automatically flip it round so that it is displayed in the right +direction on the screen. + +If you are using full-screen software which was not expecting this +to happen (especially if you are not an Arabic speaker and you +unexpectedly find yourself dealing with Arabic text files in +applications which are not Arabic-aware), you might find that the +display becomes corrupted. By ticking this box, you can disable +bidirectional text display, so that PuTTY displays text from left to +right in all situations. + +You may also find you need to disable Arabic text shaping; +see \S{config-features-arabicshaping}. + \H{config-window} The Window panel The Window configuration panel allows you to control aspects of the diff --git a/ldisc.c b/ldisc.c index e5727186..d57e6d17 100644 --- a/ldisc.c +++ b/ldisc.c @@ -32,13 +32,20 @@ static int plen(Ldisc ldisc, unsigned char c) return 1; else if (c < 128) return 2; /* ^x for some x */ + else if (in_utf(ldisc->term) && c >= 0xC0) + return 1; /* UTF-8 introducer character + * (FIXME: combining / wide chars) */ + else if (in_utf(ldisc->term) && c >= 0x80 && c < 0xC0) + return 0; /* UTF-8 followup character */ else - return 4; /* for hex XY */ + return 4; /* hex representation */ } static void pwrite(Ldisc ldisc, unsigned char c) { - if ((c >= 32 && c <= 126) || (c >= 160 && !in_utf(ldisc->term))) { + if ((c >= 32 && c <= 126) || + (!in_utf(ldisc->term) && c >= 0xA0) || + (in_utf(ldisc->term) && c >= 0x80)) { c_write(ldisc, (char *)&c, 1); } else if (c < 128) { char cc[2]; @@ -52,6 +59,14 @@ static void pwrite(Ldisc ldisc, unsigned char c) } } +static int char_start(Ldisc ldisc, unsigned char c) +{ + if (in_utf(ldisc->term)) + return (c < 0x80 || c >= 0xC0); + else + return 1; +} + static void bsb(Ldisc ldisc, int n) { while (n--) @@ -137,7 +152,9 @@ void ldisc_send(void *handle, char *buf, int len, int interactive) c += KCTRL('@'); switch (ldisc->quotenext ? ' ' : c) { /* - * ^h/^?: delete one char and output one BSB + * ^h/^?: delete, and output BSBs, to return to + * last character boundary (in UTF-8 mode this may + * be more than one byte) * ^w: delete, and output BSBs, to return to last * space/nonspace boundary * ^u: delete, and output BSBs, to return to BOL @@ -153,9 +170,11 @@ void ldisc_send(void *handle, char *buf, int len, int interactive) case KCTRL('H'): case KCTRL('?'): /* backspace/delete */ if (ldisc->buflen > 0) { - if (ECHOING) - bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1])); - ldisc->buflen--; + do { + if (ECHOING) + bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1])); + ldisc->buflen--; + } while (!char_start(ldisc, ldisc->buf[ldisc->buflen])); } break; case CTRL('W'): /* delete word */ diff --git a/minibidi.c b/minibidi.c new file mode 100644 index 00000000..9943ae39 --- /dev/null +++ b/minibidi.c @@ -0,0 +1,1788 @@ +/************************************************************************ + * $Id: minibidi.c,v 1.1 2004/05/22 10:36:50 simon Exp $ + * + * ------------ + * Description: + * ------------ + * This is an implemention of Unicode's Bidirectional Algorithm + * (known as UAX #9). + * + * http://www.unicode.org/reports/tr9/ + * + * Author: Ahmad Khalifa + * + * ----------------- + * Revision Details: (Updated by Revision Control System) + * ----------------- + * $Date: 2004/05/22 10:36:50 $ + * $Author: simon $ + * $Revision: 1.1 $ + * $Source: /u1/simon/svn-migration/cvs/putty/minibidi.c,v $ + * + * (www.arabeyes.org - under MIT license) + * + ************************************************************************/ + +/* + * TODO: + * ===== + * - Explicit marks need to be handled (they are not 100% now) + * - Ligatures + */ + +#include "minibidi.h" + +/* + * Flips the text buffer, according to max level, and + * all higher levels + * + * Input: + * from: text buffer, on which to apply flipping + * level: resolved levels buffer + * max: the maximum level found in this line (should be unsigned char) + * count: line size in bidi_char + */ +void flipThisRun(bidi_char *from, unsigned char *level, int max, int count) +{ + int i, j, rcount, tlevel; + bidi_char temp; + + j = i = 0; + while(i((i-j)/2); rcount--) + { + temp = from[j+rcount-1]; + from[j+rcount-1] = from[i-rcount]; + from[i-rcount] = temp; + } + } +} + +/* + * Finds the index of a run with level equals tlevel + */ +int findIndexOfRun(unsigned char* level , int start, int count, int tlevel) +{ + int i; + for(i=start; i0 && level[from] == current) + { + from--; + } + return level[++from]; +} + +/* + * Returns the first odd value greater than x + */ +unsigned char leastGreaterOdd(unsigned char x) +{ + if((x % 2) == 0) + return x+1; + else + return x+2; +} + +/* + * Returns the first even value greater than x + */ +unsigned char leastGreaterEven(unsigned char x) +{ + if((x % 2) == 0) + return x+2; + else + return x+1; +} + +/* + * Loops over the RLE_table array looking for the + * type of ch + */ +unsigned char getRLE(wchar_t ch) +{ + int offset, i, freq; + + freq = offset = 0; + for(i=0; i<0xFFFF; i++) + { + freq = ((RLENode*)RLE_table)[i].f; + offset += freq; + if(offset == ch) + return ((RLENode*)RLE_table)[i].d; + else if(offset > ch) + return ((RLENode*)RLE_table)[i-1].d; + } + /* this is here to stop compiler nagging */ + return ON; +} + +/* The Main shaping function, and the only one to be used + * by the outside world. + * + * line: buffer to apply shaping to. this must be passed by doBidi() first + * to: output buffer for the shaped data + * count: number of characters in line + */ +int do_shape(bidi_char *line, bidi_char *to, int count) +{ + int i, tempShape, ligFlag; + + for(ligFlag=i=0; i= 0) + { + if(types[j] == AL) + { + types[i] = AN; + break; + }else if(types[j] == R || types[j] == L) + { + break; + } + j--; + } + } + } + + /* Rule (W3) + * W3. Change all ALs to R. + * + * Optimization: on Rule Xn, we might set a flag on AL type + * to prevent this loop in L R lines only... + */ + for(i=0; i= 0) + { + if(types[j] == L) + { + types[i] = L; + break; + } + else if(types[j] == R || types[j] == AL) + { + break; + } + j--; + } + } + } + + /* Rule (N1) + * N1. A sequence of neutrals takes the direction of the surrounding + * strong text if the text on both sides has the same direction. European + * and Arabic numbers are treated as though they were R. + */ + if(types[0] == ON) + { + if((types[1] == R) || (types[1] == EN) || (types[1] == AN)) + types[0] = R; + else if(types[1] == L) + types[0] = L; + } + for(i=1; i<(count-1); i++) + { + if(types[i] == ON) + { + if(types[i-1] == L) + { + j=i; + while(j<(count-1) && types[j] == ON) + { + j++; + } + if(types[j] == L) + { + while(i0 && (getType(line[j].wc) == WS)) + { + j--; + } + if(j < (count-1)) + { + for(j++; j=i ; j--) + { + levels[j] = paragraphLevel; + } + } + }else if(tempType == B || tempType == S) + levels[i] = paragraphLevel; + } + + /* Rule (L4) NOT IMPLEMENTED + * L4. A character that possesses the mirrored property as specified by + * Section 4.7, Mirrored, must be depicted by a mirrored glyph if the + * resolved directionality of that character is R. + */ + /* Note: this is implemented before L2 for efficiency */ + for(i=0; i tempType) + { + tempType = levels[i]; + imax=i; + } + i++; + } + /* maximum level in tempType, its index in imax. */ + while(tempType > 0) /* loop from highest level to the least odd, */ + { /* which i assume is 1 */ + flipThisRun(line, levels, tempType, count); + tempType--; + } + + /* Rule (L3) NOT IMPLEMENTED + * L3. Combining marks applied to a right-to-left base character will at + * this point precede their base character. If the rendering engine + * expects them to follow the base characters in the final display + * process, then the ordering of the marks and the base character must + * be reversed. + */ + free(types); + free(levels); + return R; +} + + +/* + * Bad, Horrible funtion + * takes a pointer to a character that is checked for + * having a mirror glyph. + */ +void doMirror(wchar_t* ch) +{ + if((*ch & 0xFF00) == 0) + { + switch(*ch) + { + case 0x0028: + *ch = 0x0029; + break; + case 0x0029: + *ch = 0x0028; + break; + case 0x003C: + *ch = 0x003E; + break; + case 0x003E: + *ch = 0x003C; + break; + case 0x005B: + *ch = 0x005D; + break; + case 0x005D: + *ch = 0x005B; + break; + case 0x007B: + *ch = 0x007D; + break; + case 0x007D: + *ch = 0x007B; + break; + case 0x00AB: + *ch = 0x00BB; + break; + case 0x00BB: + *ch = 0x00AB; + break; + } + } + else if((*ch & 0xFF00) == 0x2000) + { + switch(*ch) + { + case 0x2039: + *ch = 0x203A; + break; + case 0x203A: + *ch = 0x2039; + break; + case 0x2045: + *ch = 0x2046; + break; + case 0x2046: + *ch = 0x2045; + break; + case 0x207D: + *ch = 0x207E; + break; + case 0x207E: + *ch = 0x207D; + break; + case 0x208D: + *ch = 0x208E; + break; + case 0x208E: + *ch = 0x208D; + break; + } + } + else if((*ch & 0xFF00) == 0x2200) + { + switch(*ch) + { + case 0x2208: + *ch = 0x220B; + break; + case 0x2209: + *ch = 0x220C; + break; + case 0x220A: + *ch = 0x220D; + break; + case 0x220B: + *ch = 0x2208; + break; + case 0x220C: + *ch = 0x2209; + break; + case 0x220D: + *ch = 0x220A; + break; + case 0x2215: + *ch = 0x29F5; + break; + case 0x223C: + *ch = 0x223D; + break; + case 0x223D: + *ch = 0x223C; + break; + case 0x2243: + *ch = 0x22CD; + break; + case 0x2252: + *ch = 0x2253; + break; + case 0x2253: + *ch = 0x2252; + break; + case 0x2254: + *ch = 0x2255; + break; + case 0x2255: + *ch = 0x2254; + break; + case 0x2264: + *ch = 0x2265; + break; + case 0x2265: + *ch = 0x2264; + break; + case 0x2266: + *ch = 0x2267; + break; + case 0x2267: + *ch = 0x2266; + break; + case 0x2268: + *ch = 0x2269; + break; + case 0x2269: + *ch = 0x2268; + break; + case 0x226A: + *ch = 0x226B; + break; + case 0x226B: + *ch = 0x226A; + break; + case 0x226E: + *ch = 0x226F; + break; + case 0x226F: + *ch = 0x226E; + break; + case 0x2270: + *ch = 0x2271; + break; + case 0x2271: + *ch = 0x2270; + break; + case 0x2272: + *ch = 0x2273; + break; + case 0x2273: + *ch = 0x2272; + break; + case 0x2274: + *ch = 0x2275; + break; + case 0x2275: + *ch = 0x2274; + break; + case 0x2276: + *ch = 0x2277; + break; + case 0x2277: + *ch = 0x2276; + break; + case 0x2278: + *ch = 0x2279; + break; + case 0x2279: + *ch = 0x2278; + break; + case 0x227A: + *ch = 0x227B; + break; + case 0x227B: + *ch = 0x227A; + break; + case 0x227C: + *ch = 0x227D; + break; + case 0x227D: + *ch = 0x227C; + break; + case 0x227E: + *ch = 0x227F; + break; + case 0x227F: + *ch = 0x227E; + break; + case 0x2280: + *ch = 0x2281; + break; + case 0x2281: + *ch = 0x2280; + break; + case 0x2282: + *ch = 0x2283; + break; + case 0x2283: + *ch = 0x2282; + break; + case 0x2284: + *ch = 0x2285; + break; + case 0x2285: + *ch = 0x2284; + break; + case 0x2286: + *ch = 0x2287; + break; + case 0x2287: + *ch = 0x2286; + break; + case 0x2288: + *ch = 0x2289; + break; + case 0x2289: + *ch = 0x2288; + break; + case 0x228A: + *ch = 0x228B; + break; + case 0x228B: + *ch = 0x228A; + break; + case 0x228F: + *ch = 0x2290; + break; + case 0x2290: + *ch = 0x228F; + break; + case 0x2291: + *ch = 0x2292; + break; + case 0x2292: + *ch = 0x2291; + break; + case 0x2298: + *ch = 0x29B8; + break; + case 0x22A2: + *ch = 0x22A3; + break; + case 0x22A3: + *ch = 0x22A2; + break; + case 0x22A6: + *ch = 0x2ADE; + break; + case 0x22A8: + *ch = 0x2AE4; + break; + case 0x22A9: + *ch = 0x2AE3; + break; + case 0x22AB: + *ch = 0x2AE5; + break; + case 0x22B0: + *ch = 0x22B1; + break; + case 0x22B1: + *ch = 0x22B0; + break; + case 0x22B2: + *ch = 0x22B3; + break; + case 0x22B3: + *ch = 0x22B2; + break; + case 0x22B4: + *ch = 0x22B5; + break; + case 0x22B5: + *ch = 0x22B4; + break; + case 0x22B6: + *ch = 0x22B7; + break; + case 0x22B7: + *ch = 0x22B6; + break; + case 0x22C9: + *ch = 0x22CA; + break; + case 0x22CA: + *ch = 0x22C9; + break; + case 0x22CB: + *ch = 0x22CC; + break; + case 0x22CC: + *ch = 0x22CB; + break; + case 0x22CD: + *ch = 0x2243; + break; + case 0x22D0: + *ch = 0x22D1; + break; + case 0x22D1: + *ch = 0x22D0; + break; + case 0x22D6: + *ch = 0x22D7; + break; + case 0x22D7: + *ch = 0x22D6; + break; + case 0x22D8: + *ch = 0x22D9; + break; + case 0x22D9: + *ch = 0x22D8; + break; + case 0x22DA: + *ch = 0x22DB; + break; + case 0x22DB: + *ch = 0x22DA; + break; + case 0x22DC: + *ch = 0x22DD; + break; + case 0x22DD: + *ch = 0x22DC; + break; + case 0x22DE: + *ch = 0x22DF; + break; + case 0x22DF: + *ch = 0x22DE; + break; + case 0x22E0: + *ch = 0x22E1; + break; + case 0x22E1: + *ch = 0x22E0; + break; + case 0x22E2: + *ch = 0x22E3; + break; + case 0x22E3: + *ch = 0x22E2; + break; + case 0x22E4: + *ch = 0x22E5; + break; + case 0x22E5: + *ch = 0x22E4; + break; + case 0x22E6: + *ch = 0x22E7; + break; + case 0x22E7: + *ch = 0x22E6; + break; + case 0x22E8: + *ch = 0x22E9; + break; + case 0x22E9: + *ch = 0x22E8; + break; + case 0x22EA: + *ch = 0x22EB; + break; + case 0x22EB: + *ch = 0x22EA; + break; + case 0x22EC: + *ch = 0x22ED; + break; + case 0x22ED: + *ch = 0x22EC; + break; + case 0x22F0: + *ch = 0x22F1; + break; + case 0x22F1: + *ch = 0x22F0; + break; + case 0x22F2: + *ch = 0x22FA; + break; + case 0x22F3: + *ch = 0x22FB; + break; + case 0x22F4: + *ch = 0x22FC; + break; + case 0x22F6: + *ch = 0x22FD; + break; + case 0x22F7: + *ch = 0x22FE; + break; + case 0x22FA: + *ch = 0x22F2; + break; + case 0x22FB: + *ch = 0x22F3; + break; + case 0x22FC: + *ch = 0x22F4; + break; + case 0x22FD: + *ch = 0x22F6; + break; + case 0x22FE: + *ch = 0x22F7; + break; + } + }else if((*ch & 0xFF00) == 0x2300) + { + switch(*ch) + { + case 0x2308: + *ch = 0x2309; + break; + case 0x2309: + *ch = 0x2308; + break; + case 0x230A: + *ch = 0x230B; + break; + case 0x230B: + *ch = 0x230A; + break; + case 0x2329: + *ch = 0x232A; + break; + case 0x232A: + *ch = 0x2329; + break; + } + } + else if((*ch & 0xFF00) == 0x2700) + { + switch(*ch) + { + case 0x2768: + *ch = 0x2769; + break; + case 0x2769: + *ch = 0x2768; + break; + case 0x276A: + *ch = 0x276B; + break; + case 0x276B: + *ch = 0x276A; + break; + case 0x276C: + *ch = 0x276D; + break; + case 0x276D: + *ch = 0x276C; + break; + case 0x276E: + *ch = 0x276F; + break; + case 0x276F: + *ch = 0x276E; + break; + case 0x2770: + *ch = 0x2771; + break; + case 0x2771: + *ch = 0x2770; + break; + case 0x2772: + *ch = 0x2773; + break; + case 0x2773: + *ch = 0x2772; + break; + case 0x2774: + *ch = 0x2775; + break; + case 0x2775: + *ch = 0x2774; + break; + case 0x27D5: + *ch = 0x27D6; + break; + case 0x27D6: + *ch = 0x27D5; + break; + case 0x27DD: + *ch = 0x27DE; + break; + case 0x27DE: + *ch = 0x27DD; + break; + case 0x27E2: + *ch = 0x27E3; + break; + case 0x27E3: + *ch = 0x27E2; + break; + case 0x27E4: + *ch = 0x27E5; + break; + case 0x27E5: + *ch = 0x27E4; + break; + case 0x27E6: + *ch = 0x27E7; + break; + case 0x27E7: + *ch = 0x27E6; + break; + case 0x27E8: + *ch = 0x27E9; + break; + case 0x27E9: + *ch = 0x27E8; + break; + case 0x27EA: + *ch = 0x27EB; + break; + case 0x27EB: + *ch = 0x27EA; + break; + } + } + else if((*ch & 0xFF00) == 0x2900) + { + switch(*ch) + { + case 0x2983: + *ch = 0x2984; + break; + case 0x2984: + *ch = 0x2983; + break; + case 0x2985: + *ch = 0x2986; + break; + case 0x2986: + *ch = 0x2985; + break; + case 0x2987: + *ch = 0x2988; + break; + case 0x2988: + *ch = 0x2987; + break; + case 0x2989: + *ch = 0x298A; + break; + case 0x298A: + *ch = 0x2989; + break; + case 0x298B: + *ch = 0x298C; + break; + case 0x298C: + *ch = 0x298B; + break; + case 0x298D: + *ch = 0x2990; + break; + case 0x298E: + *ch = 0x298F; + break; + case 0x298F: + *ch = 0x298E; + break; + case 0x2990: + *ch = 0x298D; + break; + case 0x2991: + *ch = 0x2992; + break; + case 0x2992: + *ch = 0x2991; + break; + case 0x2993: + *ch = 0x2994; + break; + case 0x2994: + *ch = 0x2993; + break; + case 0x2995: + *ch = 0x2996; + break; + case 0x2996: + *ch = 0x2995; + break; + case 0x2997: + *ch = 0x2998; + break; + case 0x2998: + *ch = 0x2997; + break; + case 0x29B8: + *ch = 0x2298; + break; + case 0x29C0: + *ch = 0x29C1; + break; + case 0x29C1: + *ch = 0x29C0; + break; + case 0x29C4: + *ch = 0x29C5; + break; + case 0x29C5: + *ch = 0x29C4; + break; + case 0x29CF: + *ch = 0x29D0; + break; + case 0x29D0: + *ch = 0x29CF; + break; + case 0x29D1: + *ch = 0x29D2; + break; + case 0x29D2: + *ch = 0x29D1; + break; + case 0x29D4: + *ch = 0x29D5; + break; + case 0x29D5: + *ch = 0x29D4; + break; + case 0x29D8: + *ch = 0x29D9; + break; + case 0x29D9: + *ch = 0x29D8; + break; + case 0x29DA: + *ch = 0x29DB; + break; + case 0x29DB: + *ch = 0x29DA; + break; + case 0x29F5: + *ch = 0x2215; + break; + case 0x29F8: + *ch = 0x29F9; + break; + case 0x29F9: + *ch = 0x29F8; + break; + case 0x29FC: + *ch = 0x29FD; + break; + case 0x29FD: + *ch = 0x29FC; + break; + } + } + else if((*ch & 0xFF00) == 0x2A00) + { + switch(*ch) + { + case 0x2A2B: + *ch = 0x2A2C; + break; + case 0x2A2C: + *ch = 0x2A2B; + break; + case 0x2A2D: + *ch = 0x2A2C; + break; + case 0x2A2E: + *ch = 0x2A2D; + break; + case 0x2A34: + *ch = 0x2A35; + break; + case 0x2A35: + *ch = 0x2A34; + break; + case 0x2A3C: + *ch = 0x2A3D; + break; + case 0x2A3D: + *ch = 0x2A3C; + break; + case 0x2A64: + *ch = 0x2A65; + break; + case 0x2A65: + *ch = 0x2A64; + break; + case 0x2A79: + *ch = 0x2A7A; + break; + case 0x2A7A: + *ch = 0x2A79; + break; + case 0x2A7D: + *ch = 0x2A7E; + break; + case 0x2A7E: + *ch = 0x2A7D; + break; + case 0x2A7F: + *ch = 0x2A80; + break; + case 0x2A80: + *ch = 0x2A7F; + break; + case 0x2A81: + *ch = 0x2A82; + break; + case 0x2A82: + *ch = 0x2A81; + break; + case 0x2A83: + *ch = 0x2A84; + break; + case 0x2A84: + *ch = 0x2A83; + break; + case 0x2A8B: + *ch = 0x2A8C; + break; + case 0x2A8C: + *ch = 0x2A8B; + break; + case 0x2A91: + *ch = 0x2A92; + break; + case 0x2A92: + *ch = 0x2A91; + break; + case 0x2A93: + *ch = 0x2A94; + break; + case 0x2A94: + *ch = 0x2A93; + break; + case 0x2A95: + *ch = 0x2A96; + break; + case 0x2A96: + *ch = 0x2A95; + break; + case 0x2A97: + *ch = 0x2A98; + break; + case 0x2A98: + *ch = 0x2A97; + break; + case 0x2A99: + *ch = 0x2A9A; + break; + case 0x2A9A: + *ch = 0x2A99; + break; + case 0x2A9B: + *ch = 0x2A9C; + break; + case 0x2A9C: + *ch = 0x2A9B; + break; + case 0x2AA1: + *ch = 0x2AA2; + break; + case 0x2AA2: + *ch = 0x2AA1; + break; + case 0x2AA6: + *ch = 0x2AA7; + break; + case 0x2AA7: + *ch = 0x2AA6; + break; + case 0x2AA8: + *ch = 0x2AA9; + break; + case 0x2AA9: + *ch = 0x2AA8; + break; + case 0x2AAA: + *ch = 0x2AAB; + break; + case 0x2AAB: + *ch = 0x2AAA; + break; + case 0x2AAC: + *ch = 0x2AAD; + break; + case 0x2AAD: + *ch = 0x2AAC; + break; + case 0x2AAF: + *ch = 0x2AB0; + break; + case 0x2AB0: + *ch = 0x2AAF; + break; + case 0x2AB3: + *ch = 0x2AB4; + break; + case 0x2AB4: + *ch = 0x2AB3; + break; + case 0x2ABB: + *ch = 0x2ABC; + break; + case 0x2ABC: + *ch = 0x2ABB; + break; + case 0x2ABD: + *ch = 0x2ABE; + break; + case 0x2ABE: + *ch = 0x2ABD; + break; + case 0x2ABF: + *ch = 0x2AC0; + break; + case 0x2AC0: + *ch = 0x2ABF; + break; + case 0x2AC1: + *ch = 0x2AC2; + break; + case 0x2AC2: + *ch = 0x2AC1; + break; + case 0x2AC3: + *ch = 0x2AC4; + break; + case 0x2AC4: + *ch = 0x2AC3; + break; + case 0x2AC5: + *ch = 0x2AC6; + break; + case 0x2AC6: + *ch = 0x2AC5; + break; + case 0x2ACD: + *ch = 0x2ACE; + break; + case 0x2ACE: + *ch = 0x2ACD; + break; + case 0x2ACF: + *ch = 0x2AD0; + break; + case 0x2AD0: + *ch = 0x2ACF; + break; + case 0x2AD1: + *ch = 0x2AD2; + break; + case 0x2AD2: + *ch = 0x2AD1; + break; + case 0x2AD3: + *ch = 0x2AD4; + break; + case 0x2AD4: + *ch = 0x2AD3; + break; + case 0x2AD5: + *ch = 0x2AD6; + break; + case 0x2AD6: + *ch = 0x2AD5; + break; + case 0x2ADE: + *ch = 0x22A6; + break; + case 0x2AE3: + *ch = 0x22A9; + break; + case 0x2AE4: + *ch = 0x22A8; + break; + case 0x2AE5: + *ch = 0x22AB; + break; + case 0x2AEC: + *ch = 0x2AED; + break; + case 0x2AED: + *ch = 0x2AEC; + break; + case 0x2AF7: + *ch = 0x2AF8; + break; + case 0x2AF8: + *ch = 0x2AF7; + break; + case 0x2AF9: + *ch = 0x2AFA; + break; + case 0x2AFA: + *ch = 0x2AF9; + break; + } + } + else if((*ch & 0xFF00) == 0x3000) + { + switch(*ch) + { + case 0x3008: + *ch = 0x3009; + break; + case 0x3009: + *ch = 0x3008; + break; + case 0x300A: + *ch = 0x300B; + break; + case 0x300B: + *ch = 0x300A; + break; + case 0x300C: + *ch = 0x300D; + break; + case 0x300D: + *ch = 0x300C; + break; + case 0x300E: + *ch = 0x300F; + break; + case 0x300F: + *ch = 0x300E; + break; + case 0x3010: + *ch = 0x3011; + break; + case 0x3011: + *ch = 0x3010; + break; + case 0x3014: + *ch = 0x3015; + break; + case 0x3015: + *ch = 0x3014; + break; + case 0x3016: + *ch = 0x3017; + break; + case 0x3017: + *ch = 0x3016; + break; + case 0x3018: + *ch = 0x3019; + break; + case 0x3019: + *ch = 0x3018; + break; + case 0x301A: + *ch = 0x301B; + break; + case 0x301B: + *ch = 0x301A; + break; + } + } + else if((*ch & 0xFF00) == 0xFF00) + { + switch(*ch) + { + case 0xFF08: + *ch = 0xFF09; + break; + case 0xFF09: + *ch = 0xFF08; + break; + case 0xFF1C: + *ch = 0xFF1E; + break; + case 0xFF1E: + *ch = 0xFF1C; + break; + case 0xFF3B: + *ch = 0xFF3D; + break; + case 0xFF3D: + *ch = 0xFF3B; + break; + case 0xFF5B: + *ch = 0xFF5D; + break; + case 0xFF5D: + *ch = 0xFF5B; + break; + case 0xFF5F: + *ch = 0xFF60; + break; + case 0xFF60: + *ch = 0xFF5F; + break; + case 0xFF62: + *ch = 0xFF63; + break; + case 0xFF63: + *ch = 0xFF62; + break; + } + } +} diff --git a/minibidi.h b/minibidi.h new file mode 100644 index 00000000..91df54ab --- /dev/null +++ b/minibidi.h @@ -0,0 +1,456 @@ +/************************************************************************ + * $Id: minibidi.h,v 1.1 2004/05/22 10:36:50 simon Exp $ + * + * ------------ + * Description: + * ------------ + * This is an implemention of Unicode's Bidirectional Algorithm + * (known as UAX #9). + * + * http://www.unicode.org/reports/tr9/ + * + * Author: Ahmad Khalifa + * + * ----------------- + * Revision Details: (Updated by Revision Control System) + * ----------------- + * $Date: 2004/05/22 10:36:50 $ + * $Author: simon $ + * $Revision: 1.1 $ + * $Source: /u1/simon/svn-migration/cvs/putty/minibidi.h,v $ + * + * (www.arabeyes.org - under MIT license) + * + ************************************************************************/ + +/* + * TODO: + * ===== + * - work almost finished + * - Shaping Table to be expanded to include the whole range. + * - Ligature handling + */ + +#include /* definition of wchar_t*/ + +#define LMASK 0x3F /* Embedding Level mask */ +#define OMASK 0xC0 /* Override mask */ +#define OISL 0x80 /* Override is L */ +#define OISR 0x40 /* Override is R */ + +/* Shaping Helpers */ +#define STYPE(xh) (((xh >= SHAPE_FIRST) && (xh <= SHAPE_LAST)) ? \ +shapetypes[xh-SHAPE_FIRST].type : SU) /*))*/ +#define SISOLATED(xh) (shapetypes[xh-SHAPE_FIRST].form_b) +#define SFINAL(xh) xh+1 +#define SINITIAL(xh) xh+2 +#define SMEDIAL(ch) ch+3 + +typedef struct bidi_char { + wchar_t origwc, wc; + unsigned short index; +} bidi_char; + +/* function declarations */ +void flipThisRun(bidi_char *from, unsigned char* level, int max, int count); +int findIndexOfRun(unsigned char* level , int start, int count, int tlevel); +unsigned char getType(wchar_t ch); +unsigned char setOverrideBits(unsigned char level, unsigned char override); +unsigned char getPreviousLevel(unsigned char* level, int from); +unsigned char leastGreaterOdd(unsigned char x); +unsigned char leastGreaterEven(unsigned char x); +unsigned char getRLE(wchar_t ch); +int do_shape(bidi_char *line, bidi_char *to, int count); +int do_bidi(bidi_char *line, int count); +void doMirror(wchar_t* ch); + +/* character types */ +enum +{ + L, + LRE, + LRO, + R, + AL, + RLE, + RLO, + PDF, + EN, + ES, + ET, + AN, + CS, + NSM, + BN, + B, + S, + WS, + ON, +}; + +/* Shaping Types */ +enum +{ + SL, /* Left-Joining, doesnt exist in U+0600 - U+06FF */ + SR, /* Right-Joining, ie has Isolated, Final */ + SD, /* Dual-Joining, ie has Isolated, Final, Initial, Medial */ + SU, /* Non-Joining */ + SC /* Join-Causing, like U+0640 (TATWEEL) */ +}; + +typedef struct{ + char type; + wchar_t form_b; +} shape_node; + +/* Kept near the actual table, for verification. */ +#define SHAPE_FIRST 0x621 +#define SHAPE_LAST 0x64A + +const shape_node shapetypes[] = { +/* index, Typ, Iso, Ligature Index*/ +/* 621 */ {SU, 0xFE80}, +/* 622 */ {SR, 0xFE81}, +/* 623 */ {SR, 0xFE83}, +/* 624 */ {SR, 0xFE85}, +/* 625 */ {SR, 0xFE87}, +/* 626 */ {SD, 0xFE89}, +/* 627 */ {SR, 0xFE8D}, +/* 628 */ {SD, 0xFE8F}, +/* 629 */ {SR, 0xFE93}, +/* 62A */ {SD, 0xFE95}, +/* 62B */ {SD, 0xFE99}, +/* 62C */ {SD, 0xFE9D}, +/* 62D */ {SD, 0xFEA1}, +/* 62E */ {SD, 0xFEA5}, +/* 62F */ {SR, 0xFEA9}, +/* 630 */ {SR, 0xFEAB}, +/* 631 */ {SR, 0xFEAD}, +/* 632 */ {SR, 0xFEAF}, +/* 633 */ {SD, 0xFEB1}, +/* 634 */ {SD, 0xFEB5}, +/* 635 */ {SD, 0xFEB9}, +/* 636 */ {SD, 0xFEBD}, +/* 637 */ {SD, 0xFEC1}, +/* 638 */ {SD, 0xFEC5}, +/* 639 */ {SD, 0xFEC9}, +/* 63A */ {SD, 0xFECD}, +/* 63B */ {SU, 0x0}, +/* 63C */ {SU, 0x0}, +/* 63D */ {SU, 0x0}, +/* 63E */ {SU, 0x0}, +/* 63F */ {SU, 0x0}, +/* 640 */ {SC, 0x0}, +/* 641 */ {SD, 0xFED1}, +/* 642 */ {SD, 0xFED5}, +/* 643 */ {SD, 0xFED9}, +/* 644 */ {SD, 0xFEDD}, +/* 645 */ {SD, 0xFEE1}, +/* 646 */ {SD, 0xFEE5}, +/* 647 */ {SD, 0xFEE9}, +/* 648 */ {SR, 0xFEED}, +/* 649 */ {SR, 0xFEEF}, /* SD */ +/* 64A */ {SD, 0xFEF1}, +}; + +/* + * This describes the data byte and its frequency + */ +typedef struct +{ + unsigned char f; + unsigned char d; +}RLENode; + + +/* This is an array of RLENodes, which is the + * Compressed unicode types table + */ +const unsigned char RLE_table[] = +{ + 0x09, 0x10, 0x01, 0x0F, 0x01, 0x10, 0x01, 0x11, + 0x01, 0x0F, 0x01, 0x0E, 0x0E, 0x0F, 0x03, 0x10, + 0x01, 0x11, 0x01, 0x12, 0x02, 0x0A, 0x03, 0x12, + 0x05, 0x0A, 0x01, 0x0C, 0x01, 0x0A, 0x01, 0x0C, + 0x01, 0x09, 0x01, 0x08, 0x0A, 0x0C, 0x01, 0x12, + 0x06, 0x00, 0x1A, 0x12, 0x06, 0x00, 0x1A, 0x12, + 0x04, 0x0E, 0x06, 0x0F, 0x01, 0x0E, 0x1A, 0x0C, + 0x01, 0x12, 0x01, 0x0A, 0x04, 0x12, 0x04, 0x00, + 0x01, 0x12, 0x05, 0x0A, 0x02, 0x08, 0x02, 0x12, + 0x01, 0x00, 0x01, 0x12, 0x03, 0x08, 0x01, 0x00, + 0x01, 0x12, 0x05, 0x00, 0x17, 0x12, 0x01, 0x00, + 0x1F, 0x12, 0x01, 0x00, 0xFF, 0x00, 0x2A, 0x12, + 0x01, 0x00, 0x12, 0x12, 0x1C, 0x00, 0x5E, 0x12, + 0x02, 0x00, 0x09, 0x12, 0x02, 0x00, 0x07, 0x12, + 0x0E, 0x00, 0x02, 0x12, 0x0E, 0x00, 0x05, 0x12, + 0x09, 0x00, 0x01, 0x12, 0x11, 0x0D, 0x50, 0x12, + 0x10, 0x0D, 0x10, 0x12, 0x0A, 0x00, 0x01, 0x12, + 0x0B, 0x00, 0x01, 0x12, 0x01, 0x00, 0x03, 0x12, + 0x01, 0x00, 0x01, 0x12, 0x01, 0x00, 0x14, 0x12, + 0x01, 0x00, 0x2C, 0x12, 0x01, 0x00, 0x26, 0x12, + 0x0A, 0x00, 0x83, 0x0D, 0x04, 0x12, 0x01, 0x0D, + 0x02, 0x00, 0x45, 0x12, 0x01, 0x00, 0x26, 0x12, + 0x02, 0x00, 0x02, 0x12, 0x06, 0x00, 0x10, 0x12, + 0x21, 0x00, 0x26, 0x12, 0x02, 0x00, 0x07, 0x12, + 0x01, 0x00, 0x27, 0x12, 0x01, 0x00, 0x01, 0x12, + 0x07, 0x0D, 0x11, 0x12, 0x01, 0x0D, 0x17, 0x12, + 0x01, 0x0D, 0x03, 0x03, 0x01, 0x0D, 0x01, 0x03, + 0x01, 0x0D, 0x02, 0x03, 0x01, 0x0D, 0x01, 0x12, + 0x0B, 0x03, 0x1B, 0x12, 0x05, 0x03, 0x05, 0x12, + 0x17, 0x0C, 0x01, 0x12, 0x0E, 0x04, 0x01, 0x12, + 0x03, 0x04, 0x01, 0x12, 0x01, 0x04, 0x1A, 0x12, + 0x05, 0x04, 0x0B, 0x0D, 0x0B, 0x12, 0x0A, 0x0B, + 0x0A, 0x0A, 0x01, 0x0B, 0x02, 0x04, 0x03, 0x0D, + 0x01, 0x04, 0x65, 0x0D, 0x07, 0x04, 0x01, 0x0D, + 0x07, 0x04, 0x02, 0x0D, 0x02, 0x12, 0x01, 0x0D, + 0x04, 0x12, 0x02, 0x08, 0x0A, 0x04, 0x05, 0x12, + 0x01, 0x04, 0x0E, 0x12, 0x01, 0x0E, 0x01, 0x04, + 0x01, 0x0D, 0x01, 0x04, 0x1B, 0x12, 0x03, 0x0D, + 0x1B, 0x12, 0x35, 0x04, 0x26, 0x0D, 0x0B, 0x04, + 0x01, 0x12, 0xFF, 0x12, 0x50, 0x0D, 0x02, 0x00, + 0x01, 0x12, 0x01, 0x00, 0x35, 0x12, 0x02, 0x0D, + 0x01, 0x00, 0x04, 0x0D, 0x08, 0x00, 0x04, 0x0D, + 0x01, 0x12, 0x02, 0x00, 0x01, 0x0D, 0x04, 0x12, + 0x03, 0x00, 0x0A, 0x0D, 0x02, 0x00, 0x0D, 0x12, + 0x10, 0x0D, 0x01, 0x00, 0x02, 0x12, 0x01, 0x00, + 0x08, 0x12, 0x02, 0x00, 0x02, 0x12, 0x02, 0x00, + 0x16, 0x12, 0x01, 0x00, 0x07, 0x12, 0x01, 0x00, + 0x01, 0x12, 0x03, 0x00, 0x04, 0x12, 0x02, 0x0D, + 0x01, 0x12, 0x01, 0x00, 0x03, 0x0D, 0x04, 0x12, + 0x02, 0x00, 0x02, 0x12, 0x02, 0x00, 0x02, 0x0D, + 0x01, 0x12, 0x09, 0x00, 0x01, 0x12, 0x04, 0x00, + 0x02, 0x12, 0x01, 0x00, 0x03, 0x0D, 0x02, 0x12, + 0x02, 0x00, 0x0C, 0x0A, 0x02, 0x00, 0x07, 0x12, + 0x07, 0x0D, 0x01, 0x12, 0x02, 0x00, 0x06, 0x12, + 0x04, 0x00, 0x02, 0x12, 0x02, 0x00, 0x16, 0x12, + 0x01, 0x00, 0x07, 0x12, 0x01, 0x00, 0x02, 0x12, + 0x01, 0x00, 0x02, 0x12, 0x01, 0x00, 0x02, 0x12, + 0x02, 0x0D, 0x01, 0x12, 0x01, 0x00, 0x03, 0x0D, + 0x02, 0x12, 0x04, 0x0D, 0x02, 0x12, 0x02, 0x0D, + 0x03, 0x12, 0x0B, 0x00, 0x04, 0x12, 0x01, 0x00, + 0x01, 0x12, 0x07, 0x00, 0x0A, 0x0D, 0x02, 0x00, + 0x03, 0x12, 0x0C, 0x0D, 0x02, 0x00, 0x01, 0x12, + 0x01, 0x00, 0x07, 0x12, 0x01, 0x00, 0x01, 0x12, + 0x01, 0x00, 0x03, 0x12, 0x01, 0x00, 0x16, 0x12, + 0x01, 0x00, 0x07, 0x12, 0x01, 0x00, 0x02, 0x12, + 0x01, 0x00, 0x05, 0x12, 0x02, 0x0D, 0x01, 0x00, + 0x04, 0x0D, 0x05, 0x12, 0x01, 0x0D, 0x02, 0x00, + 0x01, 0x12, 0x01, 0x00, 0x02, 0x0D, 0x01, 0x12, + 0x02, 0x00, 0x01, 0x12, 0x0F, 0x00, 0x01, 0x12, + 0x05, 0x00, 0x0A, 0x12, 0x11, 0x0D, 0x01, 0x00, + 0x02, 0x12, 0x01, 0x00, 0x08, 0x12, 0x02, 0x00, + 0x02, 0x12, 0x02, 0x00, 0x16, 0x12, 0x01, 0x00, + 0x07, 0x12, 0x01, 0x00, 0x02, 0x12, 0x02, 0x00, + 0x04, 0x12, 0x02, 0x0D, 0x01, 0x00, 0x02, 0x0D, + 0x01, 0x00, 0x01, 0x0D, 0x03, 0x12, 0x03, 0x00, + 0x02, 0x12, 0x02, 0x00, 0x02, 0x0D, 0x01, 0x12, + 0x08, 0x0D, 0x01, 0x00, 0x01, 0x12, 0x04, 0x00, + 0x02, 0x12, 0x01, 0x00, 0x03, 0x12, 0x04, 0x00, + 0x0B, 0x12, 0x11, 0x0D, 0x01, 0x00, 0x01, 0x12, + 0x01, 0x00, 0x06, 0x12, 0x03, 0x00, 0x03, 0x12, + 0x01, 0x00, 0x04, 0x12, 0x03, 0x00, 0x02, 0x12, + 0x01, 0x00, 0x01, 0x12, 0x01, 0x00, 0x02, 0x12, + 0x03, 0x00, 0x02, 0x12, 0x03, 0x00, 0x03, 0x12, + 0x03, 0x00, 0x08, 0x12, 0x01, 0x00, 0x03, 0x12, + 0x04, 0x00, 0x02, 0x0D, 0x01, 0x00, 0x02, 0x12, + 0x03, 0x00, 0x03, 0x12, 0x01, 0x00, 0x03, 0x0D, + 0x01, 0x12, 0x09, 0x00, 0x01, 0x12, 0x0F, 0x00, + 0x0C, 0x12, 0x0E, 0x00, 0x03, 0x12, 0x01, 0x00, + 0x08, 0x12, 0x01, 0x00, 0x03, 0x12, 0x01, 0x00, + 0x17, 0x12, 0x01, 0x00, 0x0A, 0x12, 0x01, 0x00, + 0x05, 0x12, 0x04, 0x0D, 0x03, 0x00, 0x04, 0x12, + 0x01, 0x0D, 0x03, 0x12, 0x01, 0x0D, 0x04, 0x12, + 0x07, 0x0D, 0x02, 0x12, 0x09, 0x00, 0x02, 0x12, + 0x04, 0x00, 0x0A, 0x12, 0x12, 0x00, 0x02, 0x12, + 0x01, 0x00, 0x08, 0x12, 0x01, 0x00, 0x03, 0x12, + 0x01, 0x00, 0x17, 0x12, 0x01, 0x00, 0x0A, 0x12, + 0x01, 0x00, 0x05, 0x12, 0x04, 0x00, 0x01, 0x0D, + 0x01, 0x00, 0x05, 0x12, 0x01, 0x0D, 0x01, 0x00, + 0x02, 0x12, 0x01, 0x00, 0x02, 0x0D, 0x02, 0x12, + 0x07, 0x00, 0x02, 0x12, 0x07, 0x00, 0x01, 0x12, + 0x01, 0x00, 0x02, 0x12, 0x04, 0x00, 0x0A, 0x12, + 0x12, 0x00, 0x02, 0x12, 0x01, 0x00, 0x08, 0x12, + 0x01, 0x00, 0x03, 0x12, 0x01, 0x00, 0x17, 0x12, + 0x01, 0x00, 0x10, 0x12, 0x04, 0x00, 0x03, 0x0D, + 0x03, 0x12, 0x02, 0x00, 0x03, 0x12, 0x01, 0x00, + 0x03, 0x0D, 0x01, 0x12, 0x09, 0x00, 0x01, 0x12, + 0x08, 0x00, 0x02, 0x12, 0x04, 0x00, 0x0A, 0x12, + 0x12, 0x00, 0x02, 0x12, 0x01, 0x00, 0x12, 0x12, + 0x03, 0x00, 0x18, 0x12, 0x01, 0x00, 0x09, 0x12, + 0x01, 0x00, 0x01, 0x12, 0x02, 0x00, 0x07, 0x12, + 0x03, 0x0D, 0x01, 0x12, 0x04, 0x00, 0x03, 0x0D, + 0x03, 0x12, 0x01, 0x0D, 0x01, 0x12, 0x01, 0x00, + 0x08, 0x12, 0x12, 0x00, 0x03, 0x12, 0x0C, 0x00, + 0x30, 0x0D, 0x01, 0x00, 0x02, 0x0D, 0x07, 0x12, + 0x04, 0x0A, 0x01, 0x00, 0x07, 0x0D, 0x08, 0x00, + 0x0D, 0x12, 0x25, 0x00, 0x02, 0x12, 0x01, 0x00, + 0x01, 0x12, 0x02, 0x00, 0x02, 0x12, 0x01, 0x00, + 0x01, 0x12, 0x02, 0x00, 0x01, 0x12, 0x06, 0x00, + 0x04, 0x12, 0x01, 0x00, 0x07, 0x12, 0x01, 0x00, + 0x03, 0x12, 0x01, 0x00, 0x01, 0x12, 0x01, 0x00, + 0x01, 0x12, 0x02, 0x00, 0x02, 0x12, 0x01, 0x00, + 0x04, 0x0D, 0x01, 0x00, 0x02, 0x0D, 0x06, 0x12, + 0x01, 0x0D, 0x02, 0x00, 0x01, 0x12, 0x02, 0x00, + 0x05, 0x12, 0x01, 0x00, 0x01, 0x12, 0x01, 0x0D, + 0x06, 0x12, 0x02, 0x00, 0x0A, 0x12, 0x02, 0x00, + 0x02, 0x12, 0x22, 0x00, 0x18, 0x0D, 0x02, 0x00, + 0x1B, 0x0D, 0x01, 0x00, 0x01, 0x0D, 0x01, 0x00, + 0x01, 0x0D, 0x01, 0x12, 0x04, 0x00, 0x0A, 0x12, + 0x01, 0x00, 0x22, 0x12, 0x06, 0x0D, 0x0E, 0x00, + 0x01, 0x0D, 0x05, 0x00, 0x01, 0x0D, 0x02, 0x00, + 0x04, 0x12, 0x04, 0x0D, 0x08, 0x12, 0x01, 0x0D, + 0x24, 0x12, 0x01, 0x00, 0x08, 0x0D, 0x01, 0x00, + 0x06, 0x12, 0x02, 0x00, 0x01, 0x12, 0x30, 0x00, + 0x22, 0x12, 0x01, 0x00, 0x05, 0x12, 0x01, 0x00, + 0x02, 0x12, 0x01, 0x00, 0x01, 0x0D, 0x04, 0x00, + 0x01, 0x0D, 0x01, 0x12, 0x03, 0x0D, 0x02, 0x00, + 0x01, 0x0D, 0x01, 0x12, 0x06, 0x00, 0x18, 0x0D, + 0x02, 0x12, 0x46, 0x00, 0x26, 0x12, 0x0A, 0x00, + 0x29, 0x12, 0x02, 0x00, 0x01, 0x12, 0x04, 0x00, + 0x5A, 0x12, 0x05, 0x00, 0x44, 0x12, 0x05, 0x00, + 0x52, 0x12, 0x06, 0x00, 0x07, 0x12, 0x01, 0x00, + 0x3F, 0x12, 0x01, 0x00, 0x01, 0x12, 0x01, 0x00, + 0x04, 0x12, 0x02, 0x00, 0x07, 0x12, 0x01, 0x00, + 0x01, 0x12, 0x01, 0x00, 0x04, 0x12, 0x02, 0x00, + 0x27, 0x12, 0x01, 0x00, 0x01, 0x12, 0x01, 0x00, + 0x04, 0x12, 0x02, 0x00, 0x1F, 0x12, 0x01, 0x00, + 0x01, 0x12, 0x01, 0x00, 0x04, 0x12, 0x02, 0x00, + 0x07, 0x12, 0x01, 0x00, 0x01, 0x12, 0x01, 0x00, + 0x04, 0x12, 0x02, 0x00, 0x07, 0x12, 0x01, 0x00, + 0x07, 0x12, 0x01, 0x00, 0x17, 0x12, 0x01, 0x00, + 0x1F, 0x12, 0x01, 0x00, 0x01, 0x12, 0x01, 0x00, + 0x04, 0x12, 0x02, 0x00, 0x07, 0x12, 0x01, 0x00, + 0x27, 0x12, 0x01, 0x00, 0x13, 0x12, 0x06, 0x00, + 0x1C, 0x12, 0x23, 0x00, 0x55, 0x12, 0x0C, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0x78, 0x12, 0x09, 0x11, + 0x01, 0x00, 0x1A, 0x12, 0x05, 0x00, 0x51, 0x12, + 0x0F, 0x00, 0x0D, 0x12, 0x01, 0x00, 0x04, 0x0D, + 0x03, 0x12, 0x0B, 0x00, 0x12, 0x0D, 0x03, 0x00, + 0x02, 0x12, 0x09, 0x00, 0x12, 0x0D, 0x02, 0x12, + 0x0C, 0x00, 0x0D, 0x12, 0x01, 0x00, 0x03, 0x12, + 0x01, 0x0D, 0x02, 0x12, 0x0C, 0x00, 0x37, 0x0D, + 0x07, 0x00, 0x08, 0x0D, 0x01, 0x00, 0x02, 0x0D, + 0x0B, 0x00, 0x07, 0x0A, 0x01, 0x00, 0x01, 0x12, + 0x03, 0x00, 0x0A, 0x12, 0x21, 0x0D, 0x03, 0x0E, + 0x01, 0x12, 0x01, 0x00, 0x0A, 0x12, 0x06, 0x00, + 0x58, 0x12, 0x08, 0x00, 0x29, 0x0D, 0x01, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0x5B, 0x00, 0x9C, 0x12, 0x04, 0x00, + 0x5A, 0x12, 0x06, 0x00, 0x16, 0x12, 0x02, 0x00, + 0x06, 0x12, 0x02, 0x00, 0x26, 0x12, 0x02, 0x00, + 0x06, 0x12, 0x02, 0x00, 0x08, 0x12, 0x01, 0x00, + 0x01, 0x12, 0x01, 0x00, 0x01, 0x12, 0x01, 0x00, + 0x01, 0x12, 0x01, 0x00, 0x1F, 0x12, 0x02, 0x00, + 0x35, 0x12, 0x01, 0x00, 0x07, 0x12, 0x01, 0x00, + 0x01, 0x12, 0x03, 0x00, 0x03, 0x12, 0x01, 0x00, + 0x07, 0x12, 0x03, 0x00, 0x04, 0x12, 0x02, 0x00, + 0x06, 0x12, 0x04, 0x00, 0x0D, 0x12, 0x05, 0x00, + 0x03, 0x12, 0x01, 0x00, 0x07, 0x12, 0x03, 0x11, + 0x0B, 0x0E, 0x03, 0x00, 0x01, 0x03, 0x01, 0x12, + 0x18, 0x11, 0x01, 0x0F, 0x01, 0x01, 0x01, 0x05, + 0x01, 0x07, 0x01, 0x02, 0x01, 0x06, 0x01, 0x11, + 0x01, 0x0A, 0x05, 0x12, 0x2A, 0x11, 0x01, 0x0E, + 0x04, 0x12, 0x06, 0x0E, 0x06, 0x08, 0x01, 0x00, + 0x01, 0x12, 0x02, 0x08, 0x06, 0x0A, 0x02, 0x12, + 0x03, 0x00, 0x01, 0x08, 0x0A, 0x0A, 0x02, 0x12, + 0x14, 0x0A, 0x12, 0x12, 0x1E, 0x0D, 0x1B, 0x12, + 0x17, 0x00, 0x01, 0x12, 0x04, 0x00, 0x01, 0x12, + 0x02, 0x00, 0x0A, 0x12, 0x01, 0x00, 0x01, 0x12, + 0x03, 0x00, 0x05, 0x12, 0x06, 0x00, 0x01, 0x12, + 0x01, 0x00, 0x01, 0x12, 0x01, 0x00, 0x01, 0x12, + 0x01, 0x00, 0x04, 0x0A, 0x01, 0x00, 0x03, 0x12, + 0x01, 0x00, 0x07, 0x12, 0x03, 0x00, 0x03, 0x12, + 0x05, 0x00, 0x05, 0x12, 0x16, 0x00, 0x24, 0x12, + 0x8E, 0x0A, 0x02, 0x12, 0xFF, 0x12, 0x23, 0x00, + 0x45, 0x12, 0x1A, 0x00, 0x01, 0x12, 0xCA, 0x08, + 0x3C, 0x00, 0x4E, 0x08, 0x01, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0x20, 0x11, 0x01, 0x12, + 0x04, 0x00, 0x03, 0x12, 0x19, 0x00, 0x09, 0x0D, + 0x06, 0x12, 0x01, 0x00, 0x05, 0x12, 0x02, 0x00, + 0x05, 0x12, 0x04, 0x00, 0x56, 0x12, 0x02, 0x0D, + 0x02, 0x12, 0x02, 0x00, 0x03, 0x12, 0x01, 0x00, + 0x5A, 0x12, 0x01, 0x00, 0x04, 0x12, 0x05, 0x00, + 0x28, 0x12, 0x04, 0x00, 0x5E, 0x12, 0x01, 0x00, + 0x28, 0x12, 0x38, 0x00, 0x2D, 0x12, 0x03, 0x00, + 0x24, 0x12, 0x1C, 0x00, 0x1C, 0x12, 0x03, 0x00, + 0x32, 0x12, 0x0F, 0x00, 0x0C, 0x12, 0x04, 0x00, + 0x2F, 0x12, 0x01, 0x00, 0x77, 0x12, 0x04, 0x00, + 0x63, 0x12, 0x02, 0x00, 0x1F, 0x12, 0x01, 0x00, + 0x01, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xCD, 0x00, 0x01, 0x12, + 0x4A, 0x00, 0x01, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xF5, 0x00, + 0x01, 0x12, 0x5A, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0x91, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0x7A, 0x00, 0x01, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xCD, 0x00, + 0x01, 0x12, 0x5C, 0x00, 0x01, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0x81, 0x00, 0x02, 0x12, + 0x7E, 0x00, 0x02, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0x02, 0x00, 0x02, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, 0xFF, 0x12, + 0xFF, 0x12, 0x17, 0x00, 0xFF, 0x00, 0x30, 0x12, + 0x02, 0x00, 0x3B, 0x12, 0x95, 0x00, 0x07, 0x12, + 0x0C, 0x00, 0x05, 0x12, 0x05, 0x03, 0x01, 0x0D, + 0x01, 0x03, 0x0A, 0x0A, 0x01, 0x03, 0x0D, 0x12, + 0x01, 0x03, 0x05, 0x12, 0x01, 0x03, 0x01, 0x12, + 0x01, 0x03, 0x02, 0x12, 0x01, 0x03, 0x02, 0x12, + 0x01, 0x03, 0x0A, 0x04, 0x62, 0x12, 0x21, 0x04, + 0xFF, 0x04, 0x6C, 0x12, 0x12, 0x04, 0x40, 0x12, + 0x02, 0x04, 0x36, 0x12, 0x28, 0x04, 0x0D, 0x12, + 0x03, 0x0D, 0x10, 0x12, 0x10, 0x0D, 0x04, 0x12, + 0x2C, 0x0C, 0x01, 0x12, 0x01, 0x0C, 0x01, 0x12, + 0x02, 0x0C, 0x01, 0x12, 0x09, 0x0A, 0x01, 0x12, + 0x02, 0x0A, 0x02, 0x12, 0x05, 0x0A, 0x02, 0x12, + 0x05, 0x04, 0x05, 0x12, 0x01, 0x04, 0x87, 0x12, + 0x02, 0x0E, 0x01, 0x12, 0x03, 0x0A, 0x03, 0x12, + 0x05, 0x0A, 0x01, 0x0C, 0x01, 0x0A, 0x01, 0x0C, + 0x01, 0x09, 0x01, 0x08, 0x0A, 0x0C, 0x01, 0x12, + 0x06, 0x00, 0x1A, 0x12, 0x06, 0x00, 0x1A, 0x12, + 0x0B, 0x00, 0x59, 0x12, 0x03, 0x00, 0x06, 0x12, + 0x02, 0x00, 0x06, 0x12, 0x02, 0x00, 0x06, 0x12, + 0x02, 0x00, 0x03, 0x12, 0x03, 0x0A, 0x02, 0x12, + 0x03, 0x0A, 0x02, 0x12, 0x09, 0x00, 0x0E, 0x00, +}; diff --git a/putty.h b/putty.h index af3768d8..723f1e6b 100644 --- a/putty.h +++ b/putty.h @@ -428,6 +428,8 @@ struct config_tag { int window_border; char answerback[256]; char printer[128]; + int arabicshaping; + int bidi; /* Colour options */ int system_colour; int try_palette; @@ -831,6 +833,16 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, int midsession, int protocol); /* + * Exports from minibidi.c. + */ +typedef struct bidi_char { + wchar_t origwc, wc; + unsigned short index; +} bidi_char; +int do_bidi(bidi_char *line, int count); +int do_shape(bidi_char *line, bidi_char *to, int count); + +/* * X11 auth mechanisms we know about. */ enum { diff --git a/settings.c b/settings.c index 5abf15dc..b9e6621f 100644 --- a/settings.c +++ b/settings.c @@ -274,6 +274,8 @@ void save_open_settings(void *sesskey, int do_host, Config *cfg) write_setting_i(sesskey, "DECOriginMode", cfg->dec_om); write_setting_i(sesskey, "AutoWrapMode", cfg->wrap_mode); write_setting_i(sesskey, "LFImpliesCR", cfg->lfhascr); + write_setting_i(sesskey, "DisableArabicShaping", cfg->arabicshaping); + write_setting_i(sesskey, "DisableBidi", cfg->bidi); write_setting_i(sesskey, "WinNameAlways", cfg->win_name_always); write_setting_s(sesskey, "WinTitle", cfg->wintitle); write_setting_i(sesskey, "TermWidth", cfg->width); @@ -283,6 +285,7 @@ void save_open_settings(void *sesskey, int do_host, Config *cfg) write_setting_i(sesskey, "UseSystemColours", cfg->system_colour); write_setting_i(sesskey, "TryPalette", cfg->try_palette); write_setting_i(sesskey, "BoldAsColour", cfg->bold_colour); + for (i = 0; i < 22; i++) { char buf[20], buf2[30]; sprintf(buf, "Colour%d", i); @@ -531,6 +534,8 @@ void load_open_settings(void *sesskey, int do_host, Config *cfg) gppi(sesskey, "DECOriginMode", 0, &cfg->dec_om); gppi(sesskey, "AutoWrapMode", 1, &cfg->wrap_mode); gppi(sesskey, "LFImpliesCR", 0, &cfg->lfhascr); + gppi(sesskey, "DisableArabicShaping", 0, &cfg->arabicshaping); + gppi(sesskey, "DisableBidi", 0, &cfg->bidi); gppi(sesskey, "WinNameAlways", 1, &cfg->win_name_always); gpps(sesskey, "WinTitle", "", cfg->wintitle, sizeof(cfg->wintitle)); gppi(sesskey, "TermWidth", 80, &cfg->width); @@ -540,6 +545,7 @@ void load_open_settings(void *sesskey, int do_host, Config *cfg) gppi(sesskey, "UseSystemColours", 0, &cfg->system_colour); gppi(sesskey, "TryPalette", 0, &cfg->try_palette); gppi(sesskey, "BoldAsColour", 1, &cfg->bold_colour); + for (i = 0; i < 22; i++) { static const char *const defaults[] = { "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0", diff --git a/terminal.c b/terminal.c index 083b0fb4..3b149234 100644 --- a/terminal.c +++ b/terminal.c @@ -237,6 +237,15 @@ void term_update(Terminal *term) term->seen_disp_event = 0; need_sbar_update = TRUE; } + + /* Allocate temporary buffers for Arabic shaping and bidi. */ + if (!term->cfg.arabicshaping || !term->cfg.bidi) + { + term->wcFrom = sresize(term->wcFrom, term->cols, bidi_char); + term->ltemp = sresize(term->ltemp, term->cols+1, unsigned long); + term->wcTo = sresize(term->wcTo, term->cols, bidi_char); + } + if (need_sbar_update) update_sbar(term); do_paint(term, ctx, TRUE); @@ -428,6 +437,12 @@ Terminal *term_init(Config *mycfg, struct unicode_data *ucsdata, term->resize_fn = NULL; term->resize_ctx = NULL; term->in_term_out = FALSE; + term->ltemp = NULL; + term->wcFrom = NULL; + term->wcTo = NULL; + + term->bidi_cache_size = 0; + term->pre_bidi_cache = term->post_bidi_cache = NULL; return term; } @@ -436,6 +451,7 @@ void term_free(Terminal *term) { unsigned long *line; struct beeptime *beep; + int i; while ((line = delpos234(term->scrollback, 0)) != NULL) sfree(line); @@ -457,6 +473,17 @@ void term_free(Terminal *term) printer_finish_job(term->print_job); bufchain_clear(&term->printer_buf); sfree(term->paste_buffer); + sfree(term->ltemp); + sfree(term->wcFrom); + sfree(term->wcTo); + + for (i = 0; i < term->bidi_cache_size; i++) { + sfree(term->pre_bidi_cache[i]); + sfree(term->post_bidi_cache[i]); + } + sfree(term->pre_bidi_cache); + sfree(term->post_bidi_cache); + sfree(term); } @@ -3303,12 +3330,65 @@ static int linecmp(Terminal *term, unsigned long *a, unsigned long *b) #endif /* + * To prevent having to run the reasonably tricky bidi algorithm + * too many times, we maintain a cache of the last lineful of data + * fed to the algorithm on each line of the display. + */ +static int term_bidi_cache_hit(Terminal *term, int line, + unsigned long *lbefore, int width) +{ + if (!term->pre_bidi_cache) + return FALSE; /* cache doesn't even exist yet! */ + + if (line >= term->bidi_cache_size) + return FALSE; /* cache doesn't have this many lines */ + + if (!term->pre_bidi_cache[line]) + return FALSE; /* cache doesn't contain _this_ line */ + + if (!memcmp(term->pre_bidi_cache[line], lbefore, + width * sizeof(unsigned long))) + return TRUE; /* aha! the line matches the cache */ + + return FALSE; /* it didn't match. */ +} + +static void term_bidi_cache_store(Terminal *term, int line, + unsigned long *lbefore, + unsigned long *lafter, int width) +{ + if (!term->pre_bidi_cache || term->bidi_cache_size <= line) { + int j = term->bidi_cache_size; + term->bidi_cache_size = line+1; + term->pre_bidi_cache = sresize(term->pre_bidi_cache, + term->bidi_cache_size, + unsigned long *); + term->post_bidi_cache = sresize(term->post_bidi_cache, + term->bidi_cache_size, + unsigned long *); + while (j < term->bidi_cache_size) { + term->pre_bidi_cache[j] = term->post_bidi_cache[j] = NULL; + j++; + } + } + + sfree(term->pre_bidi_cache[line]); + sfree(term->post_bidi_cache[line]); + + term->pre_bidi_cache[line] = snewn(width, unsigned long); + term->post_bidi_cache[line] = snewn(width, unsigned long); + + memcpy(term->pre_bidi_cache[line], lbefore, width * sizeof(unsigned long)); + memcpy(term->post_bidi_cache[line], lafter, width * sizeof(unsigned long)); +} + +/* * Given a context, update the window. Out of paranoia, we don't * allow WM_PAINT responses to do scrolling optimisations. */ static void do_paint(Terminal *term, Context ctx, int may_optimise) { - int i, j, our_curs_y, our_curs_x; + int i, it, j, our_curs_y, our_curs_x; unsigned long rv, cursor; pos scrpos; char ch[1024]; @@ -3324,8 +3404,8 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) if (term->in_vbell) { ticks = GETTICKCOUNT(); if (ticks - term->vbell_startpoint >= VBELL_TIMEOUT) - term->in_vbell = FALSE; - } + term->in_vbell = FALSE; + } rv = (!term->rvideo ^ !term->in_vbell ? ATTR_REVERSE : 0); @@ -3411,6 +3491,67 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) term->disptext[idx + term->cols]); term->disptext[idx + term->cols] = ldata[term->cols]; + /* Do Arabic shaping and bidi. */ + if(!term->cfg.bidi || !term->cfg.arabicshaping) { + + if (!term_bidi_cache_hit(term, i, ldata, term->cols)) { + + for(it=0; itcols ; it++) + { + int uc = (ldata[it] & 0xFFFF); + + switch (uc & CSET_MASK) { + case ATTR_LINEDRW: + if (!term->cfg.rawcnp) { + uc = term->ucsdata->unitab_xterm[uc & 0xFF]; + break; + } + case ATTR_ASCII: + uc = term->ucsdata->unitab_line[uc & 0xFF]; + break; + case ATTR_SCOACS: + uc = term->ucsdata->unitab_scoacs[uc&0xFF]; + break; + } + switch (uc & CSET_MASK) { + case ATTR_ACP: + uc = term->ucsdata->unitab_font[uc & 0xFF]; + break; + case ATTR_OEMCP: + uc = term->ucsdata->unitab_oemcp[uc & 0xFF]; + break; + } + + term->wcFrom[it].origwc = term->wcFrom[it].wc = uc; + term->wcFrom[it].index = it; + } + + if(!term->cfg.bidi) + do_bidi(term->wcFrom, term->cols); + + /* this is saved iff done from inside the shaping */ + if(!term->cfg.bidi && term->cfg.arabicshaping) + for(it=0; itcols; it++) + term->wcTo[it] = term->wcFrom[it]; + + if(!term->cfg.arabicshaping) + do_shape(term->wcFrom, term->wcTo, term->cols); + + for(it=0; itcols ; it++) + { + term->ltemp[it] = ldata[term->wcTo[it].index]; + + if (term->wcTo[it].origwc != term->wcTo[it].wc) + term->ltemp[it] = ((term->ltemp[it] & 0xFFFF0000) | + term->wcTo[it].wc); + } + term_bidi_cache_store(term, i, ldata, term->ltemp, term->cols); + ldata = term->ltemp; + } else { + ldata = term->post_bidi_cache[i]; + } + } + for (j = 0; j < term->cols; j++, idx++) { unsigned long tattr, tchar; unsigned long *d = ldata + j; diff --git a/terminal.h b/terminal.h index c3ee216f..e2b06b19 100644 --- a/terminal.h +++ b/terminal.h @@ -208,6 +208,14 @@ struct terminal_tag { * through. */ int in_term_out; + + /* + * These are buffers used by the bidi and Arabic shaping code. + */ + unsigned long *ltemp; + bidi_char *wcFrom, *wcTo; + unsigned long **pre_bidi_cache, **post_bidi_cache; + int bidi_cache_size; }; #define in_utf(term) ((term)->utf || (term)->ucsdata->line_codepage==CP_UTF8) diff --git a/window.c b/window.c index fd977ed8..71f30b4d 100644 --- a/window.c +++ b/window.c @@ -1081,6 +1081,36 @@ static void init_palette(void) } /* + * This is a wrapper to ExtTextOut() to force Windows to display + * the precise glyphs we give it. Otherwise it would do its own + * bidi and Arabic shaping, and we would end up uncertain which + * characters it had put where. + */ +static void exact_textout(HDC hdc, int x, int y, CONST RECT *lprc, + unsigned short *lpString, UINT cbCount, + CONST INT *lpDx) +{ + + GCP_RESULTSW gcpr; + char *buffer = snewn(cbCount*2+2, char); + char *classbuffer = snewn(cbCount, char); + memset(&gcpr, 0, sizeof(gcpr)); + memset(buffer, 0, cbCount*2+2); + memset(classbuffer, GCPCLASS_NEUTRAL, cbCount); + + gcpr.lStructSize = sizeof(gcpr); + gcpr.lpGlyphs = (void *)buffer; + gcpr.lpClass = classbuffer; + gcpr.nGlyphs = cbCount; + + GetCharacterPlacementW(hdc, lpString, cbCount, 0, &gcpr, + FLI_MASK | GCP_CLASSIN); + + ExtTextOut(hdc, x, y, ETO_GLYPH_INDEX | ETO_CLIPPED | ETO_OPAQUE, lprc, + buffer, cbCount, lpDx); +} + +/* * Initialise all the fonts we will need initially. There may be as many as * three or as few as one. The other (poentially) twentyone fonts are done * if/when they are needed. @@ -2989,9 +3019,13 @@ void do_text(Context ctx, int x, int y, char *text, int len, for (i = 0; i < len; i++) wbuf[i] = (WCHAR) ((attr & CSET_MASK) + (text[i] & CHAR_MASK)); - ExtTextOutW(hdc, x, + /* print Glyphs as they are, without Windows' Shaping*/ + exact_textout(hdc, x, y - font_height * (lattr == LATTR_BOT) + text_adjust, + &line_box, wbuf, len, IpDx); +/* ExtTextOutW(hdc, x, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED | ETO_OPAQUE, &line_box, wbuf, len, IpDx); + */ /* And the shadow bold hack. */ if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { diff --git a/winhelp.h b/winhelp.h index 3f72fce2..bbde922b 100644 --- a/winhelp.h +++ b/winhelp.h @@ -29,6 +29,8 @@ #define WINHELP_CTX_features_qtitle "features.qtitle" #define WINHELP_CTX_features_dbackspace "features.dbackspace" #define WINHELP_CTX_features_charset "features.charset" +#define WINHELP_CTX_features_arabicshaping "features.arabicshaping" +#define WINHELP_CTX_features_bidi "features.bidi" #define WINHELP_CTX_terminal_autowrap "terminal.autowrap" #define WINHELP_CTX_terminal_decom "terminal.decom" #define WINHELP_CTX_terminal_lfhascr "terminal.lfhascr"