]> git.eshelyaron.com Git - emacs.git/commitdiff
(dumpglyphs): Set a clipping region when we draw glyphs
authorKenichi Handa <handa@m17n.org>
Wed, 19 Mar 1997 16:33:48 +0000 (16:33 +0000)
committerKenichi Handa <handa@m17n.org>
Wed, 19 Mar 1997 16:33:48 +0000 (16:33 +0000)
with a font of inappropriate size.
(x_list_fonts): Try alternate fonts if we can't find a font of an
appropriate size.

src/xterm.c

index 471618558626fd4c31ea121c341c550e5f934860..386aa54599a3494dd0f8b1c1c5b2b1bf7b5a17b7 100644 (file)
@@ -550,7 +550,7 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
   Window window = FRAME_X_WINDOW (f);
   int orig_left = left;
   int gidx = 0;
-  int pixel_width;
+  int i;
 
   while (n > 0)
     {
@@ -619,11 +619,6 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
 
       /* LEN gets the length of the run.  */
       len = cp - buf;
-      /* PIXEL_WIDTH get the pixcel width of the run.  */
-      pixel_width
-       = (FONT_WIDTH (f->output_data.x->font)
-          * (cmpcharp ? cmpcharp->width : len * CHARSET_WIDTH (charset)));
-
       /* Now output this run of chars, with the font and pixel values
         determined by the face code CF.  */
       {
@@ -631,10 +626,18 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
        XFontStruct *font = NULL;
        GC gc;
        int stippled = 0;
+       int line_height = f->output_data.x->line_height;
+       /* Pixel width of each glyph in this run.  */
+       int glyph_width
+         = FONT_WIDTH (f->output_data.x->font) * CHARSET_WIDTH (charset);
+       /* Overall pixel width of this run.  */
+       int run_width
+         = (FONT_WIDTH (f->output_data.x->font)
+            * (cmpcharp ? cmpcharp->width : len * CHARSET_WIDTH (charset)));
        /* A flag to tell if we have already filled background.  We
           fill background in advance in the following cases:
           1) A face has stipple.
-          2) A height of font is different from that of the current line.
+          2) A height of font is shorter than LINE_HEIGHT.
           3) Drawing a composite character.
           4) Font has non-zero _MULE_BASELINE_OFFSET property.
           After filling background, we draw glyphs by XDrawString16.  */
@@ -644,6 +647,8 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
        /* The property value of `_MULE_RELATIVE_COMPOSE' and
            `_MULE_DEFAULT_ASCENT'.  */
        int relative_compose = 0, default_ascent = 0;
+       /* 1 if we find no font or a font of inappropriate size.  */
+       int require_clipping;
 
        /* HL = 3 means use a mouse face previously chosen.  */
        if (hl == 3)
@@ -691,12 +696,10 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
            font = (XFontStruct *) (fontp->font);
            gc = FACE_NON_ASCII_GC (face);
            XSetFont (FRAME_X_DISPLAY (f), gc, font->fid);
-           if (font->max_byte1 != 0)
-             baseline = (f->output_data.x->line_height
-                         + font->ascent - font->descent) / 2;
-           else
-             baseline = (f->output_data.x->font_baseline
-                         - fontp->baseline_offset);
+           baseline
+             = (font->max_byte1 != 0
+                ? (line_height + font->ascent - font->descent) / 2
+                : f->output_data.x->font_baseline - fontp->baseline_offset);
            if (cmpcharp && cmpcharp->cmp_rule == NULL)
              {
                relative_compose = fontp->relative_compose;
@@ -755,10 +758,8 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
            /* The cursor overrides stippling.  */
            stippled = 0;
 
-           if (!cmpcharp
-               && (!font
-                   || font == (XFontStruct *) FACE_DEFAULT
-                   || font == f->output_data.x->font)
+           if ((font == (XFontStruct *) FACE_DEFAULT
+                || font == f->output_data.x->font)
                && face->background == f->output_data.x->background_pixel
                && face->foreground == f->output_data.x->foreground_pixel)
              {
@@ -813,29 +814,52 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
        if (font == (XFontStruct *) FACE_DEFAULT)
          font = f->output_data.x->font;
 
+       if (font)
+         require_clipping = (FONT_HEIGHT (font) > line_height
+                             || FONT_WIDTH (font) > glyph_width
+                             || baseline != f->output_data.x->font_baseline);
+
        if (font && (just_foreground || (cmpcharp && gidx > 0)))
          background_filled = 1;
-       else if (!font
-                || stippled
-                || f->output_data.x->line_height != FONT_HEIGHT (font)
-                || cmpcharp
-                || baseline != f->output_data.x->font_baseline)
+       else if (stippled)
          {
-           if (!stippled)
-             /* This is to fill a rectangle with background color.  */
-             XSetStipple (FRAME_X_DISPLAY (f), gc,
-                          FRAME_X_DISPLAY_INFO (f)->null_pixel);
            /* Turn stipple on.  */
            XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillOpaqueStippled);
 
            /* Draw stipple or background color on background.  */
            XFillRectangle (FRAME_X_DISPLAY (f), window, gc,
-                           left, top, pixel_width,
-                           f->output_data.x->line_height);
+                           left, top, run_width, line_height);
 
            /* Turn stipple off.  */
            XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillSolid);
 
+           background_filled = 1;
+         }
+       else if (!font
+                || FONT_HEIGHT (font) < line_height
+                || FONT_WIDTH (font) < glyph_width
+                || baseline != f->output_data.x->font_baseline
+                || cmpcharp)
+         {
+           /* Fill a area for the current run in background pixle of GC.  */
+           XGCValues xgcv;
+           unsigned long mask = GCForeground | GCBackground;
+           unsigned long fore, back;
+
+           /* The current code at first exchange foreground and
+             background of GC, fill the area, then recover the
+             original foreground and background of GC.
+             Aren't there more smart ways?  */
+
+           XGetGCValues (FRAME_X_DISPLAY (f), gc, mask, &xgcv);
+           fore = xgcv.foreground, back = xgcv.background;
+           xgcv.foreground = back, xgcv.background = fore;
+           XChangeGC (FRAME_X_DISPLAY (f), gc, mask, &xgcv);
+           XFillRectangle (FRAME_X_DISPLAY (f), window, gc,
+                           left, top, run_width, line_height);
+           xgcv.foreground = fore, xgcv.background = back;
+           XChangeGC (FRAME_X_DISPLAY (f), gc, mask, &xgcv);
+
            background_filled = 1;
            if (cmpcharp)
              /* To assure not to fill background while drawing
@@ -847,10 +871,48 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
 
        if (font)
          {
-           if (cmpcharp)
+           if (require_clipping)
+             {
+               Region region;  /* Region used for setting clip mask to GC.  */
+               XPoint x[4];    /* Data used for creating REGION.  */
+
+               x[0].x = x[3].x = left, x[1].x = x[2].x = left + glyph_width;
+               x[0].y = x[1].y = top,  x[2].y = x[3].y = top + line_height;
+               region = XPolygonRegion (x, 4, EvenOddRule);
+               XSetRegion (FRAME_X_DISPLAY (f), gc, region);
+               XDestroyRegion (region);
+             }
+
+           if (!cmpcharp)
+             {
+               if (require_clipping)
+                 for (i = 0; i < len; i++)
+                   {
+                     if (i > 0) 
+                       XSetClipOrigin (FRAME_X_DISPLAY (f), gc,
+                                       glyph_width * i, 0);
+                     if (background_filled)
+                       XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
+                                      left + glyph_width * i,
+                                      top + baseline, buf + i, 1);
+                     else
+                       XDrawImageString16 (FRAME_X_DISPLAY (f), window, gc,
+                                           left + glyph_width * i,
+                                           top + baseline, buf + i, 1);
+                   }
+               else
+                 {
+                   if (background_filled)
+                     XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
+                                    left, top + baseline, buf, len);
+                   else
+                     XDrawImageString16 (FRAME_X_DISPLAY (f), window, gc,
+                                         left, top + baseline, buf, len);
+                 }
+             }
+           else
              {
                XCharStruct *pcm; /* Pointer to per char metric info.  */
-               int i;
 
                if ((cmpcharp->cmp_rule || relative_compose)
                    && gidx == 0)
@@ -939,22 +1001,8 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
                                   buf + i, 1);
                  }
              }
-           else if (background_filled)
-             XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
-                            left, top + baseline, buf, len);
-           else
-             XDrawImageString16 (FRAME_X_DISPLAY (f), window, gc,
-                                 left, top + baseline, buf, len);
-
-           /* Clear the rest of the line's height.  */
-           if (f->output_data.x->line_height > FONT_HEIGHT (font))
-             XClearArea (FRAME_X_DISPLAY (f), window, left,
-                         top + FONT_HEIGHT (font),
-                         FONT_WIDTH (font) * len,
-                         /* This is how many pixels of height
-                            we have to clear.  */
-                         f->output_data.x->line_height - FONT_HEIGHT (font),
-                         False);
+           if (require_clipping)
+             XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
 
 #if 0 /* Doesn't work, because it uses FRAME_CURRENT_GLYPHS,
         which often is not up to date yet.  */
@@ -969,29 +1017,20 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
              }
 #endif
          }
-       else
+       if (!font || require_clipping)
          {
-           /* There's no appropriate font for this glyph.  Just show
-               rectangles.  */
+           /* Show rectangles to show that we found no font or a font
+               of inappropriate size.  */
 
            if (cmpcharp)
              XDrawRectangle
                (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
-                left, top + 1,
-                pixel_width - 2, f->output_data.x->line_height - 3);
+                left, top, run_width - 1, line_height - 1);
            else
