+/*
+ * 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;
+ int bkmode = 0, got_bkmode = FALSE;
+
+ xp = xn = x;
+
+ for (i = 0; i < (int)cbCount ;) {
+ int rtl = is_rtl(lpString[i]);
+
+ xn += lpDx[i];
+
+ for (j = i+1; j < (int)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) {
+ exact_textout(hdc, xp, y, lprc, lpString+i, j-i,
+ font_varpitch ? NULL : lpDx+i, opaque);
+ } else {
+ ExtTextOutW(hdc, xp, y, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0),
+ lprc, lpString+i, j-i,
+ font_varpitch ? NULL : lpDx+i);
+ }
+
+ i = j;
+ xp = xn;
+
+ bkmode = GetBkMode(hdc);
+ got_bkmode = TRUE;
+ SetBkMode(hdc, TRANSPARENT);
+ opaque = FALSE;
+ }
+
+ if (got_bkmode)
+ SetBkMode(hdc, bkmode);
+}
+
+static int get_font_width(HDC hdc, const TEXTMETRIC *tm)
+{
+ int ret;
+ /* Note that the TMPF_FIXED_PITCH bit is defined upside down :-( */
+ if (!(tm->tmPitchAndFamily & TMPF_FIXED_PITCH)) {
+ ret = tm->tmAveCharWidth;
+ } else {
+#define FIRST '0'
+#define LAST '9'
+ ABCFLOAT widths[LAST-FIRST + 1];
+ int j;
+
+ font_varpitch = TRUE;
+ font_dualwidth = TRUE;
+ if (GetCharABCWidthsFloat(hdc, FIRST, LAST, widths)) {
+ ret = 0;
+ for (j = 0; j < lenof(widths); j++) {
+ int width = (int)(0.5 + widths[j].abcfA +
+ widths[j].abcfB + widths[j].abcfC);
+ if (ret < width)
+ ret = width;
+ }
+ } else {
+ ret = tm->tmMaxCharWidth;
+ }
+#undef FIRST
+#undef LAST
+ }
+ return ret;
+}
+