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., 59 Temple Place, Suite 330, Boston, MA
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;
302 pixel = RESOLVE_COLOR (img, color);
307 /* It is assured that the all glyphs in the current range use the
308 same realized face. */
309 ft_face = rface->rfont->fontp;
310 color = ((int *) rface->info)[reverse ? COLOR_INVERSE : COLOR_NORMAL];
311 pixel = RESOLVE_COLOR (img, color);
313 if (gstring->anti_alias)
314 r = color >> 16, g = (color >> 8) & 0xFF, b = color & 0xFF;
317 #ifdef FT_LOAD_TARGET_MONO
318 load_flags |= FT_LOAD_TARGET_MONO;
320 load_flags |= FT_LOAD_MONOCHROME;
324 for (; from < to; x += from++->width)
330 FT_Load_Glyph (ft_face, (FT_UInt) from->code, load_flags);
331 yoff = y - ft_face->glyph->bitmap_top + from->yoff;
332 bmp = ft_face->glyph->bitmap.buffer;
333 width = ft_face->glyph->bitmap.width;
334 pitch = ft_face->glyph->bitmap.pitch;
335 if (! gstring->anti_alias)
340 if (gstring->anti_alias)
341 for (i = 0; i < ft_face->glyph->bitmap.rows;
342 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
344 xoff = x + ft_face->glyph->bitmap_left + from->xoff;
345 for (j = 0; j < width; j++, xoff++)
350 int alpha = gdAlphaTransparent * (255 - bmp[j]) / 255;
353 pixel1 = gdImageColorResolveAlpha (img, r, g, b, alpha);
359 int r1, g1, b1, color1;
361 pixel1 = gdImageGetPixel (img, xoff, yoff);
362 r1 = gdImageRed (img, pixel1);
363 g1 = gdImageGreen (img, pixel1);
364 b1 = gdImageBlue (img, pixel1);
365 color1 = ((((r * f + r1 * (7 - f)) / 7) << 16)
366 | (((g * f + g1 * (7 - f)) / 7) << 8)
367 | ((b * f + b1 * (7 - f)) / 7));
368 pixel1 = RESOLVE_COLOR (img, color1);
371 gdImageSetPixel (img, xoff, yoff, pixel1);
375 for (i = 0; i < ft_face->glyph->bitmap.rows;
376 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
378 xoff = x + ft_face->glyph->bitmap_left + from->xoff;
379 for (j = 0; j < width; j++, xoff++)
380 if (bmp[j / 8] & (1 << (7 - (j % 8))))
381 gdImageSetPixel (img, xoff, yoff, pixel);
387 gd_close (MFrame *frame)
392 gd_get_prop (MFrame *frame, MSymbol key)
398 gd_realize_face (MRealizedFace *rface)
401 MFaceHLineProp *hline;
403 MSymbol *props = (MSymbol *) rface->face.property;
405 if (rface != rface->ascii_rface)
407 rface->info = rface->ascii_rface->info;
410 colors = malloc (sizeof (int) * COLOR_MAX);
411 colors[COLOR_NORMAL] = parse_color (props[MFACE_FOREGROUND]);
412 colors[COLOR_INVERSE] = parse_color (props[MFACE_BACKGROUND]);
413 if (rface->face.property[MFACE_VIDEOMODE] == Mreverse)
415 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
416 colors[COLOR_NORMAL] = colors[COLOR_INVERSE];
417 colors[COLOR_INVERSE] = colors[COLOR_HLINE];
419 colors[COLOR_HLINE] = 0;
421 hline = rface->hline;
425 colors[COLOR_HLINE] = parse_color (hline->color);
427 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
434 colors[COLOR_BOX_TOP] = parse_color (box->color_top);
436 colors[COLOR_BOX_TOP] = colors[COLOR_NORMAL];
438 if (box->color_left && box->color_left != box->color_top)
439 colors[COLOR_BOX_LEFT] = parse_color (box->color_left);
441 colors[COLOR_BOX_LEFT] = colors[COLOR_BOX_TOP];
443 if (box->color_bottom && box->color_bottom != box->color_top)
444 colors[COLOR_BOX_BOTTOM] = parse_color (box->color_bottom);
446 colors[COLOR_BOX_BOTTOM] = colors[COLOR_BOX_TOP];
448 if (box->color_right && box->color_right != box->color_bottom)
449 colors[COLOR_BOX_RIGHT] = parse_color (box->color_right);
451 colors[COLOR_BOX_RIGHT] = colors[COLOR_BOX_BOTTOM];
454 rface->info = colors;
458 gd_free_realized_face (MRealizedFace *rface)
464 gd_fill_space (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
466 int x, int y, int width, int height, MDrawRegion region)
468 gdImagePtr img = (gdImagePtr) win;
469 int *colors = rface->info;
470 int color = colors[reverse ? COLOR_NORMAL : COLOR_INVERSE];
471 MPlist *region_list = region, *plist;
473 color = RESOLVE_COLOR (img, color);
475 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
480 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
481 MPLIST_DO (plist, region_list)
483 MDrawMetric *r = MPLIST_VAL (plist), new;
485 if (INTERSECT_RECTANGLE (r, &rect, &new))
486 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
487 new.y + new.height - 1, color);
493 gd_draw_empty_boxes (MDrawWindow win, int x, int y,
494 MGlyphString *gstring, MGlyph *from, MGlyph *to,
495 int reverse, MDrawRegion region)
497 gdImagePtr img = (gdImagePtr) win;
498 int *colors = from->rface->info;
499 int color = colors[reverse ? COLOR_INVERSE : COLOR_NORMAL];
500 MPlist *region_list = region, *plist;
506 color = RESOLVE_COLOR (img, color);
507 y -= gstring->ascent - 1;
508 height = gstring->ascent + gstring->descent - 2;
510 for (; from < to; x += from++->width)
511 gdImageRectangle (img, x, y, x + from->width - 2, y + height - 1, color);
518 for (g = from, width = 0; g < to; width += g++->width);
519 cpy = get_scrach_image (img, width, height);
520 MPLIST_DO (plist, region_list)
522 MDrawMetric *rect = MPLIST_VAL (plist);
523 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
524 rect->x + rect->width, rect->y + rect->height);
526 for (x1 = 0; from < to; x1 += from++->width)
527 gdImageRectangle (cpy, x1, 0, x1 + from->width - 2, height - 1, color);
528 MPLIST_DO (plist, region_list)
530 MDrawMetric *rect = MPLIST_VAL (plist);
531 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
532 rect->x + rect->width, rect->y + rect->height);
539 gd_draw_hline (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
540 MRealizedFace *rface, int reverse,
541 int x, int y, int width, MDrawRegion region)
543 enum MFaceHLineType type = rface->hline->type;
544 int height = rface->hline->width;
545 gdImagePtr img = (gdImagePtr) win;
546 int *colors = rface->info;
547 int color = colors[COLOR_HLINE];
548 MPlist *region_list = region, *plist;
550 color = RESOLVE_COLOR (img, color);
551 y = (type == MFACE_HLINE_BOTTOM
552 ? y + gstring->text_descent - height
553 : type == MFACE_HLINE_UNDER
555 : type == MFACE_HLINE_STRIKE_THROUGH
556 ? y - ((gstring->ascent + gstring->descent) / 2)
557 : y - gstring->text_ascent);
559 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
564 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
565 MPLIST_DO (plist, region_list)
567 MDrawMetric *r = MPLIST_VAL (plist), new;
569 if (INTERSECT_RECTANGLE (r, &rect, &new))
570 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
571 new.y + new.height - 1, color);
578 gd_draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
579 MGlyph *g, int x, int y, int width, MDrawRegion region)
581 gdImagePtr img = (gdImagePtr) win;
582 int *colors = g->rface->info;
584 MRealizedFace *rface = g->rface;
585 MFaceBoxProp *box = rface->box;
586 MPlist *region_list = region, *plist;
590 y0 = y - (gstring->text_ascent
591 + rface->box->inner_vmargin + rface->box->width);
592 y1 = y + (gstring->text_descent
593 + rface->box->inner_vmargin + rface->box->width - 1);
597 int height = y1 - y0;
600 if (g->type == GLYPH_BOX)
602 cpy = get_scrach_image (img, width, height);
603 MPLIST_DO (plist, region_list)
605 MDrawMetric *rect = MPLIST_VAL (plist);
606 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
607 rect->x + rect->width, rect->y + rect->height);
609 gd_draw_box (frame, win, gstring, g, 0, y - y0, width, NULL);
610 MPLIST_DO (plist, region_list)
612 MDrawMetric *rect = MPLIST_VAL (plist);
613 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
614 rect->x + rect->width, rect->y + rect->height);
619 if (g->type == GLYPH_BOX)
624 x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
626 x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
628 /* Draw the top side. */
629 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
630 for (i = 0; i < box->width; i++)
631 gdImageLine (img, x0, y0 + i, x1, y0 + i, color);
633 /* Draw the bottom side. */
634 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
635 for (i = 0; i < box->width; i++)
636 gdImageLine (img, x0, y1 - i, x1, y1 - i, color);
638 if (g->left_padding > 0)
640 /* Draw the left side. */
641 color = RESOLVE_COLOR (img, colors[COLOR_BOX_LEFT]);
642 for (i = 0; i < rface->box->width; i++)
643 gdImageLine (img, x0 + i, y0 + i, x0 + i, y1 - i, color);
647 /* Draw the right side. */
648 color = RESOLVE_COLOR (img, colors[COLOR_BOX_RIGHT]);
649 for (i = 0; i < rface->box->width; i++)
650 gdImageLine (img, x1 - i, y0 + i, x1 - i, y1 - i, color);
656 /* Draw the top side. */
657 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
658 for (i = 0; i < box->width; i++)
659 gdImageLine (img, x, y0 + i, x + width - 1, y0 + i, color);
661 /* Draw the bottom side. */
662 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
663 for (i = 0; i < box->width; i++)
664 gdImageLine (img, x, y1 - i, x + width - 1, y1 - i, color);
670 gd_region_from_rect (MDrawMetric *rect)
673 MPlist *plist = mplist ();
675 MSTRUCT_MALLOC (new, MERROR_GD);
677 mplist_add (plist, Mt, new);
678 return (MDrawRegion) plist;
682 gd_union_rect_with_region (MDrawRegion region, MDrawMetric *rect)
684 MPlist *plist = (MPlist *) region;
687 MSTRUCT_MALLOC (r, MERROR_GD);
689 mplist_push (plist, Mt, r);
693 gd_intersect_region (MDrawRegion region1, MDrawRegion region2)
695 MPlist *plist1 = (MPlist *) region1, *p1 = plist1;
696 MPlist *plist2 = (MPlist *) region2;
698 MDrawMetric rect, *rect1, *rect2, *r;
700 while (! MPLIST_TAIL_P (p1))
702 rect1 = mplist_pop (p1);
703 MPLIST_DO (p2, plist2)
705 rect2 = MPLIST_VAL (p2);
706 if (INTERSECT_RECTANGLE (rect1, rect2, &rect))
708 MSTRUCT_MALLOC (r, MERROR_GD);
710 mplist_push (p1, Mt, r);
711 p1 = MPLIST_NEXT (p1);
719 gd_region_add_rect (MDrawRegion region, MDrawMetric *rect)
721 MPlist *plist = (MPlist *) region;
724 MSTRUCT_MALLOC (new, MERROR_GD);
726 mplist_push (plist, Mt, new);
730 gd_region_to_rect (MDrawRegion region, MDrawMetric *rect)
732 MPlist *plist = (MPlist *) region;
733 MDrawMetric *r = MPLIST_VAL (plist);
734 int min_x = r->x, max_x = min_x + r->width;
735 int min_y = r->y, max_y = min_y + r->height;
737 MPLIST_DO (plist, MPLIST_NEXT (plist))
739 r = MPLIST_VAL (plist);
742 if (r->x + r->width > max_x)
743 max_x = r->x + r->width;
746 if (r->y + r->height > max_y)
747 max_y = r->y + r->height;
751 rect->width = max_x - min_x;
752 rect->height =max_y - min_y;
756 gd_free_region (MDrawRegion region)
758 MPlist *plist = (MPlist *) region;
760 MPLIST_DO (plist, plist)
761 free (MPLIST_VAL (plist));
762 M17N_OBJECT_UNREF (region);
766 gd_dump_region (MDrawRegion region)
770 gd_region_to_rect (region, &rect);
771 fprintf (stderr, "(%d %d %d %d)\n", rect.x, rect.y, rect.width, rect.height);
774 static MDeviceDriver gd_driver =
779 gd_free_realized_face,
786 gd_union_rect_with_region,
794 /* Functions to be stored in MDeviceLibraryInterface by dlsym (). */
799 M_rgb = msymbol (" rgb");
801 realized_fontset_list = mplist ();
802 realized_font_list = mplist ();
803 realized_face_list = mplist ();
804 scratch_images[0] = scratch_images[1] = NULL;
806 gd_font_driver.select = mfont__ft_driver.select;
807 gd_font_driver.find_metric = mfont__ft_driver.find_metric;
808 gd_font_driver.has_char = mfont__ft_driver.has_char;
809 gd_font_driver.encode_char = mfont__ft_driver.encode_char;
810 gd_font_driver.list = mfont__ft_driver.list;
821 MPLIST_DO (plist, realized_fontset_list)
822 mfont__free_realized_fontset ((MRealizedFontset *) MPLIST_VAL (plist));
823 M17N_OBJECT_UNREF (realized_fontset_list);
825 MPLIST_DO (plist, realized_face_list)
827 MRealizedFace *rface = MPLIST_VAL (plist);
830 mface__free_realized (rface);
832 M17N_OBJECT_UNREF (realized_face_list);
834 if (MPLIST_VAL (realized_font_list))
835 mfont__free_realized (MPLIST_VAL (realized_font_list));
836 M17N_OBJECT_UNREF (realized_font_list);
838 for (i = 0; i < 2; i++)
839 if (scratch_images[i])
840 gdImageDestroy (scratch_images[i]);
845 device_open (MFrame *frame, MPlist *param)
849 frame->device = NULL;
850 frame->device_type = MDEVICE_SUPPORT_OUTPUT;
851 frame->dpi = (int) mplist_get (param, Mresolution);
854 frame->driver = &gd_driver;
855 frame->font_driver_list = mplist ();
856 mplist_add (frame->font_driver_list, Mfreetype, &gd_font_driver);
857 frame->realized_font_list = realized_font_list;
858 frame->realized_face_list = realized_face_list;
859 frame->realized_fontset_list = realized_fontset_list;
860 face = mface_copy (mface__default);
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 */