1 /* aafont.c - generic library for drawing anti-aliased fonts
2 Copyright (C) 1996-2017 Paul Sheer
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307, USA.
18 */
19
20 #include <config.h>
21 #ifdef HAVE_STDLIB_H
22 #include <stdlib.h>
23 #endif
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #endif
27 #include <stdio.h>
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include "aafont.h"
31 #include "mad.h"
32
33
34
35 /*
36 * list management
37 * ---------------
38 *
39 * Situation is a list of aa fonts:
40 * Each font is uniquified by a fg colour, a bg colour and a fontid.
41 * Each font has 65536 pixmap glyphs.
42 * The 65536 pixmaps are divided into 256 blocks.
43 * Each block is allocated on demand only.
44 * We *ImageString* only i.e. no DrawString - since requires knowledge
45 * of the background which is complicated.
46 */
47
48 Display *aa_display;
49 int aa_depth;
50 Window aa_root;
51 Visual *aa_visual;
52
53 int option_rgb_order = RedFirst;
54 int option_interchar_spacing = 0;
55
XAaInit(Display * display,Visual * visual,int depth,Window root)56 void XAaInit (Display * display, Visual * visual, int depth, Window root)
57 {
58 aa_display = display;
59 aa_depth = depth;
60 aa_root = root;
61 aa_visual = visual;
62 }
63
64 struct aa_glyph_cache {
65 Pixmap pixmap;
66 int width;
67 };
68
69 struct aa_font_cache {
70 XFontStruct *font_struct;
71 GC gc;
72 unsigned long fg;
73 unsigned long bg;
74 struct aa_glyph_cache *glyph[256];
75 int num_pixmaps;
76 struct aa_font_cache *next;
77 } *font_cache_list = 0;
78
aa_insert(void)79 static void aa_insert (void)
80 {
81 struct aa_font_cache *p;
82 p = malloc (sizeof (*font_cache_list));
83 memset (p, 0, sizeof (*font_cache_list));
84 if (!font_cache_list) {
85 font_cache_list = p;
86 } else {
87 p->next = font_cache_list;
88 font_cache_list = p;
89 }
90 }
91
aa_free(struct aa_font_cache * f)92 static void aa_free (struct aa_font_cache *f)
93 {
94 int i, j;
95 XFreeFontInfo (0, f->font_struct, 0);
96 for (i = 0; i < 256; i++) {
97 if (f->glyph[i]) {
98 for (j = 0; j < 256; j++)
99 if (f->glyph[i][j].pixmap)
100 XFreePixmap (aa_display, f->glyph[i][j].pixmap);
101 memset (f->glyph[i], 0, 256 * sizeof (struct aa_glyph_cache));
102 free (f->glyph[i]);
103 }
104 }
105 memset (f, 0, sizeof (*f));
106 free (f);
107 }
108
109 /* passing fg == bg == 0 finds any fid */
aa_find(Font fid,unsigned long fg,unsigned long bg)110 static struct aa_font_cache *aa_find (Font fid, unsigned long fg, unsigned long bg)
111 {
112 struct aa_font_cache *p;
113 for (p = font_cache_list; p; p = p->next)
114 if (fid && p->font_struct->fid == fid && p->fg == fg && p->bg == bg)
115 return p;
116 return 0;
117 }
118
119 /* returns zero on not found */
_aa_remove(Font fid)120 static int _aa_remove (Font fid)
121 {
122 struct aa_font_cache *p, *q = 0;
123 for (p = font_cache_list; p; p = p->next) {
124 if (fid && p->font_struct->fid == fid) {
125 if (p == font_cache_list) {
126 struct aa_font_cache *t;
127 t = font_cache_list->next;
128 aa_free (font_cache_list);
129 font_cache_list = t;
130 return 1;
131 } else {
132 q->next = p->next;
133 aa_free (p);
134 return 1;
135 }
136 }
137 q = p;
138 }
139 return 0;
140 }
141
aa_remove(Font fid)142 static void aa_remove (Font fid)
143 {
144 while (_aa_remove (fid));
145 }
146
147
148 /* fifth level */
149 /* 5 by 9/3 guassian convolution */
aa_convolve(int i,int j,unsigned char * source,int source_bytes_per_line,int byte_order,int bytes_per_pixel,int rgb_order,int red_shift,int green_shift,int blue_shift,int red_mask,int green_mask,int blue_mask)150 static unsigned long aa_convolve (int i, int j, unsigned char *source, int source_bytes_per_line,
151 int byte_order, int bytes_per_pixel, int rgb_order, int red_shift,
152 int green_shift, int blue_shift, int red_mask, int green_mask,
153 int blue_mask)
154 {
155 unsigned long red, green, blue;
156 #include "conv.c"
157 red /= (256 * 3);
158 green /= (256 * 3);
159 blue /= (256 * 3);
160 return (red << red_shift) | (green << green_shift) | (blue << blue_shift);
161 }
162
163 /* fourth level */
aa_shrink_pixmap(struct aa_font_cache * f,Pixmap pixmap,int width,int height,int * width_return)164 static Pixmap aa_shrink_pixmap (struct aa_font_cache *f, Pixmap pixmap, int width, int height,
165 int *width_return)
166 {
167 XImage *image, *shrunk;
168 int i, j, w, h, bytes_per_pixel;
169 int red_shift, green_shift, blue_shift;
170 unsigned long red_mask, green_mask, blue_mask;
171
172 /* create an image to put the enlarged glyph into - make it slightly large to hold
173 the diameter of the 5x9 guassian as well as a one pixel enlargement and rounding error */
174 image =
175 XCreateImage (aa_display, aa_visual, aa_depth, ZPixmap, 0, 0, width + 4 + X_ENLARGEMENT + option_interchar_spacing * 3,
176 height + 8 + Y_ENLARGEMENT, 8, 0);
177 bytes_per_pixel = image->bytes_per_line / image->width;
178 image->data = (char *) malloc (image->bytes_per_line * image->height);
179
180 for (i = 0; i < width + 4 + X_ENLARGEMENT + option_interchar_spacing; i++)
181 XPutPixel (image, i, 0, f->bg);
182 for (j = 0; j < height + 8 + Y_ENLARGEMENT; j++)
183 memcpy (image->data + image->bytes_per_line * j, image->data, image->bytes_per_line);
184
185 /* create an image to put the reduced glyph into. round w and h up */
186 *width_return = w = SHRINK_WIDTH (width);
187 h = SHRINK_HEIGHT (height);
188 shrunk = XCreateImage (aa_display, aa_visual, aa_depth, ZPixmap, 0, 0, w, h, 8, 0);
189 shrunk->data = (char *) malloc (shrunk->bytes_per_line * h);
190
191 for (red_mask = image->red_mask, red_shift = 0; red_shift < 32 && !(red_mask & 1);
192 red_shift++, red_mask >>= 1);
193 for (green_mask = image->green_mask, green_shift = 0; green_shift < 32 && !(green_mask & 1);
194 green_shift++, green_mask >>= 1);
195 for (blue_mask = image->blue_mask, blue_shift = 0; blue_shift < 32 && !(blue_mask & 1);
196 blue_shift++, blue_mask >>= 1);
197
198 XGetSubImage (aa_display, pixmap, 0, 0, width, height,
199 image->red_mask | image->green_mask | image->blue_mask, ZPixmap, image, 2, 4);
200
201 for (i = 0; i < w; i++) {
202 for (j = 0; j < h; j++) {
203 unsigned long pixel;
204 pixel =
205 aa_convolve (i * 3, j * 3,
206 (unsigned char *) image->data + bytes_per_pixel * 2 +
207 image->bytes_per_line * 4, image->bytes_per_line, image->byte_order,
208 bytes_per_pixel, option_rgb_order, red_shift, green_shift, blue_shift,
209 red_mask, green_mask, blue_mask);
210 XPutPixel (shrunk, i, j, pixel);
211 }
212 }
213
214 pixmap = XCreatePixmap (aa_display, aa_root, w, h, aa_depth);
215 XPutImage (aa_display, pixmap, f->gc, shrunk, 0, 0, 0, 0, w, h);
216 free (image->data);
217 image->data = 0;
218 XDestroyImage (image);
219 free (shrunk->data);
220 shrunk->data = 0;
221 XDestroyImage (shrunk);
222 return pixmap;
223 }
224
225 /* third level */
aa_create_pixmap(struct aa_font_cache * f,int j,int i,int * width)226 static Pixmap aa_create_pixmap (struct aa_font_cache *f, int j, int i, int *width)
227 {
228 Pixmap w, r;
229 int direction, ascent, descent, height;
230 XCharStruct ch;
231 XChar2b c;
232 c.byte1 = j;
233 c.byte2 = i;
234 XTextExtents16 (f->font_struct, &c, 1, &direction, &ascent, &descent, &ch);
235 height = f->font_struct->ascent + f->font_struct->descent;
236 w = XCreatePixmap (aa_display, aa_root, ch.width, height, aa_depth);
237 /* cheapest way to clear the background */
238 XDrawImageString (aa_display, w, f->gc, 0, f->font_struct->ascent, " ", 5);
239 /* needed to clear the background if the function fails on non-existing chars */
240 XDrawImageString16 (aa_display, w, f->gc, 0, f->font_struct->ascent, &c, 1);
241 r = aa_shrink_pixmap (f, w, ch.width, height, width);
242 XFreePixmap (aa_display, w);
243 return r;
244 }
245
246 /* second level */
aa_create_pixmap_(struct aa_font_cache * f,int j,int i)247 static void aa_create_pixmap_ (struct aa_font_cache *f, int j, int i)
248 {
249 if (!f->glyph[j]) {
250 f->glyph[j] = malloc (sizeof (struct aa_glyph_cache) * 256);
251 memset (f->glyph[j], 0, sizeof (struct aa_glyph_cache) * 256);
252 }
253 if (!f->glyph[j][i].pixmap)
254 f->glyph[j][i].pixmap = aa_create_pixmap (f, j, i, &f->glyph[j][i].width);
255 }
256
257 /* top level */
aa_create_pixmaps(struct aa_font_cache * f,XChar2b * wc,unsigned char * c,int n)258 static void aa_create_pixmaps (struct aa_font_cache *f, XChar2b * wc, unsigned char *c, int n)
259 {
260 int i;
261 if (aa_visual->class != TrueColor) {
262 fprintf
263 (stderr,
264 "%s:%d: Can't do anti-aliasing without TrueColor visual.\nTry setting your X server to non-8-bits-per-pixel display.\n",
265 __FILE__, __LINE__);
266 exit (1);
267 }
268 if (wc) {
269 for (i = 0; i < n; i++)
270 aa_create_pixmap_ (f, wc[i].byte1, wc[i].byte2);
271 } else {
272 for (i = 0; i < n; i++)
273 aa_create_pixmap_ (f, 0, c[i]);
274 }
275 }
276
_XAaDrawImageStringWC(Display * display,Drawable d,GC gc,int x,int y,char * s,XChar2b * wc,int length)277 int _XAaDrawImageStringWC (Display * display, Drawable d, GC gc, int x, int y, char *s,
278 XChar2b * wc, int length)
279 {
280 int i, x_start = x;
281 struct aa_font_cache *f;
282 XGCValues values_return;
283 XGetGCValues (display, gc, GCForeground | GCBackground | GCFont, &values_return);
284 f = aa_find (values_return.font, values_return.foreground, values_return.background);
285 if (!f) {
286 aa_insert ();
287 f = font_cache_list;
288 f->font_struct = XQueryFont (display, values_return.font);
289 f->gc = gc;
290 f->fg = values_return.foreground;
291 f->bg = values_return.background;
292 aa_display = display;
293 }
294 aa_create_pixmaps (f, wc, (unsigned char *) s, length);
295 if (wc) {
296 for (i = 0; i < length; i++) {
297 int width = f->glyph[wc[i].byte1][wc[i].byte2].width;
298 int height = SHRINK_HEIGHT (f->font_struct->ascent + f->font_struct->descent);
299 XCopyArea (display, f->glyph[wc[i].byte1][wc[i].byte2].pixmap, d, gc, 0, 0, width,
300 height, x, y - f->font_struct->ascent / 3);
301 x += width;
302 }
303 } else {
304 for (i = 0; i < length; i++) {
305 int width = f->glyph[0][(unsigned char) s[i]].width;
306 int height = SHRINK_HEIGHT (f->font_struct->ascent + f->font_struct->descent);
307 XCopyArea (display, f->glyph[0][(unsigned char) s[i]].pixmap, d, gc, 0, 0, width,
308 height, x, y - f->font_struct->ascent / 3);
309 x += width;
310 }
311 }
312 return x - x_start;
313 }
314
XAaTextWidth(XFontStruct * font_struct,char * s,int length)315 int XAaTextWidth (XFontStruct * font_struct, char *s, int length)
316 {
317 int w = 0, i;
318 int direction, ascent, descent;
319 for (i = 0; i < length; i++) {
320 XCharStruct ch;
321 XTextExtents (font_struct, s + i, 1, &direction, &ascent, &descent, &ch);
322 w += SHRINK_WIDTH (ch.width);
323 }
324 return w;
325 }
326
XAaTextWidth16(XFontStruct * font_struct,XChar2b * s,int length)327 int XAaTextWidth16 (XFontStruct * font_struct, XChar2b * s, int length)
328 {
329 int w = 0, i;
330 int direction, ascent, descent;
331 for (i = 0; i < length; i++) {
332 XCharStruct ch;
333 XTextExtents16 (font_struct, s + i, 1, &direction, &ascent, &descent, &ch);
334 w += SHRINK_WIDTH (ch.width);
335 }
336 return w;
337 }
338
XAaDrawImageString16(Display * display,Drawable d,GC gc,int x,int y,XChar2b * wc,int length)339 int XAaDrawImageString16 (Display * display, Drawable d, GC gc, int x, int y, XChar2b * wc,
340 int length)
341 {
342 return _XAaDrawImageStringWC (display, d, gc, x, y, 0, wc, length);
343 }
344
XAaDrawImageString(Display * display,Drawable d,GC gc,int x,int y,char * s,int length)345 int XAaDrawImageString (Display * display, Drawable d, GC gc, int x, int y, char *s, int length)
346 {
347 return _XAaDrawImageStringWC (display, d, gc, x, y, s, 0, length);
348 }
349
XAaFree(Font fid)350 void XAaFree (Font fid)
351 {
352 aa_remove (fid);
353 }
354
355