*** empty log message ***
[m17n/m17n-lib.git] / src / m17n-gd.c
index 6ffdc84..99269e1 100644 (file)
@@ -1,5 +1,5 @@
 /* m17n-gd.c -- implementation of the GUI API on GD Library.
-   Copyright (C) 2004
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
@@ -17,7 +17,7 @@
 
    You should have received a copy of the GNU Lesser General Public
    License along with the m17n library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    02111-1307, USA.  */
 
 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
@@ -67,13 +67,39 @@ static MSymbol M_rgb;
 static void
 read_rgb_txt ()
 {
-  FILE *fp = fopen ("/usr/lib/X11/rgb.txt", "r");
-  int r, g, b;
+  FILE *fp;
+  int r, g, b, i;
+
+  /* At first, support HTML 4.0 color names. */
+  msymbol_put (msymbol ("black"), M_rgb, (void *) 0x000000);
+  msymbol_put (msymbol ("silver"), M_rgb, (void *) 0xC0C0C0);
+  msymbol_put (msymbol ("gray"), M_rgb, (void *) 0x808080);
+  msymbol_put (msymbol ("white"), M_rgb, (void *) 0xFFFFFF);
+  msymbol_put (msymbol ("maroon"), M_rgb, (void *) 0x800000);
+  msymbol_put (msymbol ("red"), M_rgb, (void *) 0xFF0000);
+  msymbol_put (msymbol ("purple"), M_rgb, (void *) 0x800080);
+  msymbol_put (msymbol ("fuchsia"), M_rgb, (void *) 0xFF00FF);
+  msymbol_put (msymbol ("green"), M_rgb, (void *) 0x008000);
+  msymbol_put (msymbol ("lime"), M_rgb, (void *) 0x00FF00);
+  msymbol_put (msymbol ("olive"), M_rgb, (void *) 0x808000);
+  msymbol_put (msymbol ("yellow"), M_rgb, (void *) 0xFFFF00);
+  msymbol_put (msymbol ("navy"), M_rgb, (void *) 0x000080);
+  msymbol_put (msymbol ("blue"), M_rgb, (void *) 0x0000FF);
+  msymbol_put (msymbol ("teal"), M_rgb, (void *) 0x008080);
+  msymbol_put (msymbol ("aqua"), M_rgb, (void *) 0x00FFFF);
 
-  if (! fp)
-    fp = fopen ("/usr/X11R6/lib/X11/rgb.txt", "r");
-  if (! fp)
-    return;
+  {
+    char *rgb_path[]
+      =  {"/usr/lib/X11/rgb.txt", "/usr/X11R6/lib/X11/rgb.txt",
+         "/etc/X11/rgb.txt" };
+
+    fp = NULL;
+    for (i = 0; i < (sizeof rgb_path) / (sizeof rgb_path[0]); i++)
+      if ((fp = fopen ("/usr/lib/X11/rgb.txt", "r")))
+       break;
+    if (! fp)
+      return;
+  }
   while (1)
     {
       char buf[256];
@@ -95,6 +121,8 @@ read_rgb_txt ()
       buf[0] = c;
       fgets (buf + 1, 255, fp);
       len = strlen (buf);
+      for (i = 0; i < len; i++)
+       buf[i] = tolower (buf[i]);
       if (buf[len - 1] == '\n')
        buf[len - 1] = '\0';
       b |= (r << 16) | (g << 8);
@@ -223,6 +251,144 @@ intersect_rectangle (MDrawMetric *r1, MDrawMetric *r2, MDrawMetric *rect)
   gdImageColorResolve ((img), (color) >> 16, ((color) >> 8) & 0xFF,    \
                       (color) & 0xFF)
 
+static MRealizedFont *gd_font_open (MFrame *, MFont *, MFont *,
+                                   MRealizedFont *);
+static void gd_render (MDrawWindow, int, int, MGlyphString *,
+                      MGlyph *, MGlyph *, int, MDrawRegion);
+
+static MFontDriver gd_font_driver =
+  { NULL, gd_font_open, NULL, NULL, NULL, gd_render, NULL };
+
+static MRealizedFont *
+gd_font_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
+{
+  double size = font->size ? font->size : spec->size;
+  int reg = spec->property[MFONT_REGISTRY];
+  MRealizedFont *new;
+
+  if (rfont)
+    {
+      MRealizedFont *save = NULL;
+
+      for (; rfont; rfont = rfont->next)
+       if (rfont->font == font
+           && (rfont->font->size ? rfont->font->size == size
+               : rfont->spec.size == size)
+           && rfont->spec.property[MFONT_REGISTRY] == reg)
+         {
+           if (! save)
+             save = rfont;
+           if (rfont->driver == &gd_font_driver)
+             return rfont;
+         }
+      rfont = save;
+    }
+  rfont = (mfont__ft_driver.open) (frame, font, spec, rfont);
+  if (! rfont)
+    return NULL;
+  M17N_OBJECT_REF (rfont->info);
+  MSTRUCT_CALLOC (new, MERROR_GD);
+  *new = *rfont;
+  new->driver = &gd_font_driver;
+  new->next = MPLIST_VAL (frame->realized_font_list);
+  MPLIST_VAL (frame->realized_font_list) = new;
+  return new;
+}
+
+static void
+gd_render (MDrawWindow win, int x, int y,
+          MGlyphString *gstring, MGlyph *from, MGlyph *to,
+          int reverse, MDrawRegion region)
+{
+  gdImagePtr img = (gdImagePtr) win;
+  FT_Face ft_face;
+  MRealizedFace *rface = from->rface;
+  FT_Int32 load_flags = FT_LOAD_RENDER;
+  int i, j;
+  int color, pixel;
+  int r, g, b;
+  
+  if (from == to)
+    return;
+
+  /* It is assured that the all glyphs in the current range use the
+     same realized face.  */
+  ft_face = rface->rfont->fontp;
+  color = ((int *) rface->info)[reverse ? COLOR_INVERSE : COLOR_NORMAL];
+  pixel = RESOLVE_COLOR (img, color);
+
+  if (gstring->anti_alias)
+    r = color >> 16, g = (color >> 8) & 0xFF, b = color & 0xFF;
+  else
+    {
+#ifdef FT_LOAD_TARGET_MONO
+      load_flags |= FT_LOAD_TARGET_MONO;
+#else
+      load_flags |= FT_LOAD_MONOCHROME;
+#endif
+    }
+
+  for (; from < to; x += from++->g.xadv)
+    {
+      unsigned char *bmp;
+      int xoff, yoff;
+      int width, pitch;
+
+      FT_Load_Glyph (ft_face, (FT_UInt) from->g.code, load_flags);
+      yoff = y - ft_face->glyph->bitmap_top + from->g.yoff;
+      bmp = ft_face->glyph->bitmap.buffer;
+      width = ft_face->glyph->bitmap.width;
+      pitch = ft_face->glyph->bitmap.pitch;
+      if (! gstring->anti_alias)
+       pitch *= 8;
+      if (width > pitch)
+       width = pitch;
+
+      if (gstring->anti_alias)
+       for (i = 0; i < ft_face->glyph->bitmap.rows;
+            i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
+         {
+           xoff = x + ft_face->glyph->bitmap_left + from->g.xoff;
+           for (j = 0; j < width; j++, xoff++)
+             if (bmp[j] > 0)
+               {
+                 int pixel1 = pixel;
+#if HAVE_GD > 1
+                 int alpha = gdAlphaTransparent * (255 - bmp[j]) / 255;
+
+                 if (alpha > 0)
+                   pixel1 = gdImageColorResolveAlpha (img, r, g, b, alpha);
+#else
+                 int f = bmp[j] >> 5;
+
+                 if (f < 7)
+                   {
+                     int r1, g1, b1, color1;
+
+                     pixel1 = gdImageGetPixel (img, xoff, yoff);
+                     r1 = gdImageRed (img, pixel1);
+                     g1 = gdImageGreen (img, pixel1);
+                     b1 = gdImageBlue (img, pixel1);
+                     color1 = ((((r * f + r1 * (7 - f)) / 7) << 16)
+                               | (((g * f + g1 * (7 - f)) / 7) << 8)
+                               | ((b * f + b1 * (7 - f)) / 7));
+                     pixel1 = RESOLVE_COLOR (img, color1);
+                   }
+#endif
+                 gdImageSetPixel (img, xoff, yoff, pixel1);
+               }
+         }
+      else
+       for (i = 0; i < ft_face->glyph->bitmap.rows;
+            i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
+         {
+           xoff = x + ft_face->glyph->bitmap_left + from->g.xoff;
+           for (j = 0; j < width; j++, xoff++)
+             if (bmp[j / 8] & (1 << (7 - (j % 8))))
+               gdImageSetPixel (img, xoff, yoff, pixel);
+         }
+    }
+}
 
 static void
 gd_close (MFrame *frame)
@@ -348,15 +514,15 @@ gd_draw_empty_boxes (MDrawWindow win, int x, int y,
   y -= gstring->ascent - 1;
   height = gstring->ascent + gstring->descent - 2;
   if (! region)
-    for (; from < to; x += from++->width)
-      gdImageRectangle (img, x, y, x + from->width - 2, y + height - 1, color);
+    for (; from < to; x += from++->g.xadv)
+      gdImageRectangle (img, x, y, x + from->g.xadv - 2, y + height - 1, color);
   else
     {
       gdImagePtr cpy;
       MGlyph *g;
       int width, x1;
 
-      for (g = from, width = 0; g < to; width += g++->width);
+      for (g = from, width = 0; g < to; width += g++->g.xadv);
       cpy = get_scrach_image (img, width, height);
       MPLIST_DO (plist, region_list)
        {
@@ -364,8 +530,8 @@ gd_draw_empty_boxes (MDrawWindow win, int x, int y,
          gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
                       rect->x + rect->width, rect->y + rect->height);
        }
-      for (x1 = 0; from < to; x1 += from++->width)
-       gdImageRectangle (cpy, x1, 0, x1 + from->width - 2, height - 1, color);
+      for (x1 = 0; from < to; x1 += from++->g.xadv)
+       gdImageRectangle (cpy, x1, 0, x1 + from->g.xadv - 2, height - 1, color);
       MPLIST_DO (plist, region_list)
        {
          MDrawMetric *rect = MPLIST_VAL (plist);
@@ -439,7 +605,7 @@ gd_draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
       gdImagePtr cpy;
 
       if (g->type == GLYPH_BOX)
-       width = g->width;
+       width = g->g.xadv;
       cpy = get_scrach_image (img, width, height);
       MPLIST_DO (plist, region_list)
        {
@@ -462,9 +628,9 @@ gd_draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
       int x0, x1;
 
       if (g->left_padding)
-       x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
+       x0 = x + box->outer_hmargin, x1 = x + g->g.xadv - 1;
       else
-       x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
+       x0 = x, x1 = x + g->g.xadv - box->outer_hmargin - 1;
 
       /* Draw the top side.  */
       color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
@@ -632,102 +798,7 @@ static MDeviceDriver gd_driver =
     gd_dump_region,
   };
 
-
-static void
-gd_render (MDrawWindow win, int x, int y,
-          MGlyphString *gstring, MGlyph *from, MGlyph *to,
-          int reverse, MDrawRegion region)
-{
-  gdImagePtr img = (gdImagePtr) win;
-  MFTInfo *ft_info;
-  FT_Face ft_face;
-  MRealizedFace *rface = from->rface;
-  FT_Int32 load_flags = FT_LOAD_RENDER;
-  int i, j;
-  int color, pixel;
-  int r, g, b;
-  
-  pixel = RESOLVE_COLOR (img, color);
-
-  if (from == to)
-    return;
-
-  /* It is assured that the all glyphs in the current range use the
-     same realized face.  */
-  ft_info = (MFTInfo *) rface->rfont->info;
-  ft_face = ft_info->ft_face;
-  color = ((int *) rface->info)[reverse ? COLOR_INVERSE : COLOR_NORMAL];
-  pixel = RESOLVE_COLOR (img, color);
-
-  if (gstring->anti_alias)
-    r = color >> 16, g = (color >> 8) & 0xFF, b = color & 0xFF;
-  else
-    {
-#ifdef FT_LOAD_TARGET_MONO
-      load_flags |= FT_LOAD_TARGET_MONO;
-#else
-      load_flags |= FT_LOAD_MONOCHROME;
-#endif
-    }
-
-  for (; from < to; x += from++->width)
-    {
-      unsigned char *bmp;
-      int xoff, yoff;
-      int width, pitch;
-
-      FT_Load_Glyph (ft_face, (FT_UInt) from->code, load_flags);
-      yoff = y - ft_face->glyph->bitmap_top + from->yoff;
-      bmp = ft_face->glyph->bitmap.buffer;
-      width = ft_face->glyph->bitmap.width;
-      pitch = ft_face->glyph->bitmap.pitch;
-      if (! gstring->anti_alias)
-       pitch *= 8;
-      if (width > pitch)
-       width = pitch;
-
-      if (gstring->anti_alias)
-       for (i = 0; i < ft_face->glyph->bitmap.rows;
-            i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
-         {
-           xoff = x + ft_face->glyph->bitmap_left + from->xoff;
-           for (j = 0; j < width; j++, xoff++)
-             if (bmp[j])
-               {
-                 int f = bmp[j] >> 5;
-                 int pixel1 = pixel;
-
-                 if (f < 7)
-                   {
-                     int r1, g1, b1, color1;
-
-                     pixel1 = gdImageGetPixel (img, xoff, yoff);
-                     r1 = gdImageRed (img, pixel1);
-                     g1 = gdImageGreen (img, pixel1);
-                     b1 = gdImageBlue (img, pixel1);
-                     color1 = ((((r * f + r1 * (7 - f)) / 7) << 16)
-                               | (((g * f + g1 * (7 - f)) / 7) << 8)
-                               | ((b * f + b1 * (7 - f)) / 7));
-                     pixel1 = RESOLVE_COLOR (img, color1);
-                   }
-                 gdImageSetPixel (img, xoff, yoff, pixel1);
-               }
-         }
-      else
-       for (i = 0; i < ft_face->glyph->bitmap.rows;
-            i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
-         {
-           xoff = x + ft_face->glyph->bitmap_left + from->xoff;
-           for (j = 0; j < width; j++, xoff++)
-             if (bmp[j / 8] & (1 << (7 - (j % 8))))
-               gdImageSetPixel (img, xoff, yoff, pixel);
-         }
-    }
-}
-
-
-static MFontDriver gd_font_driver =
-  { NULL, NULL, NULL, NULL, gd_render };
+/* Functions to be stored in MDeviceLibraryInterface by dlsym ().  */
 
 int
 device_init ()
@@ -740,9 +811,12 @@ device_init ()
   scratch_images[0] = scratch_images[1] = NULL;
 
   gd_font_driver.select = mfont__ft_driver.select;
-  gd_font_driver.open = mfont__ft_driver.open;
   gd_font_driver.find_metric = mfont__ft_driver.find_metric;
+  gd_font_driver.has_char = mfont__ft_driver.has_char;
   gd_font_driver.encode_char = mfont__ft_driver.encode_char;
+  gd_font_driver.list = mfont__ft_driver.list;
+  gd_font_driver.check_otf = mfont__ft_driver.check_otf;
+  gd_font_driver.drive_otf = mfont__ft_driver.drive_otf;
 
   return 0;
 }
@@ -766,8 +840,8 @@ device_fini ()
     }
   M17N_OBJECT_UNREF (realized_face_list);
 
-  MPLIST_DO (plist, realized_font_list)
-    mfont__free_realized ((MRealizedFont *) MPLIST_VAL (plist));
+  if (MPLIST_VAL (realized_font_list))
+    mfont__free_realized (MPLIST_VAL (realized_font_list));
   M17N_OBJECT_UNREF (realized_font_list);
 
   for (i = 0; i < 2; i++)
@@ -776,12 +850,16 @@ device_fini ()
   return 0;
 }
 
-void *
+int
 device_open (MFrame *frame, MPlist *param)
 {
   MFace *face;
 
+  frame->device = NULL;
   frame->device_type = MDEVICE_SUPPORT_OUTPUT;
+  frame->dpi = (int) mplist_get (param, Mresolution);
+  if (frame->dpi == 0)
+    frame->dpi = 100;
   frame->driver = &gd_driver;
   frame->font_driver_list = mplist ();
   mplist_add (frame->font_driver_list, Mfreetype, &gd_font_driver);
@@ -789,11 +867,17 @@ device_open (MFrame *frame, MPlist *param)
   frame->realized_face_list = realized_face_list;
   frame->realized_fontset_list = realized_fontset_list;
   face = mface_copy (mface__default);
+  mface_put_prop (face, Mfoundry, Mnil);
+  mface_put_prop (face, Mfamily, Mnil);
   mplist_push (param, Mface, face);
   M17N_OBJECT_UNREF (face);
-  return Mt;
+  return 0;
 }
 
+#else  /* not HAVE_GD nor HAVE_FREETYPE */
+
+int device_open () { return -1; }
+
 #endif /* not HAVE_GD nor HAVE_FREETYPE */
 
 /*** @} */