(compose_glyph_string): Terminate the last loop after
[m17n/m17n-lib.git] / src / draw.c
index d182f0c..05b6f24 100644 (file)
@@ -84,8 +84,6 @@ static MSymbol Mlatin, Minherited;
 /* Special categories */
 static MSymbol McatCc, McatCf;
 
-static MSymbol Mdepth;
-
 \f
 /* Glyph-string composer.  */
 
@@ -239,9 +237,8 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
   int pos;
   MSymbol language = Mnil, script = Mnil, charset = Mnil;
   MRealizedFace *rface = default_rface;
-  int non_ascii_found;
   int size = gstring->control.fixed_width;
-  int i, limit;
+  int i;
   int last;
 
   MLIST_RESET (gstring);
@@ -259,7 +256,6 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
 
   stop = face_change = charset_change = language_change = pos = from;
   last = 0;
-  non_ascii_found = 0;
   while (1)
     {
       int c;
@@ -269,9 +265,10 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
        c = mtext_ref_char (mt, pos);
       else
        c = '\n';
-      g_tmp.category = Mnil;
       if (c < 0x100)
        {
+         /* Short cut for the obvious case.  */
+         g_tmp.category = Mnil;
          if (c == ' ' || c == '\n' || c == '\t')
            g_tmp.type = GLYPH_SPACE, this_script = Mnil;
          else
@@ -282,69 +279,86 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
          g_tmp.category = mchar_get_prop (c, Mcategory);
          g_tmp.type = GLYPH_CHAR;
          this_script = (MSymbol) mchar_get_prop (c, Mscript);
-         if (this_script == Minherited)
+         if (this_script == Minherited || this_script == Mnil)
            this_script = script;
+         if (this_script == Mnil)
+           /* Search forward for a character that explicitly
+              specifies a script.  */
+           for (i = pos + 1; i < to; i++)
+             {
+               int c1 = mtext_ref_char (mt, i); 
+               MSymbol sym = ((c1 > 0x20 && c1 < 0x100) ? Mlatin
+                              : mchar_get_prop (c1, Mscript));
+               
+               if (sym != Minherited && sym != Mnil)
+                 {
+                   this_script = sym;
+                   break;
+                 }
+             }
        }
 
       if (pos == stop || script != this_script
          || MGLYPH (last)->type != g_tmp.type)
        {
          g = MGLYPH (last);
-         if (non_ascii_found && g->type == GLYPH_CHAR)
+         if (g->type == GLYPH_CHAR)
            while (g < gstring->glyphs + gstring->used)
              g = mface__for_chars (script, language, charset,
                                    g, gstring->glyphs + gstring->used, size);
-         last = gstring->used;
-         non_ascii_found = 0;
-         script = this_script;
          if (pos == to)
            break;
-         if (pos < mtext_nchars (mt) && pos == language_change)
-           {
-             language = (MSymbol) mtext_get_prop (mt, pos, Mlanguage);
-             mtext_prop_range (mt, Mlanguage, pos, NULL, &language_change, 0);
-           }
-         if (pos < mtext_nchars (mt) && pos == charset_change)
-           {
-             charset = (MSymbol) mtext_get_prop (mt, pos, Mcharset);
-             mtext_prop_range (mt, Mcharset, pos, NULL, &charset_change, 0);
-           }
-         if (pos < mtext_nchars (mt) && pos == face_change)
+         last = gstring->used;
+         script = this_script;
+         if (pos == stop)
            {
-             MFace *faces[64];
-             int num = mtext_get_prop_values (mt, pos, Mface,
-                                              (void **) faces, 64);
-
-             mtext_prop_range (mt, Mface, pos, NULL, &face_change, 1);
-             rface = (num > 0
-                      ? mface__realize (frame, faces, num,
-                                        language, charset, size)
-                      : default_rface);
+             if (pos < mtext_nchars (mt) && pos == language_change)
+               {
+                 language = (MSymbol) mtext_get_prop (mt, pos, Mlanguage);
+                 mtext_prop_range (mt, Mlanguage, pos, NULL,
+                                   &language_change, 0);
+               }
+             if (pos < mtext_nchars (mt) && pos == charset_change)
+               {
+                 charset = (MSymbol) mtext_get_prop (mt, pos, Mcharset);
+                 mtext_prop_range (mt, Mcharset, pos, NULL,
+                                   &charset_change, 0);
+               }
+             if (pos < mtext_nchars (mt) && pos == face_change)
+               {
+                 MFace *faces[64];
+                 int num = mtext_get_prop_values (mt, pos, Mface,
+                                                  (void **) faces, 64);
+
+                 mtext_prop_range (mt, Mface, pos, NULL, &face_change, 1);
+                 rface = (num > 0
+                          ? mface__realize (frame, faces, num,
+                                            language, charset, size)
+                          : default_rface);
+               }
+             stop = to;
+             if (stop > language_change)
+               stop = language_change;
+             if (stop > charset_change)
+               stop = charset_change;
+             if (face_change < stop)
+               stop = face_change;             
            }
-         stop = to;
-         if (stop > language_change)
-           stop = language_change;
-         if (stop > charset_change)
-           stop = charset_change;
-         if (face_change < stop)
-           stop = face_change;         
        }
 
-      g_tmp.c = g_tmp.code = c;
+      g_tmp.c = c;
       g_tmp.pos = pos++;
       g_tmp.to = pos;
       g_tmp.rface = rface;
       
-      if (c >= 0x100)
-       non_ascii_found = 1;
-      else if (g_tmp.type == GLYPH_CHAR && (c <= 32 || c == 127))
+      if ((c <= 32 || c == 127) && g_tmp.type == GLYPH_CHAR)
        {
-         g_tmp.code = '^';
+         g_tmp.c = '^';
          APPEND_GLYPH (gstring, g_tmp);
          if (c < ' ')
-           g_tmp.code = g_tmp.c + 0x40;
+           g_tmp.c = c + 0x40;
          else
-           g_tmp.code = '?';
+           g_tmp.c = '?';
        }
       APPEND_GLYPH (gstring, g_tmp);
       if (c == '\n'
@@ -352,8 +366,6 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
        break;
     }
 
-  limit = pos - from;
-
   /* Append an anchor glyph.  */
   g_tmp.type = GLYPH_ANCHOR;
   g_tmp.c = 0;
@@ -418,6 +430,8 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
                }
              if (start + 1 < i)
                reorder_combining_chars (gstring, start, i);
+             if (this->type == GLYPH_ANCHOR)
+               break;
            }
          g = MGLYPH (i);
        }
@@ -1023,10 +1037,11 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y,
                this_x += fromg->width, this_width -= fromg->width;
              if (g[-1].type == GLYPH_BOX)
                this_width -= g[-1].width;
-             mwin__fill_space (frame, win, rface, 0,
-                               this_x, y - gstring->text_ascent, this_width,
-                               gstring->text_ascent + gstring->text_descent,
-                               control->clip_region);
+             (frame->driver->fill_space)
+               (frame, win, rface, 0,
+                this_x, y - gstring->text_ascent, this_width,
+                gstring->text_ascent + gstring->text_descent,
+                control->clip_region);
            }
          if (cursor)
            {
@@ -1047,25 +1062,24 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y,
                    rect.x += cursor_width - 1;
                  rect.width = 1;
                }
-             mwin__fill_space (frame, win, rface, 1,
-                               rect.x, rect.y, rect.width, rect.height,
-                               control->clip_region);
+             (*frame->driver->fill_space)
+               (frame, win, rface, 1, rect.x, rect.y, rect.width, rect.height,
+                control->clip_region);
              if (! region)
-               region = mwin__region_from_rect (&rect);
+               region = (*frame->driver->region_from_rect) (&rect);
              else
-               mwin__region_add_rect (region, &rect);
-             mwin__verify_region (frame, region);
+               (*frame->driver->region_add_rect) (region, &rect);
              if (cursor_bidi)
                {
                  if (cursor->bidi_level % 2)
                    rect.x -= 3;
                  rect.height = 2;
                  rect.width = cursor_width < 4 ? cursor_width : 4;
-                 mwin__fill_space (frame, win, rface, 1,
-                                   rect.x, rect.y, rect.width, rect.height,
-                                   control->clip_region);
-                 mwin__region_add_rect (region, &rect);
-                 mwin__verify_region (frame, region);
+                 (*frame->driver->fill_space)
+                   (frame, win, rface, 1,
+                    rect.x, rect.y, rect.width, rect.height,
+                    control->clip_region);
+                 (*frame->driver->region_add_rect) (region, &rect);
                }
            }
 
@@ -1096,24 +1110,23 @@ draw_background (MFrame *frame, MDrawWindow win, int x, int y,
                  rect.y = y - gstring->text_ascent;
                  rect.height = gstring->text_ascent + gstring->text_descent;
                  rect.width = 1;
-                 mwin__fill_space (frame, win, rface, 1,
-                                   rect.x, rect.y, rect.width, rect.height,
-                                   control->clip_region);
+                 (*frame->driver->fill_space)
+                   (frame, win, rface, 1,
+                    rect.x, rect.y, rect.width, rect.height,
+                    control->clip_region);
                  if (! region)
-                   region = mwin__region_from_rect (&rect);
+                   region = (*frame->driver->region_from_rect) (&rect);
                  else
-                   mwin__region_add_rect (region, &rect);
-                 mwin__verify_region (frame, region);
+                   (*frame->driver->region_add_rect) (region, &rect);
                  rect.y += rect.height - 2;
                  rect.height = 2;
                  rect.width = cursor_width < 4 ? cursor_width : 4;
                  if (! (cursor->bidi_level % 2))
                    rect.x -= rect.width - 1;
-                 mwin__fill_space (frame, win, rface, 1,
+                 (*frame->driver->fill_space) (frame, win, rface, 1,
                                    rect.x, rect.y, rect.width, rect.height,
                                    control->clip_region);
-                 mwin__region_add_rect (region, &rect);
-                 mwin__verify_region (frame, region);
+                 (*frame->driver->region_add_rect) (region, &rect);
                }
            }
          x += width;
@@ -1137,7 +1150,7 @@ render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
     {
       MDrawMetric rect;
 
-      mwin__region_to_rect (region, &rect);
+      (*frame->driver->region_to_rect) (region, &rect);
       if (rect.x > x)
        {
          while (g != gend && x + g->rbearing <= rect.x)
@@ -1181,11 +1194,11 @@ render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
 
          if (from_g->type == GLYPH_CHAR)
            {
-             if (rface->rfont && from_g->code >= 0)
+             if (rface->rfont && from_g->code != MCHAR_INVALID_CODE)
                (rface->rfont->driver->render) (win, x, y, gstring, from_g, g,
                                                reverse, region);
              else
-               mwin__draw_empty_boxes (win, x, y, gstring, from_g, g,
+               (*frame->driver->draw_empty_boxes) (win, x, y, gstring, from_g, g,
                                        reverse, region);
            }
          else if (from_g->type == GLYPH_BOX)
@@ -1193,18 +1206,18 @@ render_glyphs (MFrame *frame, MDrawWindow win, int x, int y, int width,
              /* Draw the left or right side of a box.  If
                 from_g->lbearing is nonzero, this is the left side,
                 else this is the right side.  */
-             mwin__draw_box (frame, win, gstring, from_g, x, y, 0, region);
+             (*frame->driver->draw_box) (frame, win, gstring, from_g, x, y, 0, region);
            }
 
          if (from_g->type != GLYPH_BOX)
            {
              if (rface->hline)
-               mwin__draw_hline (frame, win, gstring, rface, reverse,
+               (*frame->driver->draw_hline) (frame, win, gstring, rface, reverse,
                                  x, y, width, region);
              if (rface->box
                  && ! reverse)
                /* Draw the top and bottom side of a box.  */
-                  mwin__draw_box (frame, win, gstring, from_g,
+               (*frame->driver->draw_box) (frame, win, gstring, from_g,
                                   x, y, width, region);
            }
          x += width;
@@ -1321,9 +1334,9 @@ render_glyph_string (MFrame *frame, MDrawWindow win, int x, int y,
        {
          rect.y = y - gstring->line_ascent;
          rect.height = gstring->height;
-         clip_region = mwin__region_from_rect (&rect);
+         clip_region = (*frame->driver->region_from_rect) (&rect);
          if (control->clip_region)
-           mwin__intersect_region (clip_region, control->clip_region);
+           (*frame->driver->intersect_region) (clip_region, control->clip_region);
        }
       else
        clip_region = control->clip_region;
@@ -1336,14 +1349,14 @@ render_glyph_string (MFrame *frame, MDrawWindow win, int x, int y,
   if (cursor_region)
     {
       if (clip_region)
-       mwin__intersect_region (cursor_region, clip_region);
+       (*frame->driver->intersect_region) (cursor_region, clip_region);
       render_glyphs (frame, win, x, y, to_x - x, gstring, from_idx, to_idx,
                     1, cursor_region);
     }
   if (clip_region != control->clip_region)
-    mwin__free_region (clip_region);
+    (*frame->driver->free_region) (clip_region);
   if (cursor_region)
-    mwin__free_region (cursor_region);
+    (*frame->driver->free_region) (cursor_region);
   return;
 }
 
@@ -1393,9 +1406,6 @@ alloc_gstring (MFrame *frame, MText *mt, int pos, MDrawControl *control,
   else
     gstring->width_limit = control->max_line_width;
   gstring->anti_alias = control->anti_alias;
-  if (gstring->anti_alias
-      && (unsigned) mwin__device_get_prop (frame->device, Mdepth) < 8)
-    gstring->anti_alias = 0;
   return gstring;
 }
 
@@ -1714,7 +1724,6 @@ mdraw__init ()
 
   McatCc = msymbol ("Cc");
   McatCf = msymbol ("Cf");
-  Mdepth = msymbol ("depth");
 
   MbidiR = msymbol ("R");
   MbidiAL = msymbol ("AL");
@@ -1895,6 +1904,7 @@ mdraw_text (MFrame *frame, MDrawWindow win, int x, int y,
 {
   MDrawControl control;
 
+  M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
   memset (&control, 0, sizeof control);
   control.as_image = 0;
   return draw_text (frame, win, x, y, mt, from, to, &control);
@@ -1957,6 +1967,7 @@ mdraw_image_text (MFrame *frame, MDrawWindow win, int x, int y,
 {
   MDrawControl control;
 
+  M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
   memset (&control, 0, sizeof control);
   control.as_image = 1;
   return draw_text (frame, win, x, y, mt, from, to, &control);
@@ -2000,6 +2011,7 @@ int
 mdraw_text_with_control (MFrame *frame, MDrawWindow win, int x, int y,
                         MText *mt, int from, int to, MDrawControl *control)
 {
+  M_CHECK_WRITABLE (frame, MERROR_DRAW, -1);
   return draw_text (frame, win, x, y, mt, from, to, control);
 }
 
@@ -2225,7 +2237,7 @@ mdraw_text_per_char_extents (MFrame *frame,
   ASSURE_CONTROL (control);
   *num_chars_return = to - from;
   if (array_size < *num_chars_return)
-    return 0;
+    MERROR (MERROR_DRAW, -1);
   if (overall_logical_return)
     memset (overall_logical_return, 0, sizeof (MDrawMetric));
   if (overall_ink_return)
@@ -2299,7 +2311,7 @@ mdraw_text_per_char_extents (MFrame *frame,
     }
 
   M17N_OBJECT_UNREF (gstring->top);
-  return 1;
+  return 0;
 }
 
 /*=*/
@@ -2486,14 +2498,16 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
     }
   info->from = g->pos;
   info->to = g->to;
+  info->glyph_code = g->code;
   info->this.x = g->lbearing;
   info->this.y = - gstring->line_ascent;
   info->this.height = gstring->height;
+  info->this.width = - g->lbearing + g->width;
   if (g->rface->rfont)
     info->font = &g->rface->rfont->font;
   else
     info->font = NULL;
-  /* info->this.width is calculated later.  */
+  /* info->logical_width is calculated later.  */
 
   if (info->from > info->line_from)
     {
@@ -2570,9 +2584,10 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
   else
     info->next_to = -1;
 
-  for (info->this.width = (g++)->width;
+  for (info->logical_width = (g++)->width;
        g->pos == pos && g->type != GLYPH_ANCHOR;
-       info->this.width += (g++)->width);
+       info->this.width += g->width, info->logical_width += (g++)->width);
+  info->this.width += g[-1].rbearing - g[-1].width;
 
   if (g->type != GLYPH_ANCHOR)
     info->right_from = g->pos, info->right_to = g->to;
@@ -2609,6 +2624,54 @@ mdraw_glyph_info (MFrame *frame, MText *mt, int from, int pos,
 
 /*=*/
 
+int
+mdraw_glyph_list (MFrame *frame, MText *mt, int from, int to,
+                 MDrawControl *control, MDrawGlyphInfo *info,
+                 int array_size, int *num_glyphs_return)
+{
+  MGlyphString *gstring;
+  MGlyph *g;
+  int n;
+
+  ASSURE_CONTROL (control);
+  *num_glyphs_return = 0;
+  M_CHECK_RANGE (mt, from, to, -1, 0);
+  gstring = get_gstring (frame, mt, from, to, control);
+  if (! gstring)
+    return -1;
+  for (g = MGLYPH (1), n = 0; g->type != GLYPH_ANCHOR; g++)
+    {
+      if (g->type == GLYPH_BOX
+         || g->pos < from || g->pos >= to)
+       continue;
+      if (n < array_size)
+       {
+         info->from = g->pos;
+         info->to = g->to;
+         info->glyph_code = (g->type == GLYPH_CHAR ? g->code : 0);
+         info->x = g->xoff;
+         info->y = g->yoff;
+         info->this.x = g->lbearing;
+         info->this.y = - g->ascent;
+         info->this.height = g->ascent + g->descent;
+         info->this.width = g->rbearing - g->lbearing;
+         info->logical_width = g->width;
+         if (g->rface->rfont)
+           info->font = &g->rface->rfont->font;
+         else
+           info->font = NULL;
+         info++;
+       }
+      n++;
+    }
+  M17N_OBJECT_UNREF (gstring->top);
+
+  *num_glyphs_return = n;
+  return (n <= array_size ? 0 : -1);
+}
+
+/*=*/
+
 /***en
     @brief Draw one or more textitems.
 
@@ -2635,6 +2698,8 @@ void
 mdraw_text_items (MFrame *frame, MDrawWindow win, int x, int y,
                  MDrawTextItem *items, int nitems)
 {
+  if (! (frame->device_type & MDEVICE_SUPPORT_OUTPUT))
+    return;
   while (nitems-- > 0)
     {
       if (items->face)
@@ -2734,18 +2799,18 @@ mdraw_default_line_break (MText *mt, int pos,
 
     If pointer $OVERALL_RETURN is not @c NULL, this function also
     computes the extents of the overall text and stores the results in
-    the members of the structure pointed to by $OVERALL_RETURN  */
+    the members of the structure pointed to by $OVERALL_RETURN.  */
 
 /***ja
     @brief M-text ¤Îʸ»úËè¤Îɽ¼¨ÈϰϾðÊó¤òÆÀ¤ë.
 
     ´Ø¿ô mdraw_per_char_extents () ¤Ï¡¢M-text $MT Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈÏ°Ï
     ¤ò·×»»¤¹¤ë¡£¤³¤Î·×»»¤ËÍѤ¤¤ë¥Õ¥©¥ó¥È¤Ï¡¢$MT ¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤Ç
-    »ØÄꤵ¤ì¤¿¥Õ¥§¡¼¥¹¤È¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥§¡¼¥¹¤Ë¤è¤Ã¤Æ·è
-    ¤Þ¤ë¡£$ARRAY_RETURN ¤Î³ÆÍ×ÁǤϡ¢Åö³º M-text Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈÏ°Ï
-    ¾ðÊó¤Ë¤è¤Ã¤Æ½ç¤ËËä¤á¤é¤ì¤ë¡£¤³¤Îɽ¼¨ÈϰϾðÊó¤Ï¡¢M-text ¤Îɽ¼¨¸¶ÅÀ
-    ¤«¤é¤ÎÁêÂаÌÃ֤Ǥ¢¤ë¡£$ARRAY_RETURN ¤ÎÍ×ÁÇ¿ô¤Ï¡¢M-text ¤Îʸ»ú¿ô°Ê
-    ¾å¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£
+    »ØÄꤵ¤ì¤¿¥Õ¥§¡¼¥¹¤Èa¡¢¥Õ¥ì¡¼¥à $FRAME ¤Î¥Ç¥Õ¥©¥ë¥È¥Õ¥§¡¼¥¹¤Ë¤è¤Ã¤Æ
+    ·è¤Þ¤ë¡£$ARRAY_RETURN ¤Î³ÆÍ×ÁǤϡ¢Åö³º M-text Ãæ¤Î³Æʸ»ú¤Îɽ¼¨ÈÏ°Ï
+    ¾ðÊó¤Ë¤è¤Ã¤Æ½ç¤ËËä¤á¤é¤ì¤ë¡£¤³¤Îɽ¼¨ÈϰϾðÊó¤Ï¡¢M-text ¤Îɽ¼¨¸¶ÅÀ¤«
+    ¤é¤ÎÁêÂаÌÃ֤Ǥ¢¤ë¡£$ARRAY_RETURN ¤ÎÍ×ÁÇ¿ô¤Ï¡¢M-text ¤Î°Ê¾å¤Ç¤Ê¤±¤ì
+    ¤Ð¤Ê¤é¤Ê¤¤¡£
 
     ¥Ý¥¤¥ó¥¿ $OVERALL_RETURN ¤¬ @c NULL ¤Ç¤Ê¤¤¾ì¹ç¤Ï¡¢¥Æ¥­¥¹¥ÈÁ´ÂΤÎɽ
     ¼¨ÈϰϾðÊó¤â·×»»¤·¡¢¤½¤Î·ë²Ì¤ò $OVERALL_RETURN ¤Î»Ø¤¹¹½Â¤ÂΤ˳ÊǼ
@@ -2755,9 +2820,13 @@ mdraw_default_line_break (MText *mt, int pos,
 
 void
 mdraw_per_char_extents (MFrame *frame, MText *mt,
-  MDrawMetric *array_return,
-  MDrawMetric *overall_return)
+                       MDrawMetric *array_return,
+                       MDrawMetric *overall_return)
 {
+  int n = mtext_nchars (mt);
+
+  mdraw_text_per_char_extents (frame, mt, 0, n, NULL, array_return, NULL,
+                              n, &n, overall_return, NULL);
 }
 
 /***en