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++)
331 int alpha = gdAlphaTransparent * (255 - bmp[j]) / 255;
334 pixel1 = gdImageColorResolveAlpha (img, r, g, b, alpha);
340 int r1, g1, b1, color1;
342 pixel1 = gdImageGetPixel (img, xoff, yoff);
343 r1 = gdImageRed (img, pixel1);
344 g1 = gdImageGreen (img, pixel1);
345 b1 = gdImageBlue (img, pixel1);
346 color1 = ((((r * f + r1 * (7 - f)) / 7) << 16)
347 | (((g * f + g1 * (7 - f)) / 7) << 8)
348 | ((b * f + b1 * (7 - f)) / 7));
349 pixel1 = RESOLVE_COLOR (img, color1);
352 gdImageSetPixel (img, xoff, yoff, pixel1);
356 for (i = 0; i < ft_face->glyph->bitmap.rows;
357 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
359 xoff = x + ft_face->glyph->bitmap_left + from->xoff;
360 for (j = 0; j < width; j++, xoff++)
361 if (bmp[j / 8] & (1 << (7 - (j % 8))))
362 gdImageSetPixel (img, xoff, yoff, pixel);
368 gd_close (MFrame *frame)
373 gd_get_prop (MFrame *frame, MSymbol key)
379 gd_realize_face (MRealizedFace *rface)
382 MFaceHLineProp *hline;
384 MSymbol *props = (MSymbol *) rface->face.property;
386 if (rface != rface->ascii_rface)
388 rface->info = rface->ascii_rface->info;
391 colors = malloc (sizeof (int) * COLOR_MAX);
392 colors[COLOR_NORMAL] = parse_color (props[MFACE_FOREGROUND]);
393 colors[COLOR_INVERSE] = parse_color (props[MFACE_BACKGROUND]);
394 if (rface->face.property[MFACE_VIDEOMODE] == Mreverse)
396 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
397 colors[COLOR_NORMAL] = colors[COLOR_INVERSE];
398 colors[COLOR_INVERSE] = colors[COLOR_HLINE];
400 colors[COLOR_HLINE] = 0;
402 hline = rface->hline;
406 colors[COLOR_HLINE] = parse_color (hline->color);
408 colors[COLOR_HLINE] = colors[COLOR_NORMAL];
415 colors[COLOR_BOX_TOP] = parse_color (box->color_top);
417 colors[COLOR_BOX_TOP] = colors[COLOR_NORMAL];
419 if (box->color_left && box->color_left != box->color_top)
420 colors[COLOR_BOX_LEFT] = parse_color (box->color_left);
422 colors[COLOR_BOX_LEFT] = colors[COLOR_BOX_TOP];
424 if (box->color_bottom && box->color_bottom != box->color_top)
425 colors[COLOR_BOX_BOTTOM] = parse_color (box->color_bottom);
427 colors[COLOR_BOX_BOTTOM] = colors[COLOR_BOX_TOP];
429 if (box->color_right && box->color_right != box->color_bottom)
430 colors[COLOR_BOX_RIGHT] = parse_color (box->color_right);
432 colors[COLOR_BOX_RIGHT] = colors[COLOR_BOX_BOTTOM];
435 rface->info = colors;
439 gd_free_realized_face (MRealizedFace *rface)
445 gd_fill_space (MFrame *frame, MDrawWindow win, MRealizedFace *rface,
447 int x, int y, int width, int height, MDrawRegion region)
449 gdImagePtr img = (gdImagePtr) win;
450 int *colors = rface->info;
451 int color = colors[reverse ? COLOR_NORMAL : COLOR_INVERSE];
452 MPlist *region_list = region, *plist;
454 color = RESOLVE_COLOR (img, color);
456 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
461 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
462 MPLIST_DO (plist, region_list)
464 MDrawMetric *r = MPLIST_VAL (plist), new;
466 if (INTERSECT_RECTANGLE (r, &rect, &new))
467 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
468 new.y + new.height - 1, color);
474 gd_draw_empty_boxes (MDrawWindow win, int x, int y,
475 MGlyphString *gstring, MGlyph *from, MGlyph *to,
476 int reverse, MDrawRegion region)
478 gdImagePtr img = (gdImagePtr) win;
479 int *colors = from->rface->info;
480 int color = colors[reverse ? COLOR_INVERSE : COLOR_NORMAL];
481 MPlist *region_list = region, *plist;
487 color = RESOLVE_COLOR (img, color);
488 y -= gstring->ascent - 1;
489 height = gstring->ascent + gstring->descent - 2;
491 for (; from < to; x += from++->width)
492 gdImageRectangle (img, x, y, x + from->width - 2, y + height - 1, color);
499 for (g = from, width = 0; g < to; width += g++->width);
500 cpy = get_scrach_image (img, width, height);
501 MPLIST_DO (plist, region_list)
503 MDrawMetric *rect = MPLIST_VAL (plist);
504 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
505 rect->x + rect->width, rect->y + rect->height);
507 for (x1 = 0; from < to; x1 += from++->width)
508 gdImageRectangle (cpy, x1, 0, x1 + from->width - 2, height - 1, color);
509 MPLIST_DO (plist, region_list)
511 MDrawMetric *rect = MPLIST_VAL (plist);
512 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
513 rect->x + rect->width, rect->y + rect->height);
520 gd_draw_hline (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
521 MRealizedFace *rface, int reverse,
522 int x, int y, int width, MDrawRegion region)
524 enum MFaceHLineType type = rface->hline->type;
525 int height = rface->hline->width;
526 gdImagePtr img = (gdImagePtr) win;
527 int *colors = rface->info;
528 int color = colors[COLOR_HLINE];
529 MPlist *region_list = region, *plist;
531 color = RESOLVE_COLOR (img, color);
532 y = (type == MFACE_HLINE_BOTTOM
533 ? y + gstring->text_descent - height
534 : type == MFACE_HLINE_UNDER
536 : type == MFACE_HLINE_STRIKE_THROUGH
537 ? y - ((gstring->ascent + gstring->descent) / 2)
538 : y - gstring->text_ascent);
540 gdImageFilledRectangle (img, x, y, x + width - 1, y + height - 1, color);
545 rect.x = x, rect.y = y, rect.width = width, rect.height = height;
546 MPLIST_DO (plist, region_list)
548 MDrawMetric *r = MPLIST_VAL (plist), new;
550 if (INTERSECT_RECTANGLE (r, &rect, &new))
551 gdImageFilledRectangle (img, new.x, new.y, new.x + new.width - 1,
552 new.y + new.height - 1, color);
559 gd_draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
560 MGlyph *g, int x, int y, int width, MDrawRegion region)
562 gdImagePtr img = (gdImagePtr) win;
563 int *colors = g->rface->info;
565 MRealizedFace *rface = g->rface;
566 MFaceBoxProp *box = rface->box;
567 MPlist *region_list = region, *plist;
571 y0 = y - (gstring->text_ascent
572 + rface->box->inner_vmargin + rface->box->width);
573 y1 = y + (gstring->text_descent
574 + rface->box->inner_vmargin + rface->box->width - 1);
578 int height = y1 - y0;
581 if (g->type == GLYPH_BOX)
583 cpy = get_scrach_image (img, width, height);
584 MPLIST_DO (plist, region_list)
586 MDrawMetric *rect = MPLIST_VAL (plist);
587 gdImageCopy (cpy, img, rect->x - x, rect->y - y, rect->x, rect->y,
588 rect->x + rect->width, rect->y + rect->height);
590 gd_draw_box (frame, win, gstring, g, 0, y - y0, width, NULL);
591 MPLIST_DO (plist, region_list)
593 MDrawMetric *rect = MPLIST_VAL (plist);
594 gdImageCopy (img, cpy, rect->x, rect->y, rect->x - x, rect->y - y,
595 rect->x + rect->width, rect->y + rect->height);
600 if (g->type == GLYPH_BOX)
605 x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
607 x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
609 /* Draw the top side. */
610 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
611 for (i = 0; i < box->width; i++)
612 gdImageLine (img, x0, y0 + i, x1, y0 + i, color);
614 /* Draw the bottom side. */
615 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
616 for (i = 0; i < box->width; i++)
617 gdImageLine (img, x0, y1 - i, x1, y1 - i, color);
619 if (g->left_padding > 0)
621 /* Draw the left side. */
622 color = RESOLVE_COLOR (img, colors[COLOR_BOX_LEFT]);
623 for (i = 0; i < rface->box->width; i++)
624 gdImageLine (img, x0 + i, y0 + i, x0 + i, y1 - i, color);
628 /* Draw the right side. */
629 color = RESOLVE_COLOR (img, colors[COLOR_BOX_RIGHT]);
630 for (i = 0; i < rface->box->width; i++)
631 gdImageLine (img, x1 - i, y0 + i, x1 - i, y1 - i, color);
637 /* Draw the top side. */
638 color = RESOLVE_COLOR (img, colors[COLOR_BOX_TOP]);
639 for (i = 0; i < box->width; i++)
640 gdImageLine (img, x, y0 + i, x + width - 1, y0 + i, color);
642 /* Draw the bottom side. */
643 color = RESOLVE_COLOR (img, colors[COLOR_BOX_BOTTOM]);
644 for (i = 0; i < box->width; i++)
645 gdImageLine (img, x, y1 - i, x + width - 1, y1 - i, color);
651 gd_region_from_rect (MDrawMetric *rect)
654 MPlist *plist = mplist ();
656 MSTRUCT_MALLOC (new, MERROR_GD);
658 mplist_add (plist, Mt, new);
659 return (MDrawRegion) plist;
663 gd_union_rect_with_region (MDrawRegion region, MDrawMetric *rect)
665 MPlist *plist = (MPlist *) region;
668 MSTRUCT_MALLOC (r, MERROR_GD);
670 mplist_push (plist, Mt, r);
674 gd_intersect_region (MDrawRegion region1, MDrawRegion region2)
676 MPlist *plist1 = (MPlist *) region1, *p1 = plist1;
677 MPlist *plist2 = (MPlist *) region2;
679 MDrawMetric rect, *rect1, *rect2, *r;
681 while (! MPLIST_TAIL_P (p1))
683 rect1 = mplist_pop (p1);
684 MPLIST_DO (p2, plist2)
686 rect2 = MPLIST_VAL (p2);
687 if (INTERSECT_RECTANGLE (rect1, rect2, &rect))
689 MSTRUCT_MALLOC (r, MERROR_GD);
691 mplist_push (p1, Mt, r);
692 p1 = MPLIST_NEXT (p1);
700 gd_region_add_rect (MDrawRegion region, MDrawMetric *rect)
702 MPlist *plist = (MPlist *) region;
705 MSTRUCT_MALLOC (new, MERROR_GD);
707 mplist_push (plist, Mt, new);
711 gd_region_to_rect (MDrawRegion region, MDrawMetric *rect)
713 MPlist *plist = (MPlist *) region;
714 MDrawMetric *r = MPLIST_VAL (plist);
715 int min_x = r->x, max_x = min_x + r->width;
716 int min_y = r->y, max_y = min_y + r->height;
718 MPLIST_DO (plist, MPLIST_NEXT (plist))
720 r = MPLIST_VAL (plist);
723 if (r->x + r->width > max_x)
724 max_x = r->x + r->width;
727 if (r->y + r->height > max_y)
728 max_y = r->y + r->height;
732 rect->width = max_x - min_x;
733 rect->height =max_y - min_y;
737 gd_free_region (MDrawRegion region)
739 MPlist *plist = (MPlist *) region;
741 MPLIST_DO (plist, plist)
742 free (MPLIST_VAL (plist));
743 M17N_OBJECT_UNREF (region);
747 gd_dump_region (MDrawRegion region)
751 gd_region_to_rect (region, &rect);
752 fprintf (stderr, "(%d %d %d %d)\n", rect.x, rect.y, rect.width, rect.height);
755 static MDeviceDriver gd_driver =
760 gd_free_realized_face,
767 gd_union_rect_with_region,
775 /* Functions to be stored in MDeviceLibraryInterface by dlsym (). */
780 M_rgb = msymbol (" rgb");
782 realized_fontset_list = mplist ();
783 realized_font_list = mplist ();
784 realized_face_list = mplist ();
785 scratch_images[0] = scratch_images[1] = NULL;
787 gd_font_driver.select = mfont__ft_driver.select;
788 gd_font_driver.find_metric = mfont__ft_driver.find_metric;
789 gd_font_driver.has_char = mfont__ft_driver.has_char;
790 gd_font_driver.encode_char = mfont__ft_driver.encode_char;
791 gd_font_driver.list = mfont__ft_driver.list;
802 MPLIST_DO (plist, realized_fontset_list)
803 mfont__free_realized_fontset ((MRealizedFontset *) MPLIST_VAL (plist));
804 M17N_OBJECT_UNREF (realized_fontset_list);
806 MPLIST_DO (plist, realized_face_list)
808 MRealizedFace *rface = MPLIST_VAL (plist);
811 mface__free_realized (rface);
813 M17N_OBJECT_UNREF (realized_face_list);
815 if (MPLIST_VAL (realized_font_list))
816 mfont__free_realized (MPLIST_VAL (realized_font_list));
817 M17N_OBJECT_UNREF (realized_font_list);
819 for (i = 0; i < 2; i++)
820 if (scratch_images[i])
821 gdImageDestroy (scratch_images[i]);
826 device_open (MFrame *frame, MPlist *param)
830 frame->device = NULL;
831 frame->device_type = MDEVICE_SUPPORT_OUTPUT;
832 frame->dpi = (int) mplist_get (param, Mresolution);
835 frame->driver = &gd_driver;
836 frame->font_driver_list = mplist ();
837 mplist_add (frame->font_driver_list, Mfreetype, &gd_font_driver);
838 frame->realized_font_list = realized_font_list;
839 frame->realized_face_list = realized_face_list;
840 frame->realized_fontset_list = realized_fontset_list;
841 face = mface_copy (mface__default);
842 mplist_push (param, Mface, face);
843 M17N_OBJECT_UNREF (face);
847 #else /* not HAVE_GD nor HAVE_FREETYPE */
849 int device_open () { return -1; }
851 #endif /* not HAVE_GD nor HAVE_FREETYPE */
854 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */