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 };
325 M_rgb = msymbol (" rgb");
327 realized_fontset_list = mplist ();
328 realized_font_list = mplist ();
329 realized_face_list = mplist ();
330 scratch_images[0] = scratch_images[1] = NULL;
332 gd_font_driver.select = mfont__ft_driver.select;
333 gd_font_driver.open = mfont__ft_driver.open;
334 gd_font_driver.find_metric = mfont__ft_driver.find_metric;
335 gd_font_driver.encode_char = mfont__ft_driver.encode_char;
346 MPLIST_DO (plist, realized_fontset_list)
347 mfont__free_realized_fontset ((MRealizedFontset *) MPLIST_VAL (plist));
348 M17N_OBJECT_UNREF (realized_fontset_list);
350 MPLIST_DO (plist, realized_face_list)
352 MRealizedFace *rface = MPLIST_VAL (plist);
355 mface__free_realized (rface);
357 M17N_OBJECT_UNREF (realized_face_list);
359 MPLIST_DO (plist, realized_font_list)
360 mfont__free_realized ((MRealizedFont *) MPLIST_VAL (plist));
361 M17N_OBJECT_UNREF (realized_font_list);
363 for (i = 0; i < 2; i++)
364 if (scratch_images[i])
365 gdImageDestroy (scratch_images[i]);
370 gd_open (MFrame *frame, MPlist *param)
374 frame->device = NULL;
375 frame->device_type = MDEVICE_SUPPORT_OUTPUT;
376 frame->font_driver_list = mplist ();
377 mplist_add (frame->font_driver_list, Mfreetype, &gd_font_driver);
378 frame->realized_font_list = realized_font_list;
379 frame->realized_face_list = realized_face_list;
380 frame->realized_fontset_list = realized_fontset_list;
381 face = mface_copy (mface__default);
382 mplist_push (param, Mface, face);
383 M17N_OBJECT_UNREF (face);
388 gd_close (MFrame *frame)
393 gd_get_prop (MFrame *frame, MSymbol key)
399 gd_realize_face (MRealizedFace *rface)
402 MFaceHLineProp *hline;
404 MSymbol *props = (MSymbol *) rface->face.property;
406 if (rface != rface->ascii_rface)
408 rface->info = rface->ascii_rface->info;
411 colors = malloc (sizeof (int) * COLOR_MAX);
412 colors[COLOR_NORMAL] = parse_color (props[MFACE_FOREGROUND]);
413 colors[COLOR_INVERSE] = parse_color (props[MFACE_BACKGROUND]);
414 if (rface->face.property[MFACE_VIDEOMODE] == Mreverse)
416 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
417 colors[COLOR_NORMAL] = colors[COLOR_INVERSE];
418 colors[COLOR_INVERSE] = colors[COLOR_HLINE];
420 colors[COLOR_HLINE] = 0;
422 hline = rface->hline;
426 colors[COLOR_HLINE] = parse_color (hline->color);
428 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
435 colors[COLOR_BOX_TOP] = parse_color (box->color_top);
437 colors[COLOR_BOX_TOP] = colors[COLOR_NORMAL];
439 if (box->color_left && box->color_left != box->color_top)
440 colors[COLOR_BOX_LEFT] = parse_color (box->color_left);
442 colors[COLOR_BOX_LEFT] = colors[COLOR_BOX_TOP];
444 if (box->color_bottom && box->color_bottom != box->color_top)
445 colors[COLOR_BOX_BOTTOM] = parse_color (box->color_bottom);
447 colors[COLOR_BOX_BOTTOM] = colors[COLOR_BOX_TOP];
449 if (box->color_right && box->color_right != box->color_bottom)
450 colors[COLOR_BOX_RIGHT] = parse_color (box->color_right);
452 colors[COLOR_BOX_RIGHT] = colors[COLOR_BOX_BOTTOM];
455 rface->info = colors;
459 gd_free_realized_face (MRealizedFace *rface)
465 gd_fill_space (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
467 int x, int y, int width, int height, MDrawRegion region)
469 gdImagePtr img = (gdImagePtr) win;
470 int *colors = rface->info;
471 int color = colors[reverse ? COLOR_NORMAL : COLOR_INVERSE];
472 MPlist *region_list = region, *plist;
474 color = RESOLVE_COLOR (img, color);
476 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
481 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
482 MPLIST_DO (plist, region_list)
484 MDrawMetric *r = MPLIST_VAL (plist), new;
486 if (INTERSECT_RECTANGLE (r, &rect, &new))
487 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
488 new.y + new.height - 1, color);
494 gd_draw_empty_boxes (MDrawWindow win, int x, int y,
495 MGlyphString *gstring, MGlyph *from, MGlyph *to,
496 int reverse, MDrawRegion region)
498 gdImagePtr img = (gdImagePtr) win;
499 int *colors = from->rface->info;
500 int color = colors[reverse ? COLOR_INVERSE : COLOR_NORMAL];
501 MPlist *region_list = region, *plist;
507 color = RESOLVE_COLOR (img, color);
508 y -= gstring->ascent - 1;
509 height = gstring->ascent + gstring->descent - 2;
511 for (; from < to; x += from++->width)
512 gdImageRectangle (img, x, y, x + from->width - 2, y + height - 1, color);
519 for (g = from, width = 0; g < to; width += g++->width);
520 cpy = get_scrach_image (img, width, height);
521 MPLIST_DO (plist, region_list)
523 MDrawMetric *rect = MPLIST_VAL (plist);
524 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
525 rect->x + rect->width, rect->y + rect->height);
527 for (x1 = 0; from < to; x1 += from++->width)
528 gdImageRectangle (cpy, x1, 0, x1 + from->width - 2, height - 1, color);
529 MPLIST_DO (plist, region_list)
531 MDrawMetric *rect = MPLIST_VAL (plist);
532 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
533 rect->x + rect->width, rect->y + rect->height);
540 gd_draw_hline (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
541 MRealizedFace *rface, int reverse,
542 int x, int y, int width, MDrawRegion region)
544 enum MFaceHLineType type = rface->hline->type;
545 int height = rface->hline->width;
546 gdImagePtr img = (gdImagePtr) win;
547 int *colors = rface->info;
548 int color = colors[COLOR_HLINE];
549 MPlist *region_list = region, *plist;
551 color = RESOLVE_COLOR (img, color);
552 y = (type == MFACE_HLINE_BOTTOM
553 ? y + gstring->text_descent - height
554 : type == MFACE_HLINE_UNDER
556 : type == MFACE_HLINE_STRIKE_THROUGH
557 ? y - ((gstring->ascent + gstring->descent) / 2)
558 : y - gstring->text_ascent);
560 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
565 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
566 MPLIST_DO (plist, region_list)
568 MDrawMetric *r = MPLIST_VAL (plist), new;
570 if (INTERSECT_RECTANGLE (r, &rect, &new))
571 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
572 new.y + new.height - 1, color);
579 gd_draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
580 MGlyph *g, int x, int y, int width, MDrawRegion region)
582 gdImagePtr img = (gdImagePtr) win;
583 int *colors = g->rface->info;
585 MRealizedFace *rface = g->rface;
586 MFaceBoxProp *box = rface->box;
587 MPlist *region_list = region, *plist;
591 y0 = y - (gstring->text_ascent
592 + rface->box->inner_vmargin + rface->box->width);
593 y1 = y + (gstring->text_descent
594 + rface->box->inner_vmargin + rface->box->width - 1);
598 int height = y1 - y0;
601 if (g->type == GLYPH_BOX)
603 cpy = get_scrach_image (img, width, height);
604 MPLIST_DO (plist, region_list)
606 MDrawMetric *rect = MPLIST_VAL (plist);
607 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
608 rect->x + rect->width, rect->y + rect->height);
610 gd_draw_box (frame, win, gstring, g, 0, y - y0, width, NULL);
611 MPLIST_DO (plist, region_list)
613 MDrawMetric *rect = MPLIST_VAL (plist);
614 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
615 rect->x + rect->width, rect->y + rect->height);
620 if (g->type == GLYPH_BOX)
625 x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
627 x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
629 /* Draw the top side. */
630 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
631 for (i = 0; i < box->width; i++)
632 gdImageLine (img, x0, y0 + i, x1, y0 + i, color);
634 /* Draw the bottom side. */
635 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
636 for (i = 0; i < box->width; i++)
637 gdImageLine (img, x0, y1 - i, x1, y1 - i, color);
639 if (g->left_padding > 0)
641 /* Draw the left side. */
642 color = RESOLVE_COLOR (img, colors[COLOR_BOX_LEFT]);
643 for (i = 0; i < rface->box->width; i++)
644 gdImageLine (img, x0 + i, y0 + i, x0 + i, y1 - i, color);
648 /* Draw the right side. */
649 color = RESOLVE_COLOR (img, colors[COLOR_BOX_RIGHT]);
650 for (i = 0; i < rface->box->width; i++)
651 gdImageLine (img, x1 - i, y0 + i, x1 - i, y1 - i, color);
657 /* Draw the top side. */
658 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
659 for (i = 0; i < box->width; i++)
660 gdImageLine (img, x, y0 + i, x + width - 1, y0 + i, color);
662 /* Draw the bottom side. */
663 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
664 for (i = 0; i < box->width; i++)
665 gdImageLine (img, x, y1 - i, x + width - 1, y1 - i, color);
671 gd_region_from_rect (MDrawMetric *rect)
674 MPlist *plist = mplist ();
676 MSTRUCT_MALLOC (new, MERROR_GD);
678 mplist_add (plist, Mt, new);
679 return (MDrawRegion) plist;
683 gd_union_rect_with_region (MDrawRegion region, MDrawMetric *rect)
685 MPlist *plist = (MPlist *) region;
688 MSTRUCT_MALLOC (r, MERROR_GD);
690 mplist_push (plist, Mt, r);
694 gd_intersect_region (MDrawRegion region1, MDrawRegion region2)
696 MPlist *plist1 = (MPlist *) region1, *p1 = plist1;
697 MPlist *plist2 = (MPlist *) region2;
699 MDrawMetric rect, *rect1, *rect2, *r;
701 while (! MPLIST_TAIL_P (p1))
703 rect1 = mplist_pop (p1);
704 MPLIST_DO (p2, plist2)
706 rect2 = MPLIST_VAL (p2);
707 if (INTERSECT_RECTANGLE (rect1, rect2, &rect))
709 MSTRUCT_MALLOC (r, MERROR_GD);
711 mplist_push (p1, Mt, r);
712 p1 = MPLIST_NEXT (p1);
720 gd_region_add_rect (MDrawRegion region, MDrawMetric *rect)
722 MPlist *plist = (MPlist *) region;
725 MSTRUCT_MALLOC (new, MERROR_GD);
727 mplist_push (plist, Mt, new);
731 gd_region_to_rect (MDrawRegion region, MDrawMetric *rect)
733 MPlist *plist = (MPlist *) region;
734 MDrawMetric *r = MPLIST_VAL (plist);
735 int min_x = r->x, max_x = min_x + r->width;
736 int min_y = r->y, max_y = min_y + r->height;
738 MPLIST_DO (plist, MPLIST_NEXT (plist))
740 r = MPLIST_VAL (plist);
743 if (r->x + r->width > max_x)
744 max_x = r->x + r->width;
747 if (r->y + r->height > max_y)
748 max_y = r->y + r->height;
752 rect->width = max_x - min_x;
753 rect->height =max_y - min_y;
757 gd_free_region (MDrawRegion region)
759 MPlist *plist = (MPlist *) region;
761 MPLIST_DO (plist, plist)
762 free (MPLIST_VAL (plist));
763 M17N_OBJECT_UNREF (region);
767 gd_dump_region (MDrawRegion region)
771 gd_region_to_rect (region, &rect);
772 fprintf (stderr, "(%d %d %d %d)\n", rect.x, rect.y, rect.width, rect.height);
775 static MDeviceDriver gd_driver =
784 gd_free_realized_face,
791 gd_union_rect_with_region,
804 gd_driver.initialized = 0;
805 mplist_put (m17n__device_library_list, Mgd, &gd_driver);
809 #else /* not HAVE_GD nor HAVE_FREETYPE */
817 #endif /* not HAVE_GD nor HAVE_FREETYPE */
820 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */