From 01b220b61ab1e1790b998a7e7a75a03cd0ef4188 Mon Sep 17 00:00:00 2001 From: Jason Rumney Date: Tue, 31 Oct 2000 12:42:51 +0000 Subject: [PATCH] (x_produce_glyphs): Handle composite characters. (x_draw_glyph_string_foreground) (x_draw_composite_glyph_string_foreground): Restore old font. --- src/ChangeLog | 6 + src/w32term.c | 343 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 321 insertions(+), 28 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index fd0fac81b2..a173016145 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2000-10-31 Jason Rumney + + * w32term.c (x_produce_glyphs): Handle composite characters. + (x_draw_glyph_string_foreground) + (x_draw_composite_glyph_string_foreground): Restore old font. + 2000-10-31 Miles Bader * minibuf.c (read_minibuf): Reset the undo history just before diff --git a/src/w32term.c b/src/w32term.c index 5a2b1bdeb1..aa2ce4980f 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -1165,9 +1165,6 @@ w32_native_per_char_metric (font, char2b, font_type, pcm) enum w32_char_font_type font_type; XCharStruct * pcm; { - /* NTEMACS_TODO: Use GetGlyphOutline where possible (no Unicode - version on W9x) */ - HDC hdc = GetDC (NULL); HFONT old_font; BOOL retval = FALSE; @@ -1205,6 +1202,11 @@ w32_native_per_char_metric (font, char2b, font_type, pcm) though - we can call GetTextExtentPoint32 to get rbearing and deduce width based on the font's per-string overhang. lbearing is assumed to be zero. */ + + /* TODO: Some Thai characters (and other composites if Windows + supports them) do have lbearing, and report their total width + as zero. Need some way of handling them when + GetCharABCWidthsW fails. */ SIZE sz; if (font_type == UNICODE_FONT) @@ -2191,7 +2193,283 @@ x_produce_glyphs (it) } else if (it->what == IT_COMPOSITION) { - /* NTEMACS_TODO: Composite glyphs. */ + /* Note: A composition is represented as one glyph in the + glyph matrix. There are no padding glyphs. */ + wchar_t char2b; + XFontStruct *font; + struct face *face = FACE_FROM_ID (it->f, it->face_id); + XCharStruct *pcm; + int font_not_found_p; + struct font_info *font_info; + int boff; /* baseline offset */ + struct composition *cmp = composition_table[it->cmp_id]; + + /* Maybe translate single-byte characters to multibyte. */ + it->char_to_display = it->c; + if (unibyte_display_via_language_environment + && SINGLE_BYTE_CHAR_P (it->c) + && (it->c >= 0240 + || (it->c >= 0200 + && !NILP (Vnonascii_translation_table)))) + { + it->char_to_display = unibyte_char_to_multibyte (it->c); + } + + /* Get face and font to use. Encode IT->char_to_display. */ + it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display); + face = FACE_FROM_ID (it->f, it->face_id); + x_get_char_face_and_encoding (it->f, it->char_to_display, + it->face_id, &char2b, it->multibyte_p); + font = face->font; + + /* When no suitable font found, use the default font. */ + font_not_found_p = font == NULL; + if (font_not_found_p) + { + font = FRAME_FONT (it->f); + boff = it->f->output_data.w32->baseline_offset; + font_info = NULL; + } + else + { + font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id); + boff = font_info->baseline_offset; + if (font_info->vertical_centering) + boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; + } + + /* There are no padding glyphs, so there is only one glyph to + produce for the composition. Important is that pixel_width, + ascent and descent are the values of what is drawn by + draw_glyphs (i.e. the values of the overall glyphs composed). */ + it->nglyphs = 1; + + /* If we have not yet calculated pixel size data of glyphs of + the composition for the current face font, calculate them + now. Theoretically, we have to check all fonts for the + glyphs, but that requires much time and memory space. So, + here we check only the font of the first glyph. This leads + to incorrect display very rarely, and C-l (recenter) can + correct the display anyway. */ + if (cmp->font != (void *) font) + { + /* Ascent and descent of the font of the first character of + this composition (adjusted by baseline offset). Ascent + and descent of overall glyphs should not be less than + them respectively. */ + int font_ascent = FONT_BASE (font) + boff; + int font_descent = FONT_DESCENT (font) - boff; + /* Bounding box of the overall glyphs. */ + int leftmost, rightmost, lowest, highest; + int i, width, ascent, descent; + enum w32_font_type font_type; + + cmp->font = (void *) font; + + if (font->bdf && CHARSET_DIMENSION (CHAR_CHARSET (it->c)) == 1) + font_type = BDF_1D_FONT; + else if (font->bdf) + font_type = BDF_2D_FONT; + else + font_type = UNICODE_FONT; + + /* Initialize the bounding box. */ + pcm = w32_per_char_metric (font, &char2b, font_type); + if (pcm) + { + width = pcm->width; + ascent = pcm->ascent; + descent = pcm->descent; + } + else + { + width = FONT_WIDTH (font); + ascent = FONT_BASE (font); + descent = FONT_DESCENT (font); + } + + rightmost = width; + lowest = - descent + boff; + highest = ascent + boff; + leftmost = 0; + + if (font_info + && font_info->default_ascent + && CHAR_TABLE_P (Vuse_default_ascent) + && !NILP (Faref (Vuse_default_ascent, + make_number (it->char_to_display)))) + highest = font_info->default_ascent + boff; + + /* Draw the first glyph at the normal position. It may be + shifted to right later if some other glyphs are drawn at + the left. */ + cmp->offsets[0] = 0; + cmp->offsets[1] = boff; + + /* Set cmp->offsets for the remaining glyphs. */ + for (i = 1; i < cmp->glyph_len; i++) + { + int left, right, btm, top; + int ch = COMPOSITION_GLYPH (cmp, i); + int face_id = FACE_FOR_CHAR (it->f, face, ch); + + face = FACE_FROM_ID (it->f, face_id); + x_get_char_face_and_encoding (it->f, ch, face->id, &char2b, + it->multibyte_p); + font = face->font; + if (font == NULL) + { + font = FRAME_FONT (it->f); + boff = it->f->output_data.w32->baseline_offset; + font_info = NULL; + } + else + { + font_info + = FONT_INFO_FROM_ID (it->f, face->font_info_id); + boff = font_info->baseline_offset; + if (font_info->vertical_centering) + boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; + } + + if (font->bdf && CHARSET_DIMENSION (CHAR_CHARSET (ch)) == 1) + font_type = BDF_1D_FONT; + else if (font->bdf) + font_type = BDF_2D_FONT; + else + font_type = UNICODE_FONT; + + pcm = w32_per_char_metric (font, &char2b, font_type); + if (pcm) + { + width = pcm->width; + ascent = pcm->ascent; + descent = pcm->descent; + } + else + { + width = FONT_WIDTH (font); + ascent = FONT_BASE (font); + descent = FONT_DESCENT (font); + } + + if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS) + { + /* Relative composition with or without + alternate chars. */ + left = (leftmost + rightmost - width) / 2; + btm = - descent + boff; + if (font_info && font_info->relative_compose + && (! CHAR_TABLE_P (Vignore_relative_composition) + || NILP (Faref (Vignore_relative_composition, + make_number (ch))))) + { + + if (- descent >= font_info->relative_compose) + /* One extra pixel between two glyphs. */ + btm = highest + 1; + else if (ascent <= 0) + /* One extra pixel between two glyphs. */ + btm = lowest - 1 - ascent - descent; + } + } + else + { + /* A composition rule is specified by an integer + value that encodes global and new reference + points (GREF and NREF). GREF and NREF are + specified by numbers as below: + + 0---1---2 -- ascent + | | + | | + | | + 9--10--11 -- center + | | + ---3---4---5--- baseline + | | + 6---7---8 -- descent + */ + int rule = COMPOSITION_RULE (cmp, i); + int gref, nref, grefx, grefy, nrefx, nrefy; + + COMPOSITION_DECODE_RULE (rule, gref, nref); + grefx = gref % 3, nrefx = nref % 3; + grefy = gref / 3, nrefy = nref / 3; + + left = (leftmost + + grefx * (rightmost - leftmost) / 2 + - nrefx * width / 2); + btm = ((grefy == 0 ? highest + : grefy == 1 ? 0 + : grefy == 2 ? lowest + : (highest + lowest) / 2) + - (nrefy == 0 ? ascent + descent + : nrefy == 1 ? descent - boff + : nrefy == 2 ? 0 + : (ascent + descent) / 2)); + } + + cmp->offsets[i * 2] = left; + cmp->offsets[i * 2 + 1] = btm + descent; + + /* Update the bounding box of the overall glyphs. */ + right = left + width; + top = btm + descent + ascent; + if (left < leftmost) + leftmost = left; + if (right > rightmost) + rightmost = right; + if (top > highest) + highest = top; + if (btm < lowest) + lowest = btm; + } + + /* If there are glyphs whose x-offsets are negative, + shift all glyphs to the right and make all x-offsets + non-negative. */ + if (leftmost < 0) + { + for (i = 0; i < cmp->glyph_len; i++) + cmp->offsets[i * 2] -= leftmost; + rightmost -= leftmost; + } + + cmp->pixel_width = rightmost; + cmp->ascent = highest; + cmp->descent = - lowest; + if (cmp->ascent < font_ascent) + cmp->ascent = font_ascent; + if (cmp->descent < font_descent) + cmp->descent = font_descent; + } + + it->pixel_width = cmp->pixel_width; + it->ascent = it->phys_ascent = cmp->ascent; + it->descent = it->phys_descent = cmp->descent; + + if (face->box != FACE_NO_BOX) + { + int thick = face->box_line_width; + it->ascent += thick; + it->descent += thick; + + if (it->start_of_box_run_p) + it->pixel_width += thick; + if (it->end_of_box_run_p) + it->pixel_width += thick; + } + + /* If face has an overline, add the height of the overline + (1 pixel) and a 1 pixel margin to the character height. */ + if (face->overline_p) + it->ascent += 2; + + take_vertical_position_into_account (it); + + if (it->glyph_row) + x_append_composite_glyph (it); } else if (it->what == IT_IMAGE) x_produce_image_glyph (it); @@ -2775,7 +3053,7 @@ static INLINE void x_compute_glyph_string_overhangs (s) struct glyph_string *s; { - /* NTEMACS_TODO: Windows does not appear to have a method for + /* TODO: Windows does not appear to have a method for getting this info without getting the ABC widths for each individual character and working it out manually. */ } @@ -3018,7 +3296,7 @@ x_draw_glyph_string_background (s, force_p) shouldn't be drawn in the first place. */ if (!s->background_filled_p) { -#if 0 /* NTEMACS_TODO: stipple */ +#if 0 /* TODO: stipple */ if (s->stippled_p) { /* Fill background with a stipple pattern. */ @@ -3054,6 +3332,7 @@ x_draw_glyph_string_foreground (s) struct glyph_string *s; { int i, x; + HFONT old_font; /* If first glyph of S has a left box line, start drawing the text of S to the right of that box line. */ @@ -3073,7 +3352,7 @@ x_draw_glyph_string_foreground (s) SetTextAlign (s->hdc, TA_BASELINE | TA_LEFT); if (s->font && s->font->hfont) - SelectObject (s->hdc, s->font->hfont); + old_font = SelectObject (s->hdc, s->font->hfont); /* Draw characters of S as rectangles if S's font could not be loaded. */ @@ -3104,6 +3383,8 @@ x_draw_glyph_string_foreground (s) /* Draw text with TextOut and friends. */ W32_TEXTOUT (s, x, s->ybase - boff, s->char2b, s->nchars); } + if (s->font && s->font->hfont) + SelectObject (s->hdc, old_font); } /* Draw the foreground of composite glyph string S. */ @@ -3113,6 +3394,7 @@ x_draw_composite_glyph_string_foreground (s) struct glyph_string *s; { int i, x; + HFONT old_font; /* If first glyph of S has a left box line, start drawing the text of S to the right of that box line. */ @@ -3132,6 +3414,9 @@ x_draw_composite_glyph_string_foreground (s) SetBkMode (s->hdc, TRANSPARENT); SetTextAlign (s->hdc, TA_BASELINE | TA_LEFT); + if (s->font && s->font->hfont) + old_font = SelectObject (s->hdc, s->font->hfont); + /* Draw a rectangle for the composition if the font for the very first character of the composition could not be loaded. */ if (s->font_not_found_p) @@ -3143,10 +3428,12 @@ x_draw_composite_glyph_string_foreground (s) else { for (i = 0; i < s->nchars; i++, ++s->gidx) - W32_TEXTOUT (s, x + s->cmp->offsets[s->gidx * 2], - s->ybase - s->cmp->offsets[s->gidx * 2 + 1], - s->char2b + i, 1); + W32_TEXTOUT (s, x + s->cmp->offsets[s->gidx * 2], + s->ybase - s->cmp->offsets[s->gidx * 2 + 1], + s->char2b + i, 1); } + if (s->font && s->font->hfont) + SelectObject (s->hdc, old_font); } /* Allocate a color which is lighter or darker than *COLOR by FACTOR @@ -3175,8 +3462,8 @@ w32_alloc_lighter_color (f, color, factor, delta) max (0, min (0xff, delta + GetGValue (*color))), max (0, min (0xff, delta + GetBValue (*color)))); - /* NTEMACS_TODO: Map to palette and retry with delta if same? */ - /* NTEMACS_TODO: Free colors (if using palette)? */ + /* TODO: Map to palette and retry with delta if same? */ + /* TODO: Free colors (if using palette)? */ if (new == *color) return 0; @@ -3209,7 +3496,7 @@ w32_setup_relief_color (f, relief, factor, delta, default_pixel) COLORREF background = di->relief_background; struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f); - /* NTEMACS_TODO: Free colors (if using palette)? */ + /* TODO: Free colors (if using palette)? */ /* Allocate new color. */ xgcv.foreground = default_pixel; @@ -3222,7 +3509,7 @@ w32_setup_relief_color (f, relief, factor, delta, default_pixel) if (relief->gc == 0) { -#if 0 /* NTEMACS_TODO: stipple */ +#if 0 /* TODO: stipple */ xgcv.stipple = dpyinfo->gray; mask |= GCStipple; #endif @@ -3462,7 +3749,7 @@ x_draw_image_foreground (s) if (s->img->pixmap) { -#if 0 /* NTEMACS_TODO: image mask */ +#if 0 /* TODO: image mask */ if (s->img->mask) { /* We can't set both a clip mask and use XSetClipRectangles @@ -3614,7 +3901,7 @@ w32_draw_image_foreground_1 (s, pixmap) if (s->img->pixmap) { -#if 0 /* NTEMACS_TODO: image mask */ +#if 0 /* TODO: image mask */ if (s->img->mask) { /* We can't set both a clip mask and use XSetClipRectangles @@ -3686,7 +3973,7 @@ x_draw_glyph_string_bg_rect (s, x, y, w, h) struct glyph_string *s; int x, y, w, h; { -#if 0 /* NTEMACS_TODO: stipple */ +#if 0 /* TODO: stipple */ if (s->stippled_p) { /* Fill background with a stipple pattern. */ @@ -3732,7 +4019,7 @@ x_draw_image_glyph_string (s) s->stippled_p = s->face->stipple != 0; if (height > s->img->height || margin -#if 0 /* NTEMACS_TODO: image mask */ +#if 0 /* TODO: image mask */ || s->img->mask #endif || s->img->pixmap == 0 @@ -3744,7 +4031,7 @@ x_draw_image_glyph_string (s) x = s->x; y = s->y + box_line_width; -#if 0 /* NTEMACS_TODO: image mask */ +#if 0 /* TODO: image mask */ if (s->img->mask) { /* Create a pixmap as large as the glyph string Fill it with @@ -3858,7 +4145,7 @@ x_draw_stretch_glyph_string (s) w32_get_glyph_string_clip_rect (s, &r); w32_set_clip_rectangle (hdc, &r); -#if 0 /* NTEMACS_TODO: stipple */ +#if 0 /* TODO: stipple */ if (s->face->stipple) { /* Fill background with a stipple pattern. */ @@ -5946,7 +6233,7 @@ note_mode_line_highlight (w, x, mode_line_p) } } -#if 0 /* NTEMACS_TODO: mouse cursor */ +#if 0 /* TODO: mouse cursor */ XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor); #endif } @@ -6017,7 +6304,7 @@ note_mouse_highlight (f, x, y) note_mode_line_highlight (w, x, portion == 1); return; } -#if 0 /* NTEMACS_TODO: mouse cursor */ +#if 0 /* TODO: mouse cursor */ else XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), f->output_data.x->text_cursor); @@ -6650,7 +6937,7 @@ show_mouse_face (dpyinfo, draw) output_cursor = saved_cursor; set_x_cursor: -#if 0 /* NTEMACS_TODO: mouse cursor */ +#if 0 /* TODO: mouse cursor */ /* Change the mouse cursor. */ if (draw == DRAW_NORMAL_TEXT) XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), @@ -7653,7 +7940,7 @@ w32_read_socket (sd, bufp, numchars, expected) if (numchars <= 0) abort (); /* Don't think this happens. */ - /* NTEMACS_TODO: tooltips, tool-bars, ghostscript integration, mouse + /* TODO: tooltips, tool-bars, ghostscript integration, mouse cursors. */ while (get_next_msg (&msg, FALSE)) { @@ -8108,7 +8395,7 @@ w32_read_socket (sd, bufp, numchars, expected) break; case WM_KILLFOCUS: - /* NTEMACS_TODO: some of this belongs in MOUSE_LEAVE */ + /* TODO: some of this belongs in MOUSE_LEAVE */ f = x_top_window_to_frame (dpyinfo, msg.msg.hwnd); if (f) @@ -8998,7 +9285,7 @@ x_font_min_bounds (font, w, h) int *w, *h; { /* - * NTEMACS_TODO: Windows does not appear to offer min bound, only + * TODO: Windows does not appear to offer min bound, only * average and maximum width, and maximum height. */ *h = FONT_HEIGHT (font); @@ -9435,7 +9722,7 @@ x_make_frame_visible (f) input_signal_count < count && !FRAME_VISIBLE_P (f);) { /* Force processing of queued events. */ - /* NTEMACS_TODO: x_sync equivalent? */ + /* TODO: x_sync equivalent? */ /* Machines that do polling rather than SIGIO have been observed to go into a busy-wait here. So we'll fake an alarm signal @@ -9634,7 +9921,7 @@ w32_initialize_display_info (display_name) dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID; dpyinfo->mouse_face_window = Qnil; - /* NTEMACS_TODO: dpyinfo->gray */ + /* TODO: dpyinfo->gray */ } -- 2.20.1