mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 09:27:59 +00:00
Reinstate as much of the Windows font-linking behaviour as I can
easily manage, by adopting a hybrid approach to Unicode text display. The old approach of simply calling ExtTextOutW provided font linking without us having to lift a finger, but didn't do the right thing when it came to bidirectional or Arabic-shaped text. Arabeyes' replacement exact_textout() supported the latter, but turned out to break the former (with no warning from the Windows API documentation, so it's not their fault). So now I've got a second wrapper layer called general_textout(), which splits the input string into substrings based on bidi character class. Any character liable to cause bidi or shaping behaviour if fed straight to ExtTextOutW is instead fed through Arabeyes' exact_textout(), but the rest is fed straight to ExtTextOutW as it used to be. The effect appears to be that font linking is restored for all characters _except_ Arabic and other bidi scripts, which means in particular that we are no longer in a state of regression over 0.57. (0.57 would have done font linking on Arabic as well, but would also have misbidied it, so we've merely exchanged one failure mode for another slightly less harmful one in that situation.) [originally from svn r6910]
This commit is contained in:
parent
53843b7392
commit
230d400ddc
34
minibidi.c
34
minibidi.c
@ -877,6 +877,40 @@ unsigned char getType(int ch)
|
||||
return ON;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function exported to front ends to allow them to identify
|
||||
* bidi-active characters (in case, for example, the platform's
|
||||
* text display function can't conveniently be prevented from doing
|
||||
* its own bidi and so special treatment is required for characters
|
||||
* that would cause the bidi algorithm to activate).
|
||||
*
|
||||
* This function is passed a single Unicode code point, and returns
|
||||
* nonzero if the presence of this code point can possibly cause
|
||||
* the bidi algorithm to do any reordering. Thus, any string
|
||||
* composed entirely of characters for which is_rtl() returns zero
|
||||
* should be safe to pass to a bidi-active platform display
|
||||
* function without fear.
|
||||
*
|
||||
* (is_rtl() must therefore also return true for any character
|
||||
* which would be affected by Arabic shaping, but this isn't
|
||||
* important because all such characters are right-to-left so it
|
||||
* would have flagged them anyway.)
|
||||
*/
|
||||
int is_rtl(int c)
|
||||
{
|
||||
/*
|
||||
* After careful reading of the Unicode bidi algorithm (URL as
|
||||
* given at the top of this file) I believe that the only
|
||||
* character classes which can possibly cause trouble are R,
|
||||
* AL, RLE and RLO. I think that any string containing no
|
||||
* character in any of those classes will be displayed
|
||||
* uniformly left-to-right by the Unicode bidi algorithm.
|
||||
*/
|
||||
const int mask = (1<<R) | (1<<AL) | (1<<RLE) | (1<<RLO);
|
||||
|
||||
return mask & (1 << (getType(c)));
|
||||
}
|
||||
|
||||
/*
|
||||
* The most significant 2 bits of each level are used to store
|
||||
* Override status of each character
|
||||
|
1
putty.h
1
putty.h
@ -1087,6 +1087,7 @@ typedef struct bidi_char {
|
||||
} bidi_char;
|
||||
int do_bidi(bidi_char *line, int count);
|
||||
int do_shape(bidi_char *line, bidi_char *to, int count);
|
||||
int is_rtl(int c);
|
||||
|
||||
/*
|
||||
* X11 auth mechanisms we know about.
|
||||
|
@ -1260,6 +1260,89 @@ static void exact_textout(HDC hdc, int x, int y, CONST RECT *lprc,
|
||||
lprc, buffer, cbCount, lpDx);
|
||||
}
|
||||
|
||||
/*
|
||||
* The exact_textout() wrapper, unfortunately, destroys the useful
|
||||
* Windows `font linking' behaviour: automatic handling of Unicode
|
||||
* code points not supported in this font by falling back to a font
|
||||
* which does contain them. Therefore, we adopt a multi-layered
|
||||
* approach: for any potentially-bidi text, we use exact_textout(),
|
||||
* and for everything else we use a simple ExtTextOut as we did
|
||||
* before exact_textout() was introduced.
|
||||
*/
|
||||
static void general_textout(HDC hdc, int x, int y, CONST RECT *lprc,
|
||||
unsigned short *lpString, UINT cbCount,
|
||||
CONST INT *lpDx, int opaque)
|
||||
{
|
||||
int i, j, xp, xn;
|
||||
RECT newrc;
|
||||
|
||||
#ifdef FIXME_REMOVE_BEFORE_CHECKIN
|
||||
int k;
|
||||
debug(("general_textout: %d,%d", x, y));
|
||||
for(k=0;k<cbCount;k++)debug((" U+%04X", lpString[k]));
|
||||
debug(("\n rect: [%d,%d %d,%d]", lprc->left, lprc->top, lprc->right, lprc->bottom));
|
||||
debug(("\n"));
|
||||
#endif
|
||||
|
||||
xp = xn = x;
|
||||
|
||||
for (i = 0; i < cbCount ;) {
|
||||
int rtl = is_rtl(lpString[i]);
|
||||
|
||||
xn += lpDx[i];
|
||||
|
||||
for (j = i+1; j < cbCount; j++) {
|
||||
if (rtl != is_rtl(lpString[j]))
|
||||
break;
|
||||
xn += lpDx[j];
|
||||
}
|
||||
|
||||
/*
|
||||
* Now [i,j) indicates a maximal substring of lpString
|
||||
* which should be displayed using the same textout
|
||||
* function.
|
||||
*/
|
||||
if (rtl) {
|
||||
newrc.left = lprc->left + xp - x;
|
||||
newrc.right = lprc->left + xn - x;
|
||||
newrc.top = lprc->top;
|
||||
newrc.bottom = lprc->bottom;
|
||||
#ifdef FIXME_REMOVE_BEFORE_CHECKIN
|
||||
{
|
||||
int k;
|
||||
debug((" exact_textout: %d,%d", xp, y));
|
||||
for(k=0;k<j-i;k++)debug((" U+%04X", lpString[i+k]));
|
||||
debug(("\n rect: [%d,%d %d,%d]\n", newrc.left, newrc.top, newrc.right, newrc.bottom));
|
||||
}
|
||||
#endif
|
||||
exact_textout(hdc, xp, y, &newrc, lpString+i, j-i, lpDx+i, opaque);
|
||||
} else {
|
||||
#ifdef FIXME_REMOVE_BEFORE_CHECKIN
|
||||
{
|
||||
int k;
|
||||
debug((" ExtTextOut : %d,%d", xp, y));
|
||||
for(k=0;k<j-i;k++)debug((" U+%04X", lpString[i+k]));
|
||||
debug(("\n rect: [%d,%d %d,%d]\n", newrc.left, newrc.top, newrc.right, newrc.bottom));
|
||||
}
|
||||
#endif
|
||||
newrc.left = lprc->left + xp - x;
|
||||
newrc.right = lprc->left + xn - x;
|
||||
newrc.top = lprc->top;
|
||||
newrc.bottom = lprc->bottom;
|
||||
ExtTextOutW(hdc, xp, y, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0),
|
||||
&newrc, lpString+i, j-i, lpDx+i);
|
||||
}
|
||||
|
||||
i = j;
|
||||
xp = xn;
|
||||
}
|
||||
|
||||
#ifdef FIXME_REMOVE_BEFORE_CHECKIN
|
||||
debug(("general_textout: done, xn=%d\n", xn));
|
||||
#endif
|
||||
assert(xn - x == lprc->right - lprc->left);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -3295,12 +3378,8 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
|
||||
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, !(attr & TATTR_COMBINING));
|
||||
/* ExtTextOutW(hdc, x,
|
||||
y - font_height * (lattr == LATTR_BOT) + text_adjust,
|
||||
ETO_CLIPPED | ETO_OPAQUE, &line_box, wbuf, len, IpDx);
|
||||
*/
|
||||
general_textout(hdc, x, y - font_height * (lattr == LATTR_BOT) + text_adjust,
|
||||
&line_box, wbuf, len, IpDx, !(attr & TATTR_COMBINING));
|
||||
|
||||
/* And the shadow bold hack. */
|
||||
if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
|
||||
|
Loading…
Reference in New Issue
Block a user