-             {
-               int left_offset;
-               int left_skip_step = (FONT_WIDTH (f->output_data.x->font)
-                                     * CHARSET_WIDTH (charset));
-
-               for (left_offset = 0; left_offset < pixel_width;
-                    left_offset += left_skip_step)
-                 XDrawRectangle
-                   (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
-                    left + left_offset, top + 1,
-                    left_skip_step - 2, f->output_data.x->line_height - 3);
-             }
+             for (i = 0; i < len; i++)
+               XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+                               left + glyph_width * i, top,
+                               glyph_width -1, line_height - 1);
          }
        
        /* We should probably check for XA_UNDERLINE_POSITION and
@@ -1004,17 +1043,17 @@ dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
             on the default font of this frame.  */
          int underline_position = f->output_data.x->font_baseline + 1;
 
-         if (underline_position >= f->output_data.x->line_height)
-           underline_position = f->output_data.x->line_height - 1;
+         if (underline_position >= line_height)
+           underline_position = line_height - 1;
 
          if (face->underline)
            XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                            FACE_GC (face),
-                           left, top + underline_position, pixel_width, 1);
+                           left, top + underline_position, run_width, 1);
        }
 
        if (!cmpcharp)
-         left += pixel_width;
+         left += run_width;
       }
     }
 
@@ -5171,8 +5210,8 @@ x_new_font (f, fontname)
 
 /* Give frame F the fontset named FONTSETNAME as its default font, and
    return the full name of that fontset.  FONTSETNAME may be a wildcard
-   pattern; in that case, we choose some font that fits the pattern.
-   The return value shows which font we chose.  */
+   pattern; in that case, we choose some fontset that fits the pattern.
+   The return value shows which fontset we chose.  */
 
 Lisp_Object
 x_new_fontset (f, fontsetname)
@@ -6128,30 +6167,39 @@ x_list_fonts (f, pattern, size, maxnames)
      int size;
      int maxnames;
 {
-  Lisp_Object list, newlist, key;
+  Lisp_Object list, patterns = Qnil, newlist = Qnil, key, tem, second_best;
   Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
 
-  key = Fcons (pattern, make_number (maxnames));
-
-  if (f == NULL)
-    list = Qnil;
-  else
-    /* See if we cached the result for this particular query.  */
-    list = Fassoc (key,
-                  XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr);
-
-  /* Now LIST has the form (KEY . FONT-DATA-LIST), where KEY is a
-    pattern which matches font names in FONT-DATA-LIST, FONT-DATA-LIST
-    is a list of cons cells for the form (FONTNAME . FONTWIDTH).  */
+  for (list = Valternative_fontname_alist; CONSP (list);
+       list = XCONS (list)->cdr)
+    {
+      tem = XCONS (list)->car;
+      if (CONSP (tem)
+         && STRINGP (XCONS (tem)->car)
+         && !NILP (Fstring_equal (XCONS (tem)->car, pattern)))
+       {
+         patterns = XCONS (tem)->cdr;
+         break;
+       }
+    }
 
-  if (!NILP (list))
-    list = XCONS (list)->cdr;
-  else
+  for (patterns = Fcons (pattern, patterns); CONSP (patterns);
+       patterns = XCONS (patterns)->cdr, pattern = XCONS (patterns)->car)
     {
-      /* At first, put PATTERN in the cache.  */
       int num_fonts;
       char **names;
 
+      /* See if we cached the result for this particular query.  */
+      if (f && (tem = XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr,
+               key = Fcons (pattern, make_number (maxnames)),
+               !NILP (list = Fassoc (key, tem))))
+       {
+         list = Fcdr_safe (list);
+         /* We have a cashed list.  Don't have to get the list again.  */
+         goto label_cached;
+       }
+
+      /* At first, put PATTERN in the cache.  */
       BLOCK_INPUT;
       names = XListFonts (dpy, XSTRING (pattern)->data, maxnames, &num_fonts);
       UNBLOCK_INPUT;
@@ -6159,7 +6207,6 @@ x_list_fonts (f, pattern, size, maxnames)
       if (names)
        {
          int i;
-         Lisp_Object tem;
 
          /* Make a list of all the fonts we got back.
             Store that in the font cache for the display.  */
@@ -6169,10 +6216,10 @@ x_list_fonts (f, pattern, size, maxnames)
              int average_width = -1, dashes = 0, width = 0;
 
              /* Count the number of dashes in NAMES[I].  If there are
-                14 dashes, and the field value following 12th dash
-                (AVERAGE_WIDTH) is 0, this is a auto-scaled font
-                which is usually too ugly to be used for editing.
-                Let's ignore it.  */
+               14 dashes, and the field value following 12th dash
+               (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
+               is usually too ugly to be used for editing.  Let's
+               ignore it.  */
              while (*p)
                if (*p++ == '-')
                  {
@@ -6192,7 +6239,7 @@ x_list_fonts (f, pattern, size, maxnames)
                              (Vx_pixel_size_width_font_regexp, names[i])
                              >= 0))
                        /* We can set the value of PIXEL_SIZE to the
-                           width of this font.  */
+                         width of this font.  */
                        list = Fcons (Fcons (tem, make_number (width)), list);
                      else
                        /* For the moment, width is not known.  */
@@ -6203,31 +6250,33 @@ x_list_fonts (f, pattern, size, maxnames)
          XFreeFontNames (names);
        }
 
+      /* Now store the result in the cache.  */
       if (f != NULL)
        XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr
          = Fcons (Fcons (key, list),
                   XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr);
-    }
 
-  if (NILP (list))
-    return Qnil;
+    label_cached:
+      if (NILP (list)) continue; /* Try the remaining alternatives.  */
 
-  newlist = Qnil;
+      newlist = second_best = Qnil;
+      /* Make a list of the fonts that have the right width.  */
+      for (; CONSP (list); list = XCONS (list)->cdr)
+       {
+         tem = XCONS (list)->car;
 
-  /* Make a list of the fonts that have the right width.  */
-  for (; CONSP (list); list = XCONS (list)->cdr)
-    {
-      Lisp_Object tem = XCONS (list)->car;
-      int keeper;
+         if (!CONSP (tem) || NILP (XCONS (tem)->car))
+           continue;
+         if (!size)
+           {
+             newlist = Fcons (XCONS (tem)->car, newlist);
+             continue;
+           }
 
-      if (!CONSP (tem) || NILP (XCONS (tem)->car))
-       continue;
-      if (!size)
-       keeper = 1;
-      else
-       {
          if (!INTEGERP (XCONS (tem)->cdr))
            {
+             /* Since we have not yet known the size of this font, we
+               must try slow function call XLoadQueryFont.  */
              XFontStruct *thisinfo;
 
              BLOCK_INPUT;
@@ -6241,12 +6290,35 @@ x_list_fonts (f, pattern, size, maxnames)
                  XFreeFont (dpy, thisinfo);
                }
              else
+               /* For unknown reason, the previous call of XListFont had
+                 retruned a font which can't be opened.  Record the size
+                 as 0 not to try to open it again.  */
                XCONS (tem)->cdr = make_number (0);
            }
-         keeper = XINT (XCONS (tem)->cdr) == size;
+         if (XINT (XCONS (tem)->cdr) == size)
+           newlist = Fcons (XCONS (tem)->car, newlist);
+         else if (NILP (second_best))
+           second_best = tem;
+         else if (XINT (XCONS (tem)->cdr) < size)
+           {
+             if (XINT (XCONS (second_best)->cdr) > size
+                 || XINT (XCONS (second_best)->cdr) < XINT (XCONS (tem)->cdr))
+               second_best = tem;
+           }
+         else
+           {
+             if (XINT (XCONS (second_best)->cdr) > size
+                 && XINT (XCONS (second_best)->cdr) > XINT (XCONS (tem)->cdr))
+               second_best = tem;
+           }
+       }
+      if (!NILP (newlist))
+       break;
+      else if (!NILP (second_best))
+       {
+         newlist = Fcons (XCONS (second_best)->car, Qnil);
+         break;
        }
-      if (keeper)
-       newlist = Fcons (XCONS (tem)->car, newlist);
     }
 
   return newlist;
@@ -6298,7 +6370,7 @@ x_load_font (f, fontname, size)
     BLOCK_INPUT;
     font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
     UNBLOCK_INPUT;
-    if (!font || (size && font->max_bounds.width != size))
+    if (!font)
       return NULL;
 
     /* Do we need to create the table?  */