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++)
334 int r1, g1, b1, color1;
336 pixel1 = gdImageGetPixel (img, xoff, yoff);
337 r1 = gdImageRed (img, pixel1);
338 g1 = gdImageGreen (img, pixel1);
339 b1 = gdImageBlue (img, pixel1);
340 color1 = ((((r * f + r1 * (7 - f)) / 7) << 16)
341 | (((g * f + g1 * (7 - f)) / 7) << 8)
342 | ((b * f + b1 * (7 - f)) / 7));
343 pixel1 = RESOLVE_COLOR (img, color1);
345 gdImageSetPixel (img, xoff, yoff, pixel1);
349 for (i = 0; i < ft_face->glyph->bitmap.rows;
350 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
352 xoff = x + ft_face->glyph->bitmap_left + from->xoff;
353 for (j = 0; j < width; j++, xoff++)
354 if (bmp[j / 8] & (1 << (7 - (j % 8))))
355 gdImageSetPixel (img, xoff, yoff, pixel);
361 gd_close (MFrame *frame)
366 gd_get_prop (MFrame *frame, MSymbol key)
372 gd_realize_face (MRealizedFace *rface)
375 MFaceHLineProp *hline;
377 MSymbol *props = (MSymbol *) rface->face.property;
379 if (rface != rface->ascii_rface)
381 rface->info = rface->ascii_rface->info;
384 colors = malloc (sizeof (int) * COLOR_MAX);
385 colors[COLOR_NORMAL] = parse_color (props[MFACE_FOREGROUND]);
386 colors[COLOR_INVERSE] = parse_color (props[MFACE_BACKGROUND]);
387 if (rface->face.property[MFACE_VIDEOMODE] == Mreverse)
389 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
390 colors[COLOR_NORMAL] = colors[COLOR_INVERSE];
391 colors[COLOR_INVERSE] = colors[COLOR_HLINE];
393 colors[COLOR_HLINE] = 0;
395 hline = rface->hline;
399 colors[COLOR_HLINE] = parse_color (hline->color);
401 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
408 colors[COLOR_BOX_TOP] = parse_color (box->color_top);
410 colors[COLOR_BOX_TOP] = colors[COLOR_NORMAL];
412 if (box->color_left && box->color_left != box->color_top)
413 colors[COLOR_BOX_LEFT] = parse_color (box->color_left);
415 colors[COLOR_BOX_LEFT] = colors[COLOR_BOX_TOP];
417 if (box->color_bottom && box->color_bottom != box->color_top)
418 colors[COLOR_BOX_BOTTOM] = parse_color (box->color_bottom);
420 colors[COLOR_BOX_BOTTOM] = colors[COLOR_BOX_TOP];
422 if (box->color_right && box->color_right != box->color_bottom)
423 colors[COLOR_BOX_RIGHT] = parse_color (box->color_right);
425 colors[COLOR_BOX_RIGHT] = colors[COLOR_BOX_BOTTOM];
428 rface->info = colors;
432 gd_free_realized_face (MRealizedFace *rface)
438 gd_fill_space (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
440 int x, int y, int width, int height, MDrawRegion region)
442 gdImagePtr img = (gdImagePtr) win;
443 int *colors = rface->info;
444 int color = colors[reverse ? COLOR_NORMAL : COLOR_INVERSE];
445 MPlist *region_list = region, *plist;
447 color = RESOLVE_COLOR (img, color);
449 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
454 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
455 MPLIST_DO (plist, region_list)
457 MDrawMetric *r = MPLIST_VAL (plist), new;
459 if (INTERSECT_RECTANGLE (r, &rect, &new))
460 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
461 new.y + new.height - 1, color);
467 gd_draw_empty_boxes (MDrawWindow win, int x, int y,
468 MGlyphString *gstring, MGlyph *from, MGlyph *to,
469 int reverse, MDrawRegion region)
471 gdImagePtr img = (gdImagePtr) win;
472 int *colors = from->rface->info;
473 int color = colors[reverse ? COLOR_INVERSE : COLOR_NORMAL];
474 MPlist *region_list = region, *plist;
480 color = RESOLVE_COLOR (img, color);
481 y -= gstring->ascent - 1;
482 height = gstring->ascent + gstring->descent - 2;
484 for (; from < to; x += from++->width)
485 gdImageRectangle (img, x, y, x + from->width - 2, y + height - 1, color);
492 for (g = from, width = 0; g < to; width += g++->width);
493 cpy = get_scrach_image (img, width, height);
494 MPLIST_DO (plist, region_list)
496 MDrawMetric *rect = MPLIST_VAL (plist);
497 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
498 rect->x + rect->width, rect->y + rect->height);
500 for (x1 = 0; from < to; x1 += from++->width)
501 gdImageRectangle (cpy, x1, 0, x1 + from->width - 2, height - 1, color);
502 MPLIST_DO (plist, region_list)
504 MDrawMetric *rect = MPLIST_VAL (plist);
505 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
506 rect->x + rect->width, rect->y + rect->height);
513 gd_draw_hline (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
514 MRealizedFace *rface, int reverse,
515 int x, int y, int width, MDrawRegion region)
517 enum MFaceHLineType type = rface->hline->type;
518 int height = rface->hline->width;
519 gdImagePtr img = (gdImagePtr) win;
520 int *colors = rface->info;
521 int color = colors[COLOR_HLINE];
522 MPlist *region_list = region, *plist;
524 color = RESOLVE_COLOR (img, color);
525 y = (type == MFACE_HLINE_BOTTOM
526 ? y + gstring->text_descent - height
527 : type == MFACE_HLINE_UNDER
529 : type == MFACE_HLINE_STRIKE_THROUGH
530 ? y - ((gstring->ascent + gstring->descent) / 2)
531 : y - gstring->text_ascent);
533 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
538 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
539 MPLIST_DO (plist, region_list)
541 MDrawMetric *r = MPLIST_VAL (plist), new;
543 if (INTERSECT_RECTANGLE (r, &rect, &new))
544 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
545 new.y + new.height - 1, color);
552 gd_draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
553 MGlyph *g, int x, int y, int width, MDrawRegion region)
555 gdImagePtr img = (gdImagePtr) win;
556 int *colors = g->rface->info;
558 MRealizedFace *rface = g->rface;
559 MFaceBoxProp *box = rface->box;
560 MPlist *region_list = region, *plist;
564 y0 = y - (gstring->text_ascent
565 + rface->box->inner_vmargin + rface->box->width);
566 y1 = y + (gstring->text_descent
567 + rface->box->inner_vmargin + rface->box->width - 1);
571 int height = y1 - y0;
574 if (g->type == GLYPH_BOX)
576 cpy = get_scrach_image (img, width, height);
577 MPLIST_DO (plist, region_list)
579 MDrawMetric *rect = MPLIST_VAL (plist);
580 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
581 rect->x + rect->width, rect->y + rect->height);
583 gd_draw_box (frame, win, gstring, g, 0, y - y0, width, NULL);
584 MPLIST_DO (plist, region_list)
586 MDrawMetric *rect = MPLIST_VAL (plist);
587 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
588 rect->x + rect->width, rect->y + rect->height);
593 if (g->type == GLYPH_BOX)
598 x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
600 x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
602 /* Draw the top side. */
603 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
604 for (i = 0; i < box->width; i++)
605 gdImageLine (img, x0, y0 + i, x1, y0 + i, color);
607 /* Draw the bottom side. */
608 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
609 for (i = 0; i < box->width; i++)
610 gdImageLine (img, x0, y1 - i, x1, y1 - i, color);
612 if (g->left_padding > 0)
614 /* Draw the left side. */
615 color = RESOLVE_COLOR (img, colors[COLOR_BOX_LEFT]);
616 for (i = 0; i < rface->box->width; i++)
617 gdImageLine (img, x0 + i, y0 + i, x0 + i, y1 - i, color);
621 /* Draw the right side. */
622 color = RESOLVE_COLOR (img, colors[COLOR_BOX_RIGHT]);
623 for (i = 0; i < rface->box->width; i++)
624 gdImageLine (img, x1 - i, y0 + i, x1 - i, y1 - i, color);
630 /* Draw the top side. */
631 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
632 for (i = 0; i < box->width; i++)
633 gdImageLine (img, x, y0 + i, x + width - 1, y0 + i, color);
635 /* Draw the bottom side. */
636 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
637 for (i = 0; i < box->width; i++)
638 gdImageLine (img, x, y1 - i, x + width - 1, y1 - i, color);
644 gd_region_from_rect (MDrawMetric *rect)
647 MPlist *plist = mplist ();
649 MSTRUCT_MALLOC (new, MERROR_GD);
651 mplist_add (plist, Mt, new);
652 return (MDrawRegion) plist;
656 gd_union_rect_with_region (MDrawRegion region, MDrawMetric *rect)
658 MPlist *plist = (MPlist *) region;
661 MSTRUCT_MALLOC (r, MERROR_GD);
663 mplist_push (plist, Mt, r);
667 gd_intersect_region (MDrawRegion region1, MDrawRegion region2)
669 MPlist *plist1 = (MPlist *) region1, *p1 = plist1;
670 MPlist *plist2 = (MPlist *) region2;
672 MDrawMetric rect, *rect1, *rect2, *r;
674 while (! MPLIST_TAIL_P (p1))
676 rect1 = mplist_pop (p1);
677 MPLIST_DO (p2, plist2)
679 rect2 = MPLIST_VAL (p2);
680 if (INTERSECT_RECTANGLE (rect1, rect2, &rect))
682 MSTRUCT_MALLOC (r, MERROR_GD);
684 mplist_push (p1, Mt, r);
685 p1 = MPLIST_NEXT (p1);
693 gd_region_add_rect (MDrawRegion region, MDrawMetric *rect)
695 MPlist *plist = (MPlist *) region;
698 MSTRUCT_MALLOC (new, MERROR_GD);
700 mplist_push (plist, Mt, new);
704 gd_region_to_rect (MDrawRegion region, MDrawMetric *rect)
706 MPlist *plist = (MPlist *) region;
707 MDrawMetric *r = MPLIST_VAL (plist);
708 int min_x = r->x, max_x = min_x + r->width;
709 int min_y = r->y, max_y = min_y + r->height;
711 MPLIST_DO (plist, MPLIST_NEXT (plist))
713 r = MPLIST_VAL (plist);
716 if (r->x + r->width > max_x)
717 max_x = r->x + r->width;
720 if (r->y + r->height > max_y)
721 max_y = r->y + r->height;
725 rect->width = max_x - min_x;
726 rect->height =max_y - min_y;
730 gd_free_region (MDrawRegion region)
732 MPlist *plist = (MPlist *) region;
734 MPLIST_DO (plist, plist)
735 free (MPLIST_VAL (plist));
736 M17N_OBJECT_UNREF (region);
740 gd_dump_region (MDrawRegion region)
744 gd_region_to_rect (region, &rect);
745 fprintf (stderr, "(%d %d %d %d)\n", rect.x, rect.y, rect.width, rect.height);
748 static MDeviceDriver gd_driver =
753 gd_free_realized_face,
760 gd_union_rect_with_region,
768 /* Functions to be stored in MDeviceLibraryInterface by dlsym (). */
773 M_rgb = msymbol (" rgb");
775 realized_fontset_list = mplist ();
776 realized_font_list = mplist ();
777 realized_face_list = mplist ();
778 scratch_images[0] = scratch_images[1] = NULL;
780 gd_font_driver.select = mfont__ft_driver.select;
781 gd_font_driver.find_metric = mfont__ft_driver.find_metric;
782 gd_font_driver.has_char = mfont__ft_driver.has_char;
783 gd_font_driver.encode_char = mfont__ft_driver.encode_char;
784 gd_font_driver.list = mfont__ft_driver.list;
795 MPLIST_DO (plist, realized_fontset_list)
796 mfont__free_realized_fontset ((MRealizedFontset *) MPLIST_VAL (plist));
797 M17N_OBJECT_UNREF (realized_fontset_list);
799 MPLIST_DO (plist, realized_face_list)
801 MRealizedFace *rface = MPLIST_VAL (plist);
804 mface__free_realized (rface);
806 M17N_OBJECT_UNREF (realized_face_list);
808 if (MPLIST_VAL (realized_font_list))
809 mfont__free_realized (MPLIST_VAL (realized_font_list));
810 M17N_OBJECT_UNREF (realized_font_list);
812 for (i = 0; i < 2; i++)
813 if (scratch_images[i])
814 gdImageDestroy (scratch_images[i]);
819 device_open (MFrame *frame, MPlist *param)
823 frame->device = NULL;
824 frame->device_type = MDEVICE_SUPPORT_OUTPUT;
825 frame->dpi = (int) mplist_get (param, Mresolution);
828 frame->driver = &gd_driver;
829 frame->font_driver_list = mplist ();
830 mplist_add (frame->font_driver_list, Mfreetype, &gd_font_driver);
831 frame->realized_font_list = realized_font_list;
832 frame->realized_face_list = realized_face_list;
833 frame->realized_fontset_list = realized_fontset_list;
834 face = mface_copy (mface__default);
835 mplist_push (param, Mface, face);
836 M17N_OBJECT_UNREF (face);
840 #else /* not HAVE_GD nor HAVE_FREETYPE */
842 int device_open () { return -1; }
844 #endif /* not HAVE_GD nor HAVE_FREETYPE */
847 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */