(x_produce_glyphs): Handle composite characters.
authorJason Rumney <jasonr@gnu.org>
Tue, 31 Oct 2000 12:42:51 +0000 (12:42 +0000)
committerJason Rumney <jasonr@gnu.org>
Tue, 31 Oct 2000 12:42:51 +0000 (12:42 +0000)
(x_draw_glyph_string_foreground)
(x_draw_composite_glyph_string_foreground): Restore old font.

src/ChangeLog
src/w32term.c

index fd0fac8..a173016 100644 (file)
@@ -1,3 +1,9 @@
+2000-10-31  Jason Rumney  <jasonr@gnu.org>
+
+       * 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  <miles@lsi.nec.co.jp>
 
        * minibuf.c (read_minibuf): Reset the undo history just before
index 5a2b1bd..aa2ce49 100644 (file)
@@ -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 */
 
 }