1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

First-stage support for Unicode combining characters. The `chars'

array of each `termline' structure now contains optional additional
entries after the normal number of columns, which are used to chain
a linked list of combining characters off any primary termchar that
needs it. This means we support arbitrarily many combining
characters per cell (unlike xterm's hard limit of 2).

Cut and paste works correctly (selecting a character cell containing
multiple code points causes all those code points to be cut and
pasted). Display works by simply overlaying all the relevant
characters on top of one another; this is good enough for Unix
(xterm does the same thing), and mostly seems OK for Windows except
that the Windows Unicode fonts have a nasty habit of not containing
most of the combining characters and thus overlaying an
unknown-code-point box on your perfectly good base glyph.

I had no idea how to add support in the Mac do_text(), so I've
simply stuck in an assertion that will trigger the first time a
combining character is displayed, and hopefully this will bite
someone with the clue to fix it.

[originally from svn r4622]
This commit is contained in:
Simon Tatham 2004-10-14 16:42:43 +00:00
parent dd279dffc2
commit 089775eb02
6 changed files with 683 additions and 227 deletions

View File

@ -1,4 +1,4 @@
/* $Id: macterm.c,v 1.77 2004/10/13 11:50:16 simon Exp $ */
/* $Id: macterm.c,v 1.78 2004/10/14 16:42:43 simon Exp $ */
/*
* Copyright (c) 1999 Simon Tatham
* Copyright (c) 1999, 2002 Ben Harris
@ -1158,6 +1158,11 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len,
assert(len <= 1024);
/* SGT, 2004-10-14: I don't know how to support combining characters
* on the Mac. Hopefully the first person to fail this assertion will
* know how to do it better than me... */
assert(!(attr & TATTR_COMBINING));
SetPort((GrafPtr)GetWindowPort(s->window));
fontwidth = s->font_width;

View File

@ -43,6 +43,7 @@ typedef struct terminal_tag Terminal;
#define TATTR_ACTCURS 0x40000000UL /* active cursor (block) */
#define TATTR_PASCURS 0x20000000UL /* passive cursor (box) */
#define TATTR_RIGHTCURS 0x10000000UL /* cursor-on-RHS */
#define TATTR_COMBINING 0x80000000UL /* combining characters */
#define LATTR_NORM 0x00000000UL
#define LATTR_WIDE 0x00000001UL

File diff suppressed because it is too large Load Diff

View File

@ -33,14 +33,35 @@ typedef struct termchar termchar;
typedef struct termline termline;
struct termchar {
/*
* Any code in terminal.c which definitely needs to be changed
* when extra fields are added here is labelled with a comment
* saying FULL-TERMCHAR.
*/
unsigned long chr;
unsigned long attr;
/*
* The cc_next field is used to link multiple termchars
* together into a list, so as to fit more than one character
* into a character cell (Unicode combining characters).
*
* cc_next is a relative offset into the current array of
* termchars. I.e. to advance to the next character in a list,
* one does `tc += tc->next'.
*
* Zero means end of list.
*/
int cc_next;
};
struct termline {
unsigned short lattr;
int cols;
int cols; /* number of real columns on the line */
int size; /* number of allocated termchars
* (cc-lists may make this > cols) */
int temporary; /* TRUE if decompressed from scrollback */
int cc_free; /* offset to first cc in free list */
struct termchar *chars;
};
@ -55,8 +76,6 @@ struct terminal_tag {
int tempsblines; /* number of lines in temporary
scrollback */
termchar *cpos; /* cursor position (convenience) */
termline **disptext; /* buffer of text on real screen */
int dispcursx, dispcursy; /* location of cursor on real screen */
int curstype; /* type of cursor on real screen */
@ -70,9 +89,6 @@ struct terminal_tag {
#define TTYPE termchar
#define TSIZE (sizeof(TTYPE))
#define fix_cpos do { \
term->cpos = lineptr(term->curs.y)->chars + term->curs.x; \
} while(0)
#ifdef OPTIMISE_SCROLL
struct scrollregion *scrollhead, *scrolltail;
@ -228,7 +244,9 @@ struct terminal_tag {
* These are buffers used by the bidi and Arabic shaping code.
*/
termchar *ltemp;
int ltemp_size;
bidi_char *wcFrom, *wcTo;
int wcFromTo_size;
termchar **pre_bidi_cache, **post_bidi_cache;
int bidi_cache_size;
};

View File

@ -1804,9 +1804,15 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
struct draw_ctx *dctx = (struct draw_ctx *)ctx;
struct gui_data *inst = dctx->inst;
GdkGC *gc = dctx->gc;
int ncombining, combining;
int nfg, nbg, t, fontid, shadow, rlen, widefactor;
if (attr & TATTR_COMBINING) {
ncombining = len;
len = 1;
} else
ncombining = 1;
nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
nfg = 2 * (nfg & 0xF) + (nfg & 0x10 ? 1 : 0);
nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
@ -1874,8 +1880,8 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
wchar_t *wcs;
int i;
wcs = snewn(len+1, wchar_t);
for (i = 0; i < len; i++) {
wcs = snewn(len*ncombining+1, wchar_t);
for (i = 0; i < len*ncombining; i++) {
wcs[i] = text[i];
}
@ -1907,31 +1913,35 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
* FIXME: when we have a wide-char equivalent of
* from_unicode, use it instead of this.
*/
for (i = 0; i <= len; i++)
gwcs[i] = wcs[i];
gdk_draw_text_wc(inst->pixmap, inst->fonts[fontid], gc,
x*inst->font_width+inst->cfg.window_border,
y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent,
gwcs, len*2);
if (shadow)
for (combining = 0; combining < ncombining; combining++) {
for (i = 0; i <= len; i++)
gwcs[i] = wcs[i + combining];
gdk_draw_text_wc(inst->pixmap, inst->fonts[fontid], gc,
x*inst->font_width+inst->cfg.window_border+inst->cfg.shadowboldoffset,
x*inst->font_width+inst->cfg.window_border,
y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent,
gwcs, len*2);
if (shadow)
gdk_draw_text_wc(inst->pixmap, inst->fonts[fontid], gc,
x*inst->font_width+inst->cfg.window_border+inst->cfg.shadowboldoffset,
y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent,
gwcs, len*2);
}
sfree(gwcs);
} else {
gcs = snewn(len+1, gchar);
wc_to_mb(inst->fontinfo[fontid].charset, 0,
wcs, len, gcs, len, ".", NULL, NULL);
gdk_draw_text(inst->pixmap, inst->fonts[fontid], gc,
x*inst->font_width+inst->cfg.window_border,
y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent,
gcs, len);
if (shadow)
for (combining = 0; combining < ncombining; combining++) {
wc_to_mb(inst->fontinfo[fontid].charset, 0,
wcs + combining, len, gcs, len, ".", NULL, NULL);
gdk_draw_text(inst->pixmap, inst->fonts[fontid], gc,
x*inst->font_width+inst->cfg.window_border+inst->cfg.shadowboldoffset,
x*inst->font_width+inst->cfg.window_border,
y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent,
gcs, len);
if (shadow)
gdk_draw_text(inst->pixmap, inst->fonts[fontid], gc,
x*inst->font_width+inst->cfg.window_border+inst->cfg.shadowboldoffset,
y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent,
gcs, len);
}
sfree(gcs);
}
sfree(wcs);

View File

@ -1136,7 +1136,7 @@ static void init_palette(void)
*/
static void exact_textout(HDC hdc, int x, int y, CONST RECT *lprc,
unsigned short *lpString, UINT cbCount,
CONST INT *lpDx)
CONST INT *lpDx, int opaque)
{
GCP_RESULTSW gcpr;
@ -1152,10 +1152,11 @@ static void exact_textout(HDC hdc, int x, int y, CONST RECT *lprc,
gcpr.nGlyphs = cbCount;
GetCharacterPlacementW(hdc, lpString, cbCount, 0, &gcpr,
FLI_MASK | GCP_CLASSIN);
FLI_MASK | GCP_CLASSIN | GCP_DIACRITIC);
ExtTextOut(hdc, x, y, ETO_GLYPH_INDEX | ETO_CLIPPED | ETO_OPAQUE, lprc,
buffer, cbCount, lpDx);
ExtTextOut(hdc, x, y,
ETO_GLYPH_INDEX | ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0),
lprc, buffer, cbCount, lpDx);
}
/*
@ -2900,8 +2901,8 @@ static void sys_cursor_update(void)
*
* We are allowed to fiddle with the contents of `text'.
*/
void do_text(Context ctx, int x, int y, wchar_t *text, int len,
unsigned long attr, int lattr)
void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
unsigned long attr, int lattr)
{
COLORREF fg, bg, t;
int nfg, nbg, nfont;
@ -3031,7 +3032,10 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len,
SelectObject(hdc, fonts[nfont]);
SetTextColor(hdc, fg);
SetBkColor(hdc, bg);
SetBkMode(hdc, OPAQUE);
if (attr & TATTR_COMBINING)
SetBkMode(hdc, TRANSPARENT);
else
SetBkMode(hdc, OPAQUE);
line_box.left = x;
line_box.top = y;
line_box.right = x + char_width * len;
@ -3124,17 +3128,19 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len,
static WCHAR *wbuf = NULL;
static int wlen = 0;
int i;
if (wlen < len) {
sfree(wbuf);
wlen = len;
wbuf = snewn(wlen, WCHAR);
}
for (i = 0; i < len; i++)
wbuf[i] = text[i];
/* 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);
&line_box, wbuf, len, IpDx, !(attr & TATTR_COMBINING));
/* ExtTextOutW(hdc, x,
y - font_height * (lattr == LATTR_BOT) + text_adjust,
ETO_CLIPPED | ETO_OPAQUE, &line_box, wbuf, len, IpDx);
@ -3165,6 +3171,24 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len,
}
}
/*
* Wrapper that handles combining characters.
*/
void do_text(Context ctx, int x, int y, wchar_t *text, int len,
unsigned long attr, int lattr)
{
if (attr & TATTR_COMBINING) {
unsigned long a = 0;
attr &= ~TATTR_COMBINING;
while (len--) {
do_text_internal(ctx, x, y, text, 1, attr | a, lattr);
text++;
a = TATTR_COMBINING;
}
} else
do_text_internal(ctx, x, y, text, len, attr, lattr);
}
void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,
unsigned long attr, int lattr)
{