1 /* m17n-gd.c -- implementation of the GUI API on GD Library.
2 Copyright (C) 2004, 2005, 2006
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
6 This file is part of the m17n library.
8 The m17n library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public License
10 as published by the Free Software Foundation; either version 2.1 of
11 the License, or (at your option) any later version.
13 The m17n library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with the m17n library; if not, write to the Free
20 Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
24 /*** @addtogroup m17nInternal
29 #if defined (HAVE_FREETYPE) && defined (HAVE_GD)
38 #include "m17n-misc.h"
40 #include "internal-gui.h"
46 static MPlist *realized_fontset_list;
47 static MPlist *realized_font_list;
48 static MPlist *realized_face_list;
50 /* The first element is for 256 color, the second for true color. */
51 static gdImagePtr scratch_images[2];
73 /* At first, support HTML 4.0 color names. */
74 msymbol_put (msymbol ("black"), M_rgb, (void *) 0x000000);
75 msymbol_put (msymbol ("silver"), M_rgb, (void *) 0xC0C0C0);
76 msymbol_put (msymbol ("gray"), M_rgb, (void *) 0x808080);
77 msymbol_put (msymbol ("white"), M_rgb, (void *) 0xFFFFFF);
78 msymbol_put (msymbol ("maroon"), M_rgb, (void *) 0x800000);
79 msymbol_put (msymbol ("red"), M_rgb, (void *) 0xFF0000);
80 msymbol_put (msymbol ("purple"), M_rgb, (void *) 0x800080);
81 msymbol_put (msymbol ("fuchsia"), M_rgb, (void *) 0xFF00FF);
82 msymbol_put (msymbol ("green"), M_rgb, (void *) 0x008000);
83 msymbol_put (msymbol ("lime"), M_rgb, (void *) 0x00FF00);
84 msymbol_put (msymbol ("olive"), M_rgb, (void *) 0x808000);
85 msymbol_put (msymbol ("yellow"), M_rgb, (void *) 0xFFFF00);
86 msymbol_put (msymbol ("navy"), M_rgb, (void *) 0x000080);
87 msymbol_put (msymbol ("blue"), M_rgb, (void *) 0x0000FF);
88 msymbol_put (msymbol ("teal"), M_rgb, (void *) 0x008080);
89 msymbol_put (msymbol ("aqua"), M_rgb, (void *) 0x00FFFF);
91 fp = fopen ("/usr/lib/X11/rgb.txt", "r");
93 fp = fopen ("/usr/X11R6/lib/X11/rgb.txt", "r");
101 if ((c = getc (fp)) == EOF)
105 while ((c = getc (fp)) != EOF && c != '\n');
109 if (fscanf (fp, "%d %d %d", &r, &g, &b) != 3)
111 while ((c = getc (fp)) != EOF && isspace (c));
115 fgets (buf + 1, 255, fp);
117 if (buf[len - 1] == '\n')
119 b |= (r << 16) | (g << 8);
120 msymbol_put (msymbol (buf), M_rgb, (void *) b);
127 parse_color (MSymbol sym)
129 char *name = MSYMBOL_NAME (sym);
130 unsigned r = 0x80, g = 0x80, b = 0x80;
134 if (strncmp (name , "rgb:", 4) == 0)
137 if (sscanf (name, "%x", &r) < 1)
139 for (i = 0; *name != '/'; i++, name++);
140 r = (i == 1 ? ((r << 1) | r) : (r >> (i - 2)));
142 if (sscanf (name, "%x", &g) < 1)
144 for (i = 0; *name != '/'; i++, name++);
145 g = (i == 1 ? ((g << 1) | g) : (g >> (i - 2)));
147 if (sscanf (name, "%x", &b) < 1)
149 for (i = 0; *name; i++, name++);
150 b = (i == 1 ? ((b << 1) | b) : (b >> (i - 2)));
152 else if (*name == '#')
158 if (sscanf (name, "%1x%1x%1x", &r, &g, &b) < 3)
160 r <<= 4, g <<= 4, b <<= 4;
164 if (sscanf (name, "%2x%2x%2x", &r, &g, &b) < 3)
169 if (sscanf (name, "%3x%3x%3x", &r, &g, &b) < 3)
171 r >>= 1, g >>= 1, b >>= 1;
175 if (sscanf (name, "%4x%4x%4x", &r, &g, &b) < 3)
177 r >>= 2, g >>= 2, b >>= 2;
181 return (int) msymbol_get (sym, M_rgb);
184 return ((r << 16) | (g << 8) | b);
189 get_scrach_image (gdImagePtr img, int width, int height)
197 index = img->trueColor ? 1 : 0;
199 scratch = scratch_images[index];
203 if (scratch->sx <= width && scratch->sy <= height)
205 gdImageDestroy (scratch);
209 scratch = scratch_images[1] = gdImageCreateTrueColor (width, height);
212 scratch = scratch_images[0] = gdImageCreate (width, height);
217 intersect_rectangle (MDrawMetric *r1, MDrawMetric *r2, MDrawMetric *rect)
221 rect->width -= (r2->x - rect->x), rect->x = r2->x;
222 if (rect->x + rect->width > r2->x + r2->width)
223 rect->width -= (r2->x + r2->width - rect->x - rect->width);
225 rect->height -= (r2->y - rect->y), rect->y = r2->y;
226 if (rect->y + rect->height > r2->y + r2->height)
227 rect->height -= (r2->y + r2->height - rect->y - rect->height);
232 #define INTERSECT_RECTANGLE(r1, r2, rect) \
233 (((r1)->x + (r1->width) <= (r2)->x \
234 || (r2)->x + (r2)->width <= (r1)->x \
235 || (r1)->y + (r1->height) <= (r2)->y \
236 || (r2)->y + (r2)->height <= (r1)->y) \
238 : intersect_rectangle (r1, r2, rect))
241 #define RESOLVE_COLOR(img, color) \
242 gdImageColorResolve ((img), (color) >> 16, ((color) >> 8) & 0xFF, \
245 static MRealizedFont *gd_font_open (MFrame *, MFont *, MFont *,
247 static void gd_render (MDrawWindow, int, int, MGlyphString *,
248 MGlyph *, MGlyph *, int, MDrawRegion);
250 static MFontDriver gd_font_driver =
251 { NULL, gd_font_open, NULL, NULL, NULL, gd_render, NULL };
253 static MRealizedFont *
254 gd_font_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
256 double size = font->size ? font->size : spec->size;
257 int reg = spec->property[MFONT_REGISTRY];
262 MRealizedFont *save = NULL;
264 for (; rfont; rfont = rfont->next)
265 if (rfont->font == font
266 && (rfont->font->size ? rfont->font->size == size
267 : rfont->spec.size == size)
268 && rfont->spec.property[MFONT_REGISTRY] == reg)
272 if (rfont->driver == &gd_font_driver)
277 rfont = (mfont__ft_driver.open) (frame, font, spec, rfont);
280 M17N_OBJECT_REF (rfont->info);
281 MSTRUCT_CALLOC (new, MERROR_GD);
283 new->driver = &gd_font_driver;
284 new->next = MPLIST_VAL (frame->realized_font_list);
285 MPLIST_VAL (frame->realized_font_list) = new;
290 gd_render (MDrawWindow win, int x, int y,
291 MGlyphString *gstring, MGlyph *from, MGlyph *to,
292 int reverse, MDrawRegion region)
294 gdImagePtr img = (gdImagePtr) win;
296 MRealizedFace *rface = from->rface;
297 FT_Int32 load_flags = FT_LOAD_RENDER;
305 /* It is assured that the all glyphs in the current range use the
306 same realized face. */
307 ft_face = rface->rfont->fontp;
308 color = ((int *) rface->info)[reverse ? COLOR_INVERSE : COLOR_NORMAL];
309 pixel = RESOLVE_COLOR (img, color);
311 if (gstring->anti_alias)
312 r = color >> 16, g = (color >> 8) & 0xFF, b = color & 0xFF;
315 #ifdef FT_LOAD_TARGET_MONO
316 load_flags |= FT_LOAD_TARGET_MONO;
318 load_flags |= FT_LOAD_MONOCHROME;
322 for (; from < to; x += from++->width)
328 FT_Load_Glyph (ft_face, (FT_UInt) from->code, load_flags);
329 yoff = y - ft_face->glyph->bitmap_top + from->yoff;
330 bmp = ft_face->glyph->bitmap.buffer;
331 width = ft_face->glyph->bitmap.width;
332 pitch = ft_face->glyph->bitmap.pitch;
333 if (! gstring->anti_alias)
338 if (gstring->anti_alias)
339 for (i = 0; i < ft_face->glyph->bitmap.rows;
340 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
342 xoff = x + ft_face->glyph->bitmap_left + from->xoff;
343 for (j = 0; j < width; j++, xoff++)
348 int alpha = gdAlphaTransparent * (255 - bmp[j]) / 255;
351 pixel1 = gdImageColorResolveAlpha (img, r, g, b, alpha);
357 int r1, g1, b1, color1;
359 pixel1 = gdImageGetPixel (img, xoff, yoff);
360 r1 = gdImageRed (img, pixel1);
361 g1 = gdImageGreen (img, pixel1);
362 b1 = gdImageBlue (img, pixel1);
363 color1 = ((((r * f + r1 * (7 - f)) / 7) << 16)
364 | (((g * f + g1 * (7 - f)) / 7) << 8)
365 | ((b * f + b1 * (7 - f)) / 7));
366 pixel1 = RESOLVE_COLOR (img, color1);
369 gdImageSetPixel (img, xoff, yoff, pixel1);
373 for (i = 0; i < ft_face->glyph->bitmap.rows;
374 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
376 xoff = x + ft_face->glyph->bitmap_left + from->xoff;
377 for (j = 0; j < width; j++, xoff++)
378 if (bmp[j / 8] & (1 << (7 - (j % 8))))
379 gdImageSetPixel (img, xoff, yoff, pixel);
385 gd_close (MFrame *frame)
390 gd_get_prop (MFrame *frame, MSymbol key)
396 gd_realize_face (MRealizedFace *rface)
399 MFaceHLineProp *hline;
401 MSymbol *props = (MSymbol *) rface->face.property;
403 if (rface != rface->ascii_rface)
405 rface->info = rface->ascii_rface->info;
408 colors = malloc (sizeof (int) * COLOR_MAX);
409 colors[COLOR_NORMAL] = parse_color (props[MFACE_FOREGROUND]);
410 colors[COLOR_INVERSE] = parse_color (props[MFACE_BACKGROUND]);
411 if (rface->face.property[MFACE_VIDEOMODE] == Mreverse)
413 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
414 colors[COLOR_NORMAL] = colors[COLOR_INVERSE];
415 colors[COLOR_INVERSE] = colors[COLOR_HLINE];
417 colors[COLOR_HLINE] = 0;
419 hline = rface->hline;
423 colors[COLOR_HLINE] = parse_color (hline->color);
425 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
432 colors[COLOR_BOX_TOP] = parse_color (box->color_top);
434 colors[COLOR_BOX_TOP] = colors[COLOR_NORMAL];
436 if (box->color_left && box->color_left != box->color_top)
437 colors[COLOR_BOX_LEFT] = parse_color (box->color_left);
439 colors[COLOR_BOX_LEFT] = colors[COLOR_BOX_TOP];
441 if (box->color_bottom && box->color_bottom != box->color_top)
442 colors[COLOR_BOX_BOTTOM] = parse_color (box->color_bottom);
444 colors[COLOR_BOX_BOTTOM] = colors[COLOR_BOX_TOP];
446 if (box->color_right && box->color_right != box->color_bottom)
447 colors[COLOR_BOX_RIGHT] = parse_color (box->color_right);
449 colors[COLOR_BOX_RIGHT] = colors[COLOR_BOX_BOTTOM];
452 rface->info = colors;
456 gd_free_realized_face (MRealizedFace *rface)
462 gd_fill_space (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
464 int x, int y, int width, int height, MDrawRegion region)
466 gdImagePtr img = (gdImagePtr) win;
467 int *colors = rface->info;
468 int color = colors[reverse ? COLOR_NORMAL : COLOR_INVERSE];
469 MPlist *region_list = region, *plist;
471 color = RESOLVE_COLOR (img, color);
473 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
478 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
479 MPLIST_DO (plist, region_list)
481 MDrawMetric *r = MPLIST_VAL (plist), new;
483 if (INTERSECT_RECTANGLE (r, &rect, &new))
484 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
485 new.y + new.height - 1, color);
491 gd_draw_empty_boxes (MDrawWindow win, int x, int y,
492 MGlyphString *gstring, MGlyph *from, MGlyph *to,
493 int reverse, MDrawRegion region)
495 gdImagePtr img = (gdImagePtr) win;
496 int *colors = from->rface->info;
497 int color = colors[reverse ? COLOR_INVERSE : COLOR_NORMAL];
498 MPlist *region_list = region, *plist;
504 color = RESOLVE_COLOR (img, color);
505 y -= gstring->ascent - 1;
506 height = gstring->ascent + gstring->descent - 2;
508 for (; from < to; x += from++->width)
509 gdImageRectangle (img, x, y, x + from->width - 2, y + height - 1, color);
516 for (g = from, width = 0; g < to; width += g++->width);
517 cpy = get_scrach_image (img, width, height);
518 MPLIST_DO (plist, region_list)
520 MDrawMetric *rect = MPLIST_VAL (plist);
521 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
522 rect->x + rect->width, rect->y + rect->height);
524 for (x1 = 0; from < to; x1 += from++->width)
525 gdImageRectangle (cpy, x1, 0, x1 + from->width - 2, height - 1, color);
526 MPLIST_DO (plist, region_list)
528 MDrawMetric *rect = MPLIST_VAL (plist);
529 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
530 rect->x + rect->width, rect->y + rect->height);
537 gd_draw_hline (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
538 MRealizedFace *rface, int reverse,
539 int x, int y, int width, MDrawRegion region)
541 enum MFaceHLineType type = rface->hline->type;
542 int height = rface->hline->width;
543 gdImagePtr img = (gdImagePtr) win;
544 int *colors = rface->info;
545 int color = colors[COLOR_HLINE];
546 MPlist *region_list = region, *plist;
548 color = RESOLVE_COLOR (img, color);
549 y = (type == MFACE_HLINE_BOTTOM
550 ? y + gstring->text_descent - height
551 : type == MFACE_HLINE_UNDER
553 : type == MFACE_HLINE_STRIKE_THROUGH
554 ? y - ((gstring->ascent + gstring->descent) / 2)
555 : y - gstring->text_ascent);
557 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
562 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
563 MPLIST_DO (plist, region_list)
565 MDrawMetric *r = MPLIST_VAL (plist), new;
567 if (INTERSECT_RECTANGLE (r, &rect, &new))
568 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
569 new.y + new.height - 1, color);
576 gd_draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
577 MGlyph *g, int x, int y, int width, MDrawRegion region)
579 gdImagePtr img = (gdImagePtr) win;
580 int *colors = g->rface->info;
582 MRealizedFace *rface = g->rface;
583 MFaceBoxProp *box = rface->box;
584 MPlist *region_list = region, *plist;
588 y0 = y - (gstring->text_ascent
589 + rface->box->inner_vmargin + rface->box->width);
590 y1 = y + (gstring->text_descent
591 + rface->box->inner_vmargin + rface->box->width - 1);
595 int height = y1 - y0;
598 if (g->type == GLYPH_BOX)
600 cpy = get_scrach_image (img, width, height);
601 MPLIST_DO (plist, region_list)
603 MDrawMetric *rect = MPLIST_VAL (plist);
604 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
605 rect->x + rect->width, rect->y + rect->height);
607 gd_draw_box (frame, win, gstring, g, 0, y - y0, width, NULL);
608 MPLIST_DO (plist, region_list)
610 MDrawMetric *rect = MPLIST_VAL (plist);
611 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
612 rect->x + rect->width, rect->y + rect->height);
617 if (g->type == GLYPH_BOX)
622 x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
624 x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
626 /* Draw the top side. */
627 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
628 for (i = 0; i < box->width; i++)
629 gdImageLine (img, x0, y0 + i, x1, y0 + i, color);
631 /* Draw the bottom side. */
632 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
633 for (i = 0; i < box->width; i++)
634 gdImageLine (img, x0, y1 - i, x1, y1 - i, color);
636 if (g->left_padding > 0)
638 /* Draw the left side. */
639 color = RESOLVE_COLOR (img, colors[COLOR_BOX_LEFT]);
640 for (i = 0; i < rface->box->width; i++)
641 gdImageLine (img, x0 + i, y0 + i, x0 + i, y1 - i, color);
645 /* Draw the right side. */
646 color = RESOLVE_COLOR (img, colors[COLOR_BOX_RIGHT]);
647 for (i = 0; i < rface->box->width; i++)
648 gdImageLine (img, x1 - i, y0 + i, x1 - i, y1 - i, color);
654 /* Draw the top side. */
655 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
656 for (i = 0; i < box->width; i++)
657 gdImageLine (img, x, y0 + i, x + width - 1, y0 + i, color);
659 /* Draw the bottom side. */
660 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
661 for (i = 0; i < box->width; i++)
662 gdImageLine (img, x, y1 - i, x + width - 1, y1 - i, color);
668 gd_region_from_rect (MDrawMetric *rect)
671 MPlist *plist = mplist ();
673 MSTRUCT_MALLOC (new, MERROR_GD);
675 mplist_add (plist, Mt, new);
676 return (MDrawRegion) plist;
680 gd_union_rect_with_region (MDrawRegion region, MDrawMetric *rect)
682 MPlist *plist = (MPlist *) region;
685 MSTRUCT_MALLOC (r, MERROR_GD);
687 mplist_push (plist, Mt, r);
691 gd_intersect_region (MDrawRegion region1, MDrawRegion region2)
693 MPlist *plist1 = (MPlist *) region1, *p1 = plist1;
694 MPlist *plist2 = (MPlist *) region2;
696 MDrawMetric rect, *rect1, *rect2, *r;
698 while (! MPLIST_TAIL_P (p1))
700 rect1 = mplist_pop (p1);
701 MPLIST_DO (p2, plist2)
703 rect2 = MPLIST_VAL (p2);
704 if (INTERSECT_RECTANGLE (rect1, rect2, &rect))
706 MSTRUCT_MALLOC (r, MERROR_GD);
708 mplist_push (p1, Mt, r);
709 p1 = MPLIST_NEXT (p1);
717 gd_region_add_rect (MDrawRegion region, MDrawMetric *rect)
719 MPlist *plist = (MPlist *) region;
722 MSTRUCT_MALLOC (new, MERROR_GD);
724 mplist_push (plist, Mt, new);
728 gd_region_to_rect (MDrawRegion region, MDrawMetric *rect)
730 MPlist *plist = (MPlist *) region;
731 MDrawMetric *r = MPLIST_VAL (plist);
732 int min_x = r->x, max_x = min_x + r->width;
733 int min_y = r->y, max_y = min_y + r->height;
735 MPLIST_DO (plist, MPLIST_NEXT (plist))
737 r = MPLIST_VAL (plist);
740 if (r->x + r->width > max_x)
741 max_x = r->x + r->width;
744 if (r->y + r->height > max_y)
745 max_y = r->y + r->height;
749 rect->width = max_x - min_x;
750 rect->height =max_y - min_y;
754 gd_free_region (MDrawRegion region)
756 MPlist *plist = (MPlist *) region;
758 MPLIST_DO (plist, plist)
759 free (MPLIST_VAL (plist));
760 M17N_OBJECT_UNREF (region);
764 gd_dump_region (MDrawRegion region)
768 gd_region_to_rect (region, &rect);
769 fprintf (stderr, "(%d %d %d %d)\n", rect.x, rect.y, rect.width, rect.height);
772 static MDeviceDriver gd_driver =
777 gd_free_realized_face,
784 gd_union_rect_with_region,
792 /* Functions to be stored in MDeviceLibraryInterface by dlsym (). */
797 M_rgb = msymbol (" rgb");
799 realized_fontset_list = mplist ();
800 realized_font_list = mplist ();
801 realized_face_list = mplist ();
802 scratch_images[0] = scratch_images[1] = NULL;
804 gd_font_driver.select = mfont__ft_driver.select;
805 gd_font_driver.find_metric = mfont__ft_driver.find_metric;
806 gd_font_driver.has_char = mfont__ft_driver.has_char;
807 gd_font_driver.encode_char = mfont__ft_driver.encode_char;
808 gd_font_driver.list = mfont__ft_driver.list;
819 MPLIST_DO (plist, realized_fontset_list)
820 mfont__free_realized_fontset ((MRealizedFontset *) MPLIST_VAL (plist));
821 M17N_OBJECT_UNREF (realized_fontset_list);
823 MPLIST_DO (plist, realized_face_list)
825 MRealizedFace *rface = MPLIST_VAL (plist);
828 mface__free_realized (rface);
830 M17N_OBJECT_UNREF (realized_face_list);
832 if (MPLIST_VAL (realized_font_list))
833 mfont__free_realized (MPLIST_VAL (realized_font_list));
834 M17N_OBJECT_UNREF (realized_font_list);
836 for (i = 0; i < 2; i++)
837 if (scratch_images[i])
838 gdImageDestroy (scratch_images[i]);
843 device_open (MFrame *frame, MPlist *param)
847 frame->device = NULL;
848 frame->device_type = MDEVICE_SUPPORT_OUTPUT;
849 frame->dpi = (int) mplist_get (param, Mresolution);
852 frame->driver = &gd_driver;
853 frame->font_driver_list = mplist ();
854 mplist_add (frame->font_driver_list, Mfreetype, &gd_font_driver);
855 frame->realized_font_list = realized_font_list;
856 frame->realized_face_list = realized_face_list;
857 frame->realized_fontset_list = realized_fontset_list;
858 face = mface_copy (mface__default);
859 mface_put_prop (face, Mfoundry, Mnil);
860 mface_put_prop (face, Mfamily, Mnil);
861 mplist_push (param, Mface, face);
862 M17N_OBJECT_UNREF (face);
866 #else /* not HAVE_GD nor HAVE_FREETYPE */
868 int device_open () { return -1; }
870 #endif /* not HAVE_GD nor HAVE_FREETYPE */
873 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */