1 /* m17n-gd.c -- implementation of the GUI API on GD Library.
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];
70 FILE *fp = fopen ("/usr/lib/X11/rgb.txt", "r");
74 fp = fopen ("/usr/X11R6/lib/X11/rgb.txt", "r");
82 if ((c = getc (fp)) == EOF)
86 while ((c = getc (fp)) != EOF && c != '\n');
90 if (fscanf (fp, "%d %d %d", &r, &g, &b) != 3)
92 while ((c = getc (fp)) != EOF && isspace (c));
96 fgets (buf + 1, 255, fp);
98 if (buf[len - 1] == '\n')
100 b |= (r << 16) | (g << 8);
101 msymbol_put (msymbol (buf), M_rgb, (void *) b);
108 parse_color (MSymbol sym)
110 char *name = MSYMBOL_NAME (sym);
111 unsigned r = 0x80, g = 0x80, b = 0x80;
115 if (strncmp (name , "rgb:", 4) == 0)
118 if (sscanf (name, "%x", &r) < 1)
120 for (i = 0; *name != '/'; i++, name++);
121 r = (i == 1 ? ((r << 1) | r) : (r >> (i - 2)));
123 if (sscanf (name, "%x", &g) < 1)
125 for (i = 0; *name != '/'; i++, name++);
126 g = (i == 1 ? ((g << 1) | g) : (g >> (i - 2)));
128 if (sscanf (name, "%x", &b) < 1)
130 for (i = 0; *name; i++, name++);
131 b = (i == 1 ? ((b << 1) | b) : (b >> (i - 2)));
133 else if (*name == '#')
139 if (sscanf (name, "%1x%1x%1x", &r, &g, &b) < 3)
141 r <<= 4, g <<= 4, b <<= 4;
145 if (sscanf (name, "%2x%2x%2x", &r, &g, &b) < 3)
150 if (sscanf (name, "%3x%3x%3x", &r, &g, &b) < 3)
152 r >>= 1, g >>= 1, b >>= 1;
156 if (sscanf (name, "%4x%4x%4x", &r, &g, &b) < 3)
158 r >>= 2, g >>= 2, b >>= 2;
162 return (int) msymbol_get (sym, M_rgb);
165 return ((r << 16) | (g << 8) | b);
170 get_scrach_image (gdImagePtr img, int width, int height)
178 index = img->trueColor ? 1 : 0;
180 scratch = scratch_images[index];
184 if (scratch->sx <= width && scratch->sy <= height)
186 gdImageDestroy (scratch);
190 scratch = scratch_images[1] = gdImageCreateTrueColor (width, height);
193 scratch = scratch_images[0] = gdImageCreate (width, height);
198 intersect_rectangle (MDrawMetric *r1, MDrawMetric *r2, MDrawMetric *rect)
202 rect->width -= (r2->x - rect->x), rect->x = r2->x;
203 if (rect->x + rect->width > r2->x + r2->width)
204 rect->width -= (r2->x + r2->width - rect->x - rect->width);
206 rect->height -= (r2->y - rect->y), rect->y = r2->y;
207 if (rect->y + rect->height > r2->y + r2->height)
208 rect->height -= (r2->y + r2->height - rect->y - rect->height);
213 #define INTERSECT_RECTANGLE(r1, r2, rect) \
214 (((r1)->x + (r1->width) <= (r2)->x \
215 || (r2)->x + (r2)->width <= (r1)->x \
216 || (r1)->y + (r1->height) <= (r2)->y \
217 || (r2)->y + (r2)->height <= (r1)->y) \
219 : intersect_rectangle (r1, r2, rect))
222 #define RESOLVE_COLOR(img, color) \
223 gdImageColorResolve ((img), (color) >> 16, ((color) >> 8) & 0xFF, \
226 static MRealizedFont *gd_font_open (MFrame *, MFont *, MFont *,
228 static void gd_render (MDrawWindow, int, int, MGlyphString *,
229 MGlyph *, MGlyph *, int, MDrawRegion);
231 static MFontDriver gd_font_driver =
232 { NULL, gd_font_open, NULL, NULL, NULL, gd_render, NULL };
234 static MRealizedFont *
235 gd_font_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
237 double size = font->size ? font->size : spec->size;
238 int reg = spec->property[MFONT_REGISTRY];
243 MRealizedFont *save = NULL;
245 for (; rfont; rfont = rfont->next)
246 if (rfont->font == font
247 && (rfont->font->size ? rfont->font->size == size
248 : rfont->spec.size == size)
249 && rfont->spec.property[MFONT_REGISTRY] == reg)
253 if (rfont->driver == &gd_font_driver)
258 rfont = (mfont__ft_driver.open) (frame, font, spec, rfont);
261 M17N_OBJECT_REF (rfont->info);
262 MSTRUCT_CALLOC (new, MERROR_GD);
264 new->driver = &gd_font_driver;
265 new->next = MPLIST_VAL (frame->realized_font_list);
266 MPLIST_VAL (frame->realized_font_list) = new;
271 gd_render (MDrawWindow win, int x, int y,
272 MGlyphString *gstring, MGlyph *from, MGlyph *to,
273 int reverse, MDrawRegion region)
275 gdImagePtr img = (gdImagePtr) win;
277 MRealizedFace *rface = from->rface;
278 FT_Int32 load_flags = FT_LOAD_RENDER;
283 pixel = RESOLVE_COLOR (img, color);
288 /* It is assured that the all glyphs in the current range use the
289 same realized face. */
290 ft_face = rface->rfont->fontp;
291 color = ((int *) rface->info)[reverse ? COLOR_INVERSE : COLOR_NORMAL];
292 pixel = RESOLVE_COLOR (img, color);
294 if (gstring->anti_alias)
295 r = color >> 16, g = (color >> 8) & 0xFF, b = color & 0xFF;
298 #ifdef FT_LOAD_TARGET_MONO
299 load_flags |= FT_LOAD_TARGET_MONO;
301 load_flags |= FT_LOAD_MONOCHROME;
305 for (; from < to; x += from++->width)
311 FT_Load_Glyph (ft_face, (FT_UInt) from->code, load_flags);
312 yoff = y - ft_face->glyph->bitmap_top + from->yoff;
313 bmp = ft_face->glyph->bitmap.buffer;
314 width = ft_face->glyph->bitmap.width;
315 pitch = ft_face->glyph->bitmap.pitch;
316 if (! gstring->anti_alias)
321 if (gstring->anti_alias)
322 for (i = 0; i < ft_face->glyph->bitmap.rows;
323 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
325 xoff = x + ft_face->glyph->bitmap_left + from->xoff;
326 for (j = 0; j < width; j++, xoff++)
330 int alpha = gdAlphaTransparent * (255 - bmp[j]) / 255;
333 pixel1 = gdImageColorResolveAlpha (img, r, g, b, alpha);
334 gdImageSetPixel (img, xoff, yoff, pixel1);
338 for (i = 0; i < ft_face->glyph->bitmap.rows;
339 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
341 xoff = x + ft_face->glyph->bitmap_left + from->xoff;
342 for (j = 0; j < width; j++, xoff++)
343 if (bmp[j / 8] & (1 << (7 - (j % 8))))
344 gdImageSetPixel (img, xoff, yoff, pixel);
350 gd_close (MFrame *frame)
355 gd_get_prop (MFrame *frame, MSymbol key)
361 gd_realize_face (MRealizedFace *rface)
364 MFaceHLineProp *hline;
366 MSymbol *props = (MSymbol *) rface->face.property;
368 if (rface != rface->ascii_rface)
370 rface->info = rface->ascii_rface->info;
373 colors = malloc (sizeof (int) * COLOR_MAX);
374 colors[COLOR_NORMAL] = parse_color (props[MFACE_FOREGROUND]);
375 colors[COLOR_INVERSE] = parse_color (props[MFACE_BACKGROUND]);
376 if (rface->face.property[MFACE_VIDEOMODE] == Mreverse)
378 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
379 colors[COLOR_NORMAL] = colors[COLOR_INVERSE];
380 colors[COLOR_INVERSE] = colors[COLOR_HLINE];
382 colors[COLOR_HLINE] = 0;
384 hline = rface->hline;
388 colors[COLOR_HLINE] = parse_color (hline->color);
390 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
397 colors[COLOR_BOX_TOP] = parse_color (box->color_top);
399 colors[COLOR_BOX_TOP] = colors[COLOR_NORMAL];
401 if (box->color_left && box->color_left != box->color_top)
402 colors[COLOR_BOX_LEFT] = parse_color (box->color_left);
404 colors[COLOR_BOX_LEFT] = colors[COLOR_BOX_TOP];
406 if (box->color_bottom && box->color_bottom != box->color_top)
407 colors[COLOR_BOX_BOTTOM] = parse_color (box->color_bottom);
409 colors[COLOR_BOX_BOTTOM] = colors[COLOR_BOX_TOP];
411 if (box->color_right && box->color_right != box->color_bottom)
412 colors[COLOR_BOX_RIGHT] = parse_color (box->color_right);
414 colors[COLOR_BOX_RIGHT] = colors[COLOR_BOX_BOTTOM];
417 rface->info = colors;
421 gd_free_realized_face (MRealizedFace *rface)
427 gd_fill_space (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
429 int x, int y, int width, int height, MDrawRegion region)
431 gdImagePtr img = (gdImagePtr) win;
432 int *colors = rface->info;
433 int color = colors[reverse ? COLOR_NORMAL : COLOR_INVERSE];
434 MPlist *region_list = region, *plist;
436 color = RESOLVE_COLOR (img, color);
438 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
443 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
444 MPLIST_DO (plist, region_list)
446 MDrawMetric *r = MPLIST_VAL (plist), new;
448 if (INTERSECT_RECTANGLE (r, &rect, &new))
449 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
450 new.y + new.height - 1, color);
456 gd_draw_empty_boxes (MDrawWindow win, int x, int y,
457 MGlyphString *gstring, MGlyph *from, MGlyph *to,
458 int reverse, MDrawRegion region)
460 gdImagePtr img = (gdImagePtr) win;
461 int *colors = from->rface->info;
462 int color = colors[reverse ? COLOR_INVERSE : COLOR_NORMAL];
463 MPlist *region_list = region, *plist;
469 color = RESOLVE_COLOR (img, color);
470 y -= gstring->ascent - 1;
471 height = gstring->ascent + gstring->descent - 2;
473 for (; from < to; x += from++->width)
474 gdImageRectangle (img, x, y, x + from->width - 2, y + height - 1, color);
481 for (g = from, width = 0; g < to; width += g++->width);
482 cpy = get_scrach_image (img, width, height);
483 MPLIST_DO (plist, region_list)
485 MDrawMetric *rect = MPLIST_VAL (plist);
486 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
487 rect->x + rect->width, rect->y + rect->height);
489 for (x1 = 0; from < to; x1 += from++->width)
490 gdImageRectangle (cpy, x1, 0, x1 + from->width - 2, height - 1, color);
491 MPLIST_DO (plist, region_list)
493 MDrawMetric *rect = MPLIST_VAL (plist);
494 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
495 rect->x + rect->width, rect->y + rect->height);
502 gd_draw_hline (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
503 MRealizedFace *rface, int reverse,
504 int x, int y, int width, MDrawRegion region)
506 enum MFaceHLineType type = rface->hline->type;
507 int height = rface->hline->width;
508 gdImagePtr img = (gdImagePtr) win;
509 int *colors = rface->info;
510 int color = colors[COLOR_HLINE];
511 MPlist *region_list = region, *plist;
513 color = RESOLVE_COLOR (img, color);
514 y = (type == MFACE_HLINE_BOTTOM
515 ? y + gstring->text_descent - height
516 : type == MFACE_HLINE_UNDER
518 : type == MFACE_HLINE_STRIKE_THROUGH
519 ? y - ((gstring->ascent + gstring->descent) / 2)
520 : y - gstring->text_ascent);
522 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
527 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
528 MPLIST_DO (plist, region_list)
530 MDrawMetric *r = MPLIST_VAL (plist), new;
532 if (INTERSECT_RECTANGLE (r, &rect, &new))
533 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
534 new.y + new.height - 1, color);
541 gd_draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
542 MGlyph *g, int x, int y, int width, MDrawRegion region)
544 gdImagePtr img = (gdImagePtr) win;
545 int *colors = g->rface->info;
547 MRealizedFace *rface = g->rface;
548 MFaceBoxProp *box = rface->box;
549 MPlist *region_list = region, *plist;
553 y0 = y - (gstring->text_ascent
554 + rface->box->inner_vmargin + rface->box->width);
555 y1 = y + (gstring->text_descent
556 + rface->box->inner_vmargin + rface->box->width - 1);
560 int height = y1 - y0;
563 if (g->type == GLYPH_BOX)
565 cpy = get_scrach_image (img, width, height);
566 MPLIST_DO (plist, region_list)
568 MDrawMetric *rect = MPLIST_VAL (plist);
569 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
570 rect->x + rect->width, rect->y + rect->height);
572 gd_draw_box (frame, win, gstring, g, 0, y - y0, width, NULL);
573 MPLIST_DO (plist, region_list)
575 MDrawMetric *rect = MPLIST_VAL (plist);
576 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
577 rect->x + rect->width, rect->y + rect->height);
582 if (g->type == GLYPH_BOX)
587 x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
589 x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
591 /* Draw the top side. */
592 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
593 for (i = 0; i < box->width; i++)
594 gdImageLine (img, x0, y0 + i, x1, y0 + i, color);
596 /* Draw the bottom side. */
597 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
598 for (i = 0; i < box->width; i++)
599 gdImageLine (img, x0, y1 - i, x1, y1 - i, color);
601 if (g->left_padding > 0)
603 /* Draw the left side. */
604 color = RESOLVE_COLOR (img, colors[COLOR_BOX_LEFT]);
605 for (i = 0; i < rface->box->width; i++)
606 gdImageLine (img, x0 + i, y0 + i, x0 + i, y1 - i, color);
610 /* Draw the right side. */
611 color = RESOLVE_COLOR (img, colors[COLOR_BOX_RIGHT]);
612 for (i = 0; i < rface->box->width; i++)
613 gdImageLine (img, x1 - i, y0 + i, x1 - i, y1 - i, color);
619 /* Draw the top side. */
620 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
621 for (i = 0; i < box->width; i++)
622 gdImageLine (img, x, y0 + i, x + width - 1, y0 + i, color);
624 /* Draw the bottom side. */
625 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
626 for (i = 0; i < box->width; i++)
627 gdImageLine (img, x, y1 - i, x + width - 1, y1 - i, color);
633 gd_region_from_rect (MDrawMetric *rect)
636 MPlist *plist = mplist ();
638 MSTRUCT_MALLOC (new, MERROR_GD);
640 mplist_add (plist, Mt, new);
641 return (MDrawRegion) plist;
645 gd_union_rect_with_region (MDrawRegion region, MDrawMetric *rect)
647 MPlist *plist = (MPlist *) region;
650 MSTRUCT_MALLOC (r, MERROR_GD);
652 mplist_push (plist, Mt, r);
656 gd_intersect_region (MDrawRegion region1, MDrawRegion region2)
658 MPlist *plist1 = (MPlist *) region1, *p1 = plist1;
659 MPlist *plist2 = (MPlist *) region2;
661 MDrawMetric rect, *rect1, *rect2, *r;
663 while (! MPLIST_TAIL_P (p1))
665 rect1 = mplist_pop (p1);
666 MPLIST_DO (p2, plist2)
668 rect2 = MPLIST_VAL (p2);
669 if (INTERSECT_RECTANGLE (rect1, rect2, &rect))
671 MSTRUCT_MALLOC (r, MERROR_GD);
673 mplist_push (p1, Mt, r);
674 p1 = MPLIST_NEXT (p1);
682 gd_region_add_rect (MDrawRegion region, MDrawMetric *rect)
684 MPlist *plist = (MPlist *) region;
687 MSTRUCT_MALLOC (new, MERROR_GD);
689 mplist_push (plist, Mt, new);
693 gd_region_to_rect (MDrawRegion region, MDrawMetric *rect)
695 MPlist *plist = (MPlist *) region;
696 MDrawMetric *r = MPLIST_VAL (plist);
697 int min_x = r->x, max_x = min_x + r->width;
698 int min_y = r->y, max_y = min_y + r->height;
700 MPLIST_DO (plist, MPLIST_NEXT (plist))
702 r = MPLIST_VAL (plist);
705 if (r->x + r->width > max_x)
706 max_x = r->x + r->width;
709 if (r->y + r->height > max_y)
710 max_y = r->y + r->height;
714 rect->width = max_x - min_x;
715 rect->height =max_y - min_y;
719 gd_free_region (MDrawRegion region)
721 MPlist *plist = (MPlist *) region;
723 MPLIST_DO (plist, plist)
724 free (MPLIST_VAL (plist));
725 M17N_OBJECT_UNREF (region);
729 gd_dump_region (MDrawRegion region)
733 gd_region_to_rect (region, &rect);
734 fprintf (stderr, "(%d %d %d %d)\n", rect.x, rect.y, rect.width, rect.height);
737 static MDeviceDriver gd_driver =
742 gd_free_realized_face,
749 gd_union_rect_with_region,
757 /* Functions to be stored in MDeviceLibraryInterface by dlsym (). */
762 M_rgb = msymbol (" rgb");
764 realized_fontset_list = mplist ();
765 realized_font_list = mplist ();
766 realized_face_list = mplist ();
767 scratch_images[0] = scratch_images[1] = NULL;
769 gd_font_driver.select = mfont__ft_driver.select;
770 gd_font_driver.find_metric = mfont__ft_driver.find_metric;
771 gd_font_driver.has_char = mfont__ft_driver.has_char;
772 gd_font_driver.encode_char = mfont__ft_driver.encode_char;
773 gd_font_driver.list = mfont__ft_driver.list;
784 MPLIST_DO (plist, realized_fontset_list)
785 mfont__free_realized_fontset ((MRealizedFontset *) MPLIST_VAL (plist));
786 M17N_OBJECT_UNREF (realized_fontset_list);
788 MPLIST_DO (plist, realized_face_list)
790 MRealizedFace *rface = MPLIST_VAL (plist);
793 mface__free_realized (rface);
795 M17N_OBJECT_UNREF (realized_face_list);
797 if (MPLIST_VAL (realized_font_list))
798 mfont__free_realized (MPLIST_VAL (realized_font_list));
799 M17N_OBJECT_UNREF (realized_font_list);
801 for (i = 0; i < 2; i++)
802 if (scratch_images[i])
803 gdImageDestroy (scratch_images[i]);
808 device_open (MFrame *frame, MPlist *param)
812 frame->device = NULL;
813 frame->device_type = MDEVICE_SUPPORT_OUTPUT;
814 frame->dpi = (int) mplist_get (param, Mresolution);
817 frame->driver = &gd_driver;
818 frame->font_driver_list = mplist ();
819 mplist_add (frame->font_driver_list, Mfreetype, &gd_font_driver);
820 frame->realized_font_list = realized_font_list;
821 frame->realized_face_list = realized_face_list;
822 frame->realized_fontset_list = realized_fontset_list;
823 face = mface_copy (mface__default);
824 mplist_push (param, Mface, face);
825 M17N_OBJECT_UNREF (face);
829 #else /* not HAVE_GD nor HAVE_FREETYPE */
831 int device_open () { return -1; }
833 #endif /* not HAVE_GD nor HAVE_FREETYPE */
836 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */