X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/29adb7b55e89881d05165ddacd28144d1f878355..5adc433ec64ffbd82f809de77fceb294fc8a93c2:/src/ftxfont.c diff --git a/src/ftxfont.c b/src/ftxfont.c index 831b75c4d4..1f97a94e94 100644 --- a/src/ftxfont.c +++ b/src/ftxfont.c @@ -1,15 +1,15 @@ /* ftxfont.c -- FreeType font driver on X (without using XFT). - Copyright (C) 2006 Free Software Foundation, Inc. - Copyright (C) 2006 + Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 2006, 2007, 2008, 2009 National Institute of Advanced Industrial Science and Technology (AIST) Registration Number H13PRO009 This file is part of GNU Emacs. -GNU Emacs is free software; you can redistribute it and/or modify +GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -17,12 +17,11 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +along with GNU Emacs. If not, see . */ #include #include +#include #include #include "lisp.h" @@ -40,43 +39,87 @@ Boston, MA 02110-1301, USA. */ static Lisp_Object Qftx; /* Prototypes for helper function. */ -static int ftxfont_create_gcs P_ ((FRAME_PTR, GC *, - unsigned long, unsigned long)); -static int ftxfont_draw_bitmap P_ ((FRAME_PTR, GC *, struct font *, unsigned, - int, int, XPoint *, int, int *n)); +static GC *ftxfont_get_gcs P_ ((FRAME_PTR, unsigned long, unsigned long)); +static int ftxfont_draw_bitmap P_ ((FRAME_PTR, GC, GC *, struct font *, + unsigned, int, int, XPoint *, int, int *, + int)); static void ftxfont_draw_backgrond P_ ((FRAME_PTR, struct font *, GC, int, int, int)); -static Font ftxfont_default_fid P_ ((FRAME_PTR)); -/* Create 6 GCs for antialiasing by interpolating colors FOREGROUND - and BACKGROUND. GCS[0] is closest to BACKGROUND, and GCS[5] is - closest to FOREGROUND. */ +struct ftxfont_frame_data +{ + /* Background and foreground colors. */ + XColor colors[2]; + /* GCs interporationg the above colors. gcs[0] is for a color + closest to BACKGROUND, and gcs[5] is for a color closest to + FOREGROUND. */ + GC gcs[6]; + struct ftxfont_frame_data *next; +}; -static int -ftxfont_create_gcs (f, gcs, foreground, background) + +/* Return an array of 6 GCs for antialiasing. */ + +static GC * +ftxfont_get_gcs (f, foreground, background) FRAME_PTR f; - GC *gcs; unsigned long foreground, background; { - XColor colors[3]; + XColor color; XGCValues xgcv; int i; + struct ftxfont_frame_data *data = font_get_frame_data (f, &ftxfont_driver); + struct ftxfont_frame_data *prev = NULL, *this = NULL, *new; - colors[0].pixel = foreground; - colors[1].pixel = background; + if (data) + { + for (this = data; this; prev = this, this = this->next) + { + if (this->colors[0].pixel < background) + continue; + if (this->colors[0].pixel > background) + break; + if (this->colors[1].pixel < foreground) + continue; + if (this->colors[1].pixel > foreground) + break; + return this->gcs; + } + } + + new = malloc (sizeof (struct ftxfont_frame_data)); + if (! new) + return NULL; + new->next = this; + if (prev) + { + prev->next = new; + } + else if (font_put_frame_data (f, &ftxfont_driver, new) < 0) + { + free (new); + return NULL; + } + + new->colors[0].pixel = background; + new->colors[1].pixel = foreground; BLOCK_INPUT; - XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, 2); + XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), new->colors, 2); for (i = 1; i < 7; i++) { - colors[2].red = (colors[0].red * i + colors[1].red * (8 - i)) / 8; - colors[2].green = (colors[0].green * i + colors[1].green * (8 - i)) / 8; - colors[2].blue = (colors[0].blue * i + colors[1].blue * (8 - i)) / 8; - if (! x_alloc_nearest_color (f, FRAME_X_COLORMAP (f), &colors[2])) + /* Interpolate colors linearly. Any better algorithm? */ + color.red + = (new->colors[1].red * i + new->colors[0].red * (8 - i)) / 8; + color.green + = (new->colors[1].green * i + new->colors[0].green * (8 - i)) / 8; + color.blue + = (new->colors[1].blue * i + new->colors[0].blue * (8 - i)) / 8; + if (! x_alloc_nearest_color (f, FRAME_X_COLORMAP (f), &color)) break; - xgcv.foreground = colors[2].pixel; - gcs[i - 1] = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - GCForeground, &xgcv); + xgcv.foreground = color.pixel; + new->gcs[i - 1] = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + GCForeground, &xgcv); } UNBLOCK_INPUT; @@ -84,22 +127,28 @@ ftxfont_create_gcs (f, gcs, foreground, background) { BLOCK_INPUT; for (i--; i >= 0; i--) - XFreeGC (FRAME_X_DISPLAY (f), gcs[i]); + XFreeGC (FRAME_X_DISPLAY (f), new->gcs[i]); UNBLOCK_INPUT; - return -1; + if (prev) + prev->next = new->next; + else if (data) + font_put_frame_data (f, &ftxfont_driver, new->next); + free (new); + return NULL; } - return 0; + return new->gcs; } static int -ftxfont_draw_bitmap (f, gc, font, code, x, y, p, size, n) +ftxfont_draw_bitmap (f, gc_fore, gcs, font, code, x, y, p, size, n, flush) FRAME_PTR f; - GC *gc; + GC gc_fore, *gcs; struct font *font; unsigned code; int x, y; XPoint *p; int size, *n; + int flush; { struct font_bitmap bitmap; unsigned char *b; @@ -107,29 +156,38 @@ ftxfont_draw_bitmap (f, gc, font, code, x, y, p, size, n) if (ftfont_driver.get_bitmap (font, code, &bitmap, size > 0x100 ? 1 : 8) < 0) return 0; - for (i = 0, b = bitmap.buffer; i < bitmap.rows; - i++, b += bitmap.pitch) + if (size > 0x100) { - if (size > 0x100) + for (i = 0, b = bitmap.buffer; i < bitmap.rows; + i++, b += bitmap.pitch) { for (j = 0; j < bitmap.width; j++) if (b[j / 8] & (1 << (7 - (j % 8)))) { p[n[0]].x = x + bitmap.left + j; p[n[0]].y = y - bitmap.top + i; - if (++n[0] == 0x400) + if (++n[0] == size) { XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - gc[0], p, size, CoordModeOrigin); + gc_fore, p, size, CoordModeOrigin); n[0] = 0; } } } - else + if (flush && n[0] > 0) + XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + gc_fore, p, n[0], CoordModeOrigin); + } + else + { + for (i = 0, b = bitmap.buffer; i < bitmap.rows; + i++, b += bitmap.pitch) { for (j = 0; j < bitmap.width; j++) { - int idx = (b[j] >> 5) - 1; + int idx = (bitmap.bits_per_pixel == 1 + ? ((b[j / 8] & (1 << (7 - (j % 8)))) ? 6 : -1) + : (b[j] >> 5) - 1); if (idx >= 0) { @@ -137,15 +195,26 @@ ftxfont_draw_bitmap (f, gc, font, code, x, y, p, size, n) pp[n[idx]].x = x + bitmap.left + j; pp[n[idx]].y = y - bitmap.top + i; - if (++(n[idx]) == 0x100) + if (++(n[idx]) == size) { XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - gc[idx], pp, size, CoordModeOrigin); + idx == 6 ? gc_fore : gcs[idx], pp, size, + CoordModeOrigin); n[idx] = 0; } } } } + if (flush) + { + for (i = 0; i < 6; i++) + if (n[i] > 0) + XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + gcs[i], p + 0x100 * i, n[i], CoordModeOrigin); + if (n[6] > 0) + XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + gc_fore, p + 0x600, n[6], CoordModeOrigin); + } } if (ftfont_driver.free_bitmap) @@ -167,41 +236,15 @@ ftxfont_draw_backgrond (f, font, gc, x, y, width) GCForeground | GCBackground, &xgcv); XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.background); XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc, - x, y - font->ascent, width, y + font->descent); + x, y - FONT_BASE (font), width, FONT_HEIGHT (font)); XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.foreground); } -/* Return the default Font ID on frame F. */ - -static Font -ftxfont_default_fid (f) - FRAME_PTR f; -{ - static int fid_known; - static Font fid; - - if (! fid_known) - { - fid = XLoadFont (FRAME_X_DISPLAY (f), "fixed"); - if (! fid) - { - fid = XLoadFont (FRAME_X_DISPLAY (f), "*"); - if (! fid) - abort (); - } - fid_known = 1; - } - return fid; -} - /* Prototypes for font-driver methods. */ static Lisp_Object ftxfont_list P_ ((Lisp_Object, Lisp_Object)); static Lisp_Object ftxfont_match P_ ((Lisp_Object, Lisp_Object)); -static struct font *ftxfont_open P_ ((FRAME_PTR, Lisp_Object, int)); +static Lisp_Object ftxfont_open P_ ((FRAME_PTR, Lisp_Object, int)); static void ftxfont_close P_ ((FRAME_PTR, struct font *)); -static int ftxfont_prepare_face (FRAME_PTR, struct face *); -static void ftxfont_done_face (FRAME_PTR, struct face *); - static int ftxfont_draw P_ ((struct glyph_string *, int, int, int, int, int)); struct font_driver ftxfont_driver; @@ -211,16 +254,11 @@ ftxfont_list (frame, spec) Lisp_Object frame; Lisp_Object spec; { - Lisp_Object val = ftfont_driver.list (frame, spec); + Lisp_Object list = ftfont_driver.list (frame, spec), tail; - if (! NILP (val)) - { - int i; - - for (i = 0; i < ASIZE (val); i++) - ASET (AREF (val, i), FONT_TYPE_INDEX, Qftx); - } - return val; + for (tail = list; CONSP (tail); tail = XCDR (tail)) + ASET (XCAR (tail), FONT_TYPE_INDEX, Qftx); + return list; } static Lisp_Object @@ -235,55 +273,21 @@ ftxfont_match (frame, spec) return entity; } -static struct font * +static Lisp_Object ftxfont_open (f, entity, pixel_size) FRAME_PTR f; Lisp_Object entity; int pixel_size; { - Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + Lisp_Object font_object; struct font *font; - XFontStruct *xfont = malloc (sizeof (XFontStruct)); - - if (! xfont) - return NULL; - font = ftfont_driver.open (f, entity, pixel_size); - if (! font) - { - free (xfont); - return NULL; - } - xfont->fid = ftxfont_default_fid (f); - xfont->ascent = font->ascent; - xfont->descent = font->descent; - xfont->max_bounds.width = font->font.size; - xfont->min_bounds.width = font->min_width; - font->font.font = xfont; + font_object = ftfont_driver.open (f, entity, pixel_size); + if (NILP (font_object)) + return Qnil; + font = XFONT_OBJECT (font_object); font->driver = &ftxfont_driver; - - dpyinfo->n_fonts++; - - /* Set global flag fonts_changed_p to non-zero if the font loaded - has a character with a smaller width than any other character - before, or if the font loaded has a smaller height than any other - font loaded before. If this happens, it will make a glyph matrix - reallocation necessary. */ - if (dpyinfo->n_fonts == 1) - { - dpyinfo->smallest_font_height = font->font.height; - dpyinfo->smallest_char_width = font->min_width; - fonts_changed_p = 1; - } - else - { - if (dpyinfo->smallest_font_height > font->font.height) - dpyinfo->smallest_font_height = font->font.height, fonts_changed_p |= 1; - if (dpyinfo->smallest_char_width > font->min_width) - dpyinfo->smallest_char_width = font->min_width, fonts_changed_p |= 1; - } - - return font; + return font_object; } static void @@ -292,52 +296,6 @@ ftxfont_close (f, font) struct font *font; { ftfont_driver.close (f, font); - FRAME_X_DISPLAY_INFO (f)->n_fonts--; -} - -static int -ftxfont_prepare_face (f, face) - FRAME_PTR f; - struct face *face; -{ - struct font *font = (struct font *) face->font_info; - GC gcs[6]; - int i; - - face->extra = NULL; - - if (! font->scalable) - return 0; - - if (ftxfont_create_gcs (f, gcs, face->foreground, face->background) < 0) - /* Give up antialiasing. */ - return 0; - - face->extra = malloc (sizeof (GC) * 7); - if (! face->extra) - return -1; - for (i = 0; i < 6; i++) - ((GC *) face->extra)[i] = gcs[i]; - ((GC *) face->extra)[i] = face->gc; - return 0; -} - -static void -ftxfont_done_face (f, face) - FRAME_PTR f; - struct face *face; -{ - if (face->extra) - { - int i; - - BLOCK_INPUT; - for (i = 0; i < 6; i++) - XFreeGC (FRAME_X_DISPLAY (f), ((GC *) face->extra)[i]); - UNBLOCK_INPUT; - free (face->extra); - face->extra = NULL; - } } static int @@ -347,18 +305,18 @@ ftxfont_draw (s, from, to, x, y, with_background) { FRAME_PTR f = s->f; struct face *face = s->face; - struct font *font = (struct font *) face->font_info; + struct font *font = s->font; XPoint p[0x700]; int n[7]; unsigned *code; int len = to - from; int i; GC *gcs; + int xadvance; n[0] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = 0; BLOCK_INPUT; - if (with_background) ftxfont_draw_backgrond (f, font, s->gc, x, y, s->width); code = alloca (sizeof (unsigned) * len); @@ -366,46 +324,46 @@ ftxfont_draw (s, from, to, x, y, with_background) code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8) | XCHAR2B_BYTE2 (s->char2b + from + i)); - gcs = face->extra; - if (gcs && face->gc != s->gc) + if (face->gc == s->gc) + { + gcs = ftxfont_get_gcs (f, face->foreground, face->background); + } + else { - /* We are drawing for cursor or for mouse highlighting, and - can't use the prepared GCs. */ XGCValues xgcv; unsigned long mask = GCForeground | GCBackground; - gcs = alloca (sizeof (GC) * 7); XGetGCValues (FRAME_X_DISPLAY (f), s->gc, mask, &xgcv); - if (ftxfont_create_gcs (f, gcs, xgcv.foreground, xgcv.background) < 0) - gcs = NULL; - gcs[6] = s->gc; + gcs = ftxfont_get_gcs (f, xgcv.foreground, xgcv.background); } - if (! gcs) + if (gcs) { - /* We are drawing with a bitmap font which doesn't use - antialiasing. */ + if (s->num_clips) + for (i = 0; i < 6; i++) + XSetClipRectangles (FRAME_X_DISPLAY (f), gcs[i], 0, 0, + s->clip, s->num_clips, Unsorted); + for (i = 0; i < len; i++) - x += ftxfont_draw_bitmap (f, &s->gc, font, code[i], x, y, - p, 0x700, n); - if (n[0] > 0) - XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - s->gc, p, n[0], CoordModeOrigin); + { + xadvance = ftxfont_draw_bitmap (f, s->gc, gcs, font, code[i], x, y, + p, 0x100, n, i + 1 == len); + x += (s->padding_p ? 1 : xadvance); + } + if (s->num_clips) + for (i = 0; i < 6; i++) + XSetClipMask (FRAME_X_DISPLAY (f), gcs[i], None); } else { - /* We are drawing with a scalable font which use - antialiasing. */ + /* We can't draw with antialiasing. + s->gc should already have a proper clipping setting. */ for (i = 0; i < len; i++) - x += ftxfont_draw_bitmap (f, gcs, font, code[i], x, y, - p, 0x100, n); - for (i = 0; i < 7; i++) - if (n[i] > 0) - XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - gcs[i], p + 0x100 * i, n[i], CoordModeOrigin); - if (face->gc != s->gc) - for (i = 0; i < 6; i++) - XFreeGC (FRAME_X_DISPLAY (f), gcs[i]); + { + xadvance = ftxfont_draw_bitmap (f, s->gc, NULL, font, code[i], x, y, + p, 0x700, n, i + 1 == len); + x += (s->padding_p ? 1 : xadvance); + } } UNBLOCK_INPUT; @@ -413,6 +371,28 @@ ftxfont_draw (s, from, to, x, y, with_background) return len; } +static int +ftxfont_end_for_frame (f) + FRAME_PTR f; +{ + struct ftxfont_frame_data *data = font_get_frame_data (f, &ftxfont_driver); + + BLOCK_INPUT; + while (data) + { + struct ftxfont_frame_data *next = data->next; + int i; + + for (i = 0; i < 6; i++) + XFreeGC (FRAME_X_DISPLAY (f), data->gcs[i]); + free (data); + data = next; + } + UNBLOCK_INPUT; + font_put_frame_data (f, &ftxfont_driver, NULL); + return 0; +} + void @@ -426,10 +406,8 @@ syms_of_ftxfont () ftxfont_driver.match = ftxfont_match; ftxfont_driver.open = ftxfont_open; ftxfont_driver.close = ftxfont_close; - ftxfont_driver.prepare_face = ftxfont_prepare_face; - ftxfont_driver.done_face = ftxfont_done_face; ftxfont_driver.draw = ftxfont_draw; - + ftxfont_driver.end_for_frame = ftxfont_end_for_frame; register_font_driver (&ftxfont_driver, NULL); }