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, \
228 gd_render (MDrawWindow win, int x, int y,
229 MGlyphString *gstring, MGlyph *from, MGlyph *to,
230 int reverse, MDrawRegion region)
232 gdImagePtr img = (gdImagePtr) win;
235 MRealizedFace *rface = from->rface;
236 FT_Int32 load_flags = FT_LOAD_RENDER;
241 pixel = RESOLVE_COLOR (img, color);
246 /* It is assured that the all glyphs in the current range use the
247 same realized face. */
248 ft_info = (MFTInfo *) rface->rfont->info;
249 ft_face = ft_info->ft_face;
250 color = ((int *) rface->info)[reverse ? COLOR_INVERSE : COLOR_NORMAL];
251 pixel = RESOLVE_COLOR (img, color);
253 if (gstring->anti_alias)
254 r = color >> 16, g = (color >> 8) & 0xFF, b = color & 0xFF;
257 #ifdef FT_LOAD_TARGET_MONO
258 load_flags |= FT_LOAD_TARGET_MONO;
260 load_flags |= FT_LOAD_MONOCHROME;
264 for (; from < to; x += from++->width)
270 FT_Load_Glyph (ft_face, (FT_UInt) from->code, load_flags);
271 yoff = y - ft_face->glyph->bitmap_top + from->yoff;
272 bmp = ft_face->glyph->bitmap.buffer;
273 width = ft_face->glyph->bitmap.width;
274 pitch = ft_face->glyph->bitmap.pitch;
275 if (! gstring->anti_alias)
280 if (gstring->anti_alias)
281 for (i = 0; i < ft_face->glyph->bitmap.rows;
282 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
284 xoff = x + ft_face->glyph->bitmap_left + from->xoff;
285 for (j = 0; j < width; j++, xoff++)
293 int r1, g1, b1, color1;
295 pixel1 = gdImageGetPixel (img, xoff, yoff);
296 r1 = gdImageRed (img, pixel1);
297 g1 = gdImageGreen (img, pixel1);
298 b1 = gdImageBlue (img, pixel1);
299 color1 = ((((r * f + r1 * (7 - f)) / 7) << 16)
300 | (((g * f + g1 * (7 - f)) / 7) << 8)
301 | ((b * f + b1 * (7 - f)) / 7));
302 pixel1 = RESOLVE_COLOR (img, color1);
304 gdImageSetPixel (img, xoff, yoff, pixel1);
308 for (i = 0; i < ft_face->glyph->bitmap.rows;
309 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
311 xoff = x + ft_face->glyph->bitmap_left + from->xoff;
312 for (j = 0; j < width; j++, xoff++)
313 if (bmp[j / 8] & (1 << (7 - (j % 8))))
314 gdImageSetPixel (img, xoff, yoff, pixel);
319 static MFontDriver gd_font_driver =
320 { NULL, NULL, NULL, NULL, gd_render };
323 gd_close (MFrame *frame)
328 gd_get_prop (MFrame *frame, MSymbol key)
334 gd_realize_face (MRealizedFace *rface)
337 MFaceHLineProp *hline;
339 MSymbol *props = (MSymbol *) rface->face.property;
341 if (rface != rface->ascii_rface)
343 rface->info = rface->ascii_rface->info;
346 colors = malloc (sizeof (int) * COLOR_MAX);
347 colors[COLOR_NORMAL] = parse_color (props[MFACE_FOREGROUND]);
348 colors[COLOR_INVERSE] = parse_color (props[MFACE_BACKGROUND]);
349 if (rface->face.property[MFACE_VIDEOMODE] == Mreverse)
351 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
352 colors[COLOR_NORMAL] = colors[COLOR_INVERSE];
353 colors[COLOR_INVERSE] = colors[COLOR_HLINE];
355 colors[COLOR_HLINE] = 0;
357 hline = rface->hline;
361 colors[COLOR_HLINE] = parse_color (hline->color);
363 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
370 colors[COLOR_BOX_TOP] = parse_color (box->color_top);
372 colors[COLOR_BOX_TOP] = colors[COLOR_NORMAL];
374 if (box->color_left && box->color_left != box->color_top)
375 colors[COLOR_BOX_LEFT] = parse_color (box->color_left);
377 colors[COLOR_BOX_LEFT] = colors[COLOR_BOX_TOP];
379 if (box->color_bottom && box->color_bottom != box->color_top)
380 colors[COLOR_BOX_BOTTOM] = parse_color (box->color_bottom);
382 colors[COLOR_BOX_BOTTOM] = colors[COLOR_BOX_TOP];
384 if (box->color_right && box->color_right != box->color_bottom)
385 colors[COLOR_BOX_RIGHT] = parse_color (box->color_right);
387 colors[COLOR_BOX_RIGHT] = colors[COLOR_BOX_BOTTOM];
390 rface->info = colors;
394 gd_free_realized_face (MRealizedFace *rface)
400 gd_fill_space (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
402 int x, int y, int width, int height, MDrawRegion region)
404 gdImagePtr img = (gdImagePtr) win;
405 int *colors = rface->info;
406 int color = colors[reverse ? COLOR_NORMAL : COLOR_INVERSE];
407 MPlist *region_list = region, *plist;
409 color = RESOLVE_COLOR (img, color);
411 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
416 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
417 MPLIST_DO (plist, region_list)
419 MDrawMetric *r = MPLIST_VAL (plist), new;
421 if (INTERSECT_RECTANGLE (r, &rect, &new))
422 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
423 new.y + new.height - 1, color);
429 gd_draw_empty_boxes (MDrawWindow win, int x, int y,
430 MGlyphString *gstring, MGlyph *from, MGlyph *to,
431 int reverse, MDrawRegion region)
433 gdImagePtr img = (gdImagePtr) win;
434 int *colors = from->rface->info;
435 int color = colors[reverse ? COLOR_INVERSE : COLOR_NORMAL];
436 MPlist *region_list = region, *plist;
442 color = RESOLVE_COLOR (img, color);
443 y -= gstring->ascent - 1;
444 height = gstring->ascent + gstring->descent - 2;
446 for (; from < to; x += from++->width)
447 gdImageRectangle (img, x, y, x + from->width - 2, y + height - 1, color);
454 for (g = from, width = 0; g < to; width += g++->width);
455 cpy = get_scrach_image (img, width, height);
456 MPLIST_DO (plist, region_list)
458 MDrawMetric *rect = MPLIST_VAL (plist);
459 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
460 rect->x + rect->width, rect->y + rect->height);
462 for (x1 = 0; from < to; x1 += from++->width)
463 gdImageRectangle (cpy, x1, 0, x1 + from->width - 2, height - 1, color);
464 MPLIST_DO (plist, region_list)
466 MDrawMetric *rect = MPLIST_VAL (plist);
467 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
468 rect->x + rect->width, rect->y + rect->height);
475 gd_draw_hline (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
476 MRealizedFace *rface, int reverse,
477 int x, int y, int width, MDrawRegion region)
479 enum MFaceHLineType type = rface->hline->type;
480 int height = rface->hline->width;
481 gdImagePtr img = (gdImagePtr) win;
482 int *colors = rface->info;
483 int color = colors[COLOR_HLINE];
484 MPlist *region_list = region, *plist;
486 color = RESOLVE_COLOR (img, color);
487 y = (type == MFACE_HLINE_BOTTOM
488 ? y + gstring->text_descent - height
489 : type == MFACE_HLINE_UNDER
491 : type == MFACE_HLINE_STRIKE_THROUGH
492 ? y - ((gstring->ascent + gstring->descent) / 2)
493 : y - gstring->text_ascent);
495 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
500 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
501 MPLIST_DO (plist, region_list)
503 MDrawMetric *r = MPLIST_VAL (plist), new;
505 if (INTERSECT_RECTANGLE (r, &rect, &new))
506 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
507 new.y + new.height - 1, color);
514 gd_draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
515 MGlyph *g, int x, int y, int width, MDrawRegion region)
517 gdImagePtr img = (gdImagePtr) win;
518 int *colors = g->rface->info;
520 MRealizedFace *rface = g->rface;
521 MFaceBoxProp *box = rface->box;
522 MPlist *region_list = region, *plist;
526 y0 = y - (gstring->text_ascent
527 + rface->box->inner_vmargin + rface->box->width);
528 y1 = y + (gstring->text_descent
529 + rface->box->inner_vmargin + rface->box->width - 1);
533 int height = y1 - y0;
536 if (g->type == GLYPH_BOX)
538 cpy = get_scrach_image (img, width, height);
539 MPLIST_DO (plist, region_list)
541 MDrawMetric *rect = MPLIST_VAL (plist);
542 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
543 rect->x + rect->width, rect->y + rect->height);
545 gd_draw_box (frame, win, gstring, g, 0, y - y0, width, NULL);
546 MPLIST_DO (plist, region_list)
548 MDrawMetric *rect = MPLIST_VAL (plist);
549 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
550 rect->x + rect->width, rect->y + rect->height);
555 if (g->type == GLYPH_BOX)
560 x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
562 x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
564 /* Draw the top side. */
565 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
566 for (i = 0; i < box->width; i++)
567 gdImageLine (img, x0, y0 + i, x1, y0 + i, color);
569 /* Draw the bottom side. */
570 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
571 for (i = 0; i < box->width; i++)
572 gdImageLine (img, x0, y1 - i, x1, y1 - i, color);
574 if (g->left_padding > 0)
576 /* Draw the left side. */
577 color = RESOLVE_COLOR (img, colors[COLOR_BOX_LEFT]);
578 for (i = 0; i < rface->box->width; i++)
579 gdImageLine (img, x0 + i, y0 + i, x0 + i, y1 - i, color);
583 /* Draw the right side. */
584 color = RESOLVE_COLOR (img, colors[COLOR_BOX_RIGHT]);
585 for (i = 0; i < rface->box->width; i++)
586 gdImageLine (img, x1 - i, y0 + i, x1 - i, y1 - i, color);
592 /* Draw the top side. */
593 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
594 for (i = 0; i < box->width; i++)
595 gdImageLine (img, x, y0 + i, x + width - 1, y0 + i, color);
597 /* Draw the bottom side. */
598 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
599 for (i = 0; i < box->width; i++)
600 gdImageLine (img, x, y1 - i, x + width - 1, y1 - i, color);
606 gd_region_from_rect (MDrawMetric *rect)
609 MPlist *plist = mplist ();
611 MSTRUCT_MALLOC (new, MERROR_GD);
613 mplist_add (plist, Mt, new);
614 return (MDrawRegion) plist;
618 gd_union_rect_with_region (MDrawRegion region, MDrawMetric *rect)
620 MPlist *plist = (MPlist *) region;
623 MSTRUCT_MALLOC (r, MERROR_GD);
625 mplist_push (plist, Mt, r);
629 gd_intersect_region (MDrawRegion region1, MDrawRegion region2)
631 MPlist *plist1 = (MPlist *) region1, *p1 = plist1;
632 MPlist *plist2 = (MPlist *) region2;
634 MDrawMetric rect, *rect1, *rect2, *r;
636 while (! MPLIST_TAIL_P (p1))
638 rect1 = mplist_pop (p1);
639 MPLIST_DO (p2, plist2)
641 rect2 = MPLIST_VAL (p2);
642 if (INTERSECT_RECTANGLE (rect1, rect2, &rect))
644 MSTRUCT_MALLOC (r, MERROR_GD);
646 mplist_push (p1, Mt, r);
647 p1 = MPLIST_NEXT (p1);
655 gd_region_add_rect (MDrawRegion region, MDrawMetric *rect)
657 MPlist *plist = (MPlist *) region;
660 MSTRUCT_MALLOC (new, MERROR_GD);
662 mplist_push (plist, Mt, new);
666 gd_region_to_rect (MDrawRegion region, MDrawMetric *rect)
668 MPlist *plist = (MPlist *) region;
669 MDrawMetric *r = MPLIST_VAL (plist);
670 int min_x = r->x, max_x = min_x + r->width;
671 int min_y = r->y, max_y = min_y + r->height;
673 MPLIST_DO (plist, MPLIST_NEXT (plist))
675 r = MPLIST_VAL (plist);
678 if (r->x + r->width > max_x)
679 max_x = r->x + r->width;
682 if (r->y + r->height > max_y)
683 max_y = r->y + r->height;
687 rect->width = max_x - min_x;
688 rect->height =max_y - min_y;
692 gd_free_region (MDrawRegion region)
694 MPlist *plist = (MPlist *) region;
696 MPLIST_DO (plist, plist)
697 free (MPLIST_VAL (plist));
698 M17N_OBJECT_UNREF (region);
702 gd_dump_region (MDrawRegion region)
706 gd_region_to_rect (region, &rect);
707 fprintf (stderr, "(%d %d %d %d)\n", rect.x, rect.y, rect.width, rect.height);
710 static MDeviceDriver gd_driver =
715 gd_free_realized_face,
722 gd_union_rect_with_region,
730 /* Functions to be stored in MDeviceLibraryInterface by dlsym (). */
735 M_rgb = msymbol (" rgb");
737 realized_fontset_list = mplist ();
738 realized_font_list = mplist ();
739 realized_face_list = mplist ();
740 scratch_images[0] = scratch_images[1] = NULL;
742 gd_font_driver.select = mfont__ft_driver.select;
743 gd_font_driver.open = mfont__ft_driver.open;
744 gd_font_driver.find_metric = mfont__ft_driver.find_metric;
745 gd_font_driver.encode_char = mfont__ft_driver.encode_char;
756 MPLIST_DO (plist, realized_fontset_list)
757 mfont__free_realized_fontset ((MRealizedFontset *) MPLIST_VAL (plist));
758 M17N_OBJECT_UNREF (realized_fontset_list);
760 MPLIST_DO (plist, realized_face_list)
762 MRealizedFace *rface = MPLIST_VAL (plist);
765 mface__free_realized (rface);
767 M17N_OBJECT_UNREF (realized_face_list);
769 MPLIST_DO (plist, realized_font_list)
770 mfont__free_realized ((MRealizedFont *) MPLIST_VAL (plist));
771 M17N_OBJECT_UNREF (realized_font_list);
773 for (i = 0; i < 2; i++)
774 if (scratch_images[i])
775 gdImageDestroy (scratch_images[i]);
780 device_open (MFrame *frame, MPlist *param)
784 frame->device = NULL;
785 frame->device_type = MDEVICE_SUPPORT_OUTPUT;
786 frame->driver = &gd_driver;
787 frame->font_driver_list = mplist ();
788 mplist_add (frame->font_driver_list, Mfreetype, &gd_font_driver);
789 frame->realized_font_list = realized_font_list;
790 frame->realized_face_list = realized_face_list;
791 frame->realized_fontset_list = realized_fontset_list;
792 face = mface_copy (mface__default);
793 mplist_push (param, Mface, face);
794 M17N_OBJECT_UNREF (face);
798 #endif /* not HAVE_GD nor HAVE_FREETYPE */
801 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */