1 /* ftxfont.c -- FreeType font driver on X (without using XFT).
  2    Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
  3    Copyright (C) 2006, 2007, 2008, 2009, 2010
  4      National Institute of Advanced Industrial Science and Technology (AIST)
  5      Registration Number H13PRO009
  6 
  7 This file is part of GNU Emacs.
  8 
  9 GNU Emacs is free software: you can redistribute it and/or modify
 10 it under the terms of the GNU General Public License as published by
 11 the Free Software Foundation, either version 3 of the License, or
 12 (at your option) any later version.
 13 
 14 GNU Emacs is distributed in the hope that it will be useful,
 15 but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 17 GNU General Public License for more details.
 18 
 19 You should have received a copy of the GNU General Public License
 20 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 21 
 22 #include <config.h>
 23 #include <stdio.h>
 24 #include <setjmp.h>
 25 #include <X11/Xlib.h>
 26 
 27 #include "lisp.h"
 28 #include "dispextern.h"
 29 #include "xterm.h"
 30 #include "frame.h"
 31 #include "blockinput.h"
 32 #include "character.h"
 33 #include "charset.h"
 34 #include "fontset.h"
 35 #include "font.h"
 36 
 37 /* FTX font driver.  */
 38 
 39 static Lisp_Object Qftx;
 40 
 41 /* Prototypes for helper function.  */
 42 static GC *ftxfont_get_gcs P_ ((FRAME_PTR, unsigned long, unsigned long));
 43 static int ftxfont_draw_bitmap P_ ((FRAME_PTR, GC, GC *, struct font *,
 44                                     unsigned, int, int, XPoint *, int, int *,
 45                                     int));
 46 static void ftxfont_draw_backgrond P_ ((FRAME_PTR, struct font *, GC,
 47                                         int, int, int));
 48 
 49 struct ftxfont_frame_data
 50 {
 51   /* Background and foreground colors.  */
 52   XColor colors[2];
 53   /* GCs interporationg the above colors.  gcs[0] is for a color
 54    closest to BACKGROUND, and gcs[5] is for a color closest to
 55    FOREGROUND.  */
 56   GC gcs[6];
 57   struct ftxfont_frame_data *next;
 58 };
 59 
 60 
 61 /* Return an array of 6 GCs for antialiasing.  */
 62 
 63 static GC *
 64 ftxfont_get_gcs (f, foreground, background)
 65      FRAME_PTR f;
 66      unsigned long foreground, background;
 67 {
 68   XColor color;
 69   XGCValues xgcv;
 70   int i;
 71   struct ftxfont_frame_data *data = font_get_frame_data (f, &ftxfont_driver);
 72   struct ftxfont_frame_data *prev = NULL, *this = NULL, *new;
 73 
 74   if (data)
 75     {
 76       for (this = data; this; prev = this, this = this->next)
 77         {
 78           if (this->colors[0].pixel < background)
 79             continue;
 80           if (this->colors[0].pixel > background)
 81             break;
 82           if (this->colors[1].pixel < foreground)
 83             continue;
 84           if (this->colors[1].pixel > foreground)
 85             break;
 86           return this->gcs;
 87         }
 88     }
 89 
 90   new = malloc (sizeof (struct ftxfont_frame_data));
 91   if (! new)
 92     return NULL;
 93   new->next = this;
 94   if (prev)
 95     {
 96       prev->next = new;
 97     }
 98   else if (font_put_frame_data (f, &ftxfont_driver, new) < 0)
 99     {
100       free (new);
101       return NULL;
102     }
103 
104   new->colors[0].pixel = background;
105   new->colors[1].pixel = foreground;
106 
107   BLOCK_INPUT;
108   XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), new->colors, 2);
109   for (i = 1; i < 7; i++)
110     {
111       /* Interpolate colors linearly.  Any better algorithm?  */
112       color.red
113         = (new->colors[1].red * i + new->colors[0].red * (8 - i)) / 8;
114       color.green
115         = (new->colors[1].green * i + new->colors[0].green * (8 - i)) / 8;
116       color.blue
117         = (new->colors[1].blue * i + new->colors[0].blue * (8 - i)) / 8;
118       if (! x_alloc_nearest_color (f, FRAME_X_COLORMAP (f), &color))
119         break;
120       xgcv.foreground = color.pixel;
121       new->gcs[i - 1] = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
122                                    GCForeground, &xgcv);
123     }
124   UNBLOCK_INPUT;
125 
126   if (i < 7)
127     {
128       BLOCK_INPUT;
129       for (i--; i >= 0; i--)
130         XFreeGC (FRAME_X_DISPLAY (f), new->gcs[i]);
131       UNBLOCK_INPUT;
132       if (prev)
133         prev->next = new->next;
134       else if (data)
135         font_put_frame_data (f, &ftxfont_driver, new->next);
136       free (new);
137       return NULL;
138     }
139   return new->gcs;
140 }
141 
142 static int
143 ftxfont_draw_bitmap (f, gc_fore, gcs, font, code, x, y, p, size, n, flush)
144      FRAME_PTR f;
145      GC gc_fore, *gcs;
146      struct font *font;
147      unsigned code;
148      int x, y;
149      XPoint *p;
150      int size, *n;
151      int flush;
152 {
153   struct font_bitmap bitmap;
154   unsigned char *b;
155   int i, j;
156 
157   if (ftfont_driver.get_bitmap (font, code, &bitmap, size > 0x100 ? 1 : 8) < 0)
158     return 0;
159   if (size > 0x100)
160     {
161       for (i = 0, b = bitmap.buffer; i < bitmap.rows;
162            i++, b += bitmap.pitch)
163         {
164           for (j = 0; j < bitmap.width; j++)
165             if (b[j / 8] & (1 << (7 - (j % 8))))
166               {
167                 p[n[0]].x = x + bitmap.left + j;
168                 p[n[0]].y = y - bitmap.top + i;
169                 if (++n[0] == size)
170                   {
171                     XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
172                                  gc_fore, p, size, CoordModeOrigin);
173                     n[0] = 0;
174                   }
175               }
176         }
177       if (flush && n[0] > 0)
178         XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
179                      gc_fore, p, n[0], CoordModeOrigin);
180     }
181   else
182     {
183       for (i = 0, b = bitmap.buffer; i < bitmap.rows;
184            i++, b += bitmap.pitch)
185         {
186           for (j = 0; j < bitmap.width; j++)
187             {
188               int idx = (bitmap.bits_per_pixel == 1
189                          ? ((b[j / 8] & (1 << (7 - (j % 8)))) ? 6 : -1)
190                          : (b[j] >> 5) - 1);
191 
192               if (idx >= 0)
193                 {
194                   XPoint *pp = p + size * idx;
195 
196                   pp[n[idx]].x = x + bitmap.left + j;
197                   pp[n[idx]].y = y - bitmap.top + i;
198                   if (++(n[idx]) == size)
199                     {
200                       XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
201                                    idx == 6 ? gc_fore : gcs[idx], pp, size,
202                                    CoordModeOrigin);
203                       n[idx] = 0;
204                     }
205                 }
206             }
207         }
208       if (flush)
209         {
210           for (i = 0; i < 6; i++)
211             if (n[i] > 0)
212               XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
213                            gcs[i], p + 0x100 * i, n[i], CoordModeOrigin);
214           if (n[6] > 0)
215             XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
216                          gc_fore, p + 0x600, n[6], CoordModeOrigin);
217         }
218     }
219 
220   if (ftfont_driver.free_bitmap)
221     ftfont_driver.free_bitmap (font, &bitmap);
222 
223   return bitmap.advance;
224 }
225 
226 static void
227 ftxfont_draw_backgrond (f, font, gc, x, y, width)
228      FRAME_PTR f;
229      struct font *font;
230      GC gc;
231      int x, y, width;
232 {
233   XGCValues xgcv;
234 
235   XGetGCValues (FRAME_X_DISPLAY (f), gc,
236                 GCForeground | GCBackground, &xgcv);
237   XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.background);
238   XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
239                   x, y - FONT_BASE (font), width, FONT_HEIGHT (font));
240   XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.foreground);
241 }
242 
243 /* Prototypes for font-driver methods.  */
244 static Lisp_Object ftxfont_list P_ ((Lisp_Object, Lisp_Object));
245 static Lisp_Object ftxfont_match P_ ((Lisp_Object, Lisp_Object));
246 static Lisp_Object ftxfont_open P_ ((FRAME_PTR, Lisp_Object, int));
247 static void ftxfont_close P_ ((FRAME_PTR, struct font *));
248 static int ftxfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
249 
250 struct font_driver ftxfont_driver;
251 
252 static Lisp_Object
253 ftxfont_list (frame, spec)
254      Lisp_Object frame;
255      Lisp_Object spec;
256 {
257   Lisp_Object list = ftfont_driver.list (frame, spec), tail;
258   
259   for (tail = list; CONSP (tail); tail = XCDR (tail))
260     ASET (XCAR (tail), FONT_TYPE_INDEX, Qftx);
261   return list;
262 }
263 
264 static Lisp_Object
265 ftxfont_match (frame, spec)
266      Lisp_Object frame;
267      Lisp_Object spec;
268 {
269   Lisp_Object entity = ftfont_driver.match (frame, spec);
270 
271   if (VECTORP (entity))
272     ASET (entity, FONT_TYPE_INDEX, Qftx);
273   return entity;
274 }
275 
276 static Lisp_Object
277 ftxfont_open (f, entity, pixel_size)
278      FRAME_PTR f;
279      Lisp_Object entity;
280      int pixel_size;
281 {
282   Lisp_Object font_object;
283   struct font *font;
284 
285   font_object = ftfont_driver.open (f, entity, pixel_size);
286   if (NILP (font_object))
287     return Qnil;
288   font = XFONT_OBJECT (font_object);
289   font->driver = &ftxfont_driver;
290   return font_object;
291 }
292 
293 static void
294 ftxfont_close (f, font)
295      FRAME_PTR f;
296      struct font *font;
297 {
298   ftfont_driver.close (f, font);
299 }
300 
301 static int
302 ftxfont_draw (s, from, to, x, y, with_background)
303      struct glyph_string *s;
304      int from, to, x, y, with_background;
305 {
306   FRAME_PTR f = s->f;
307   struct face *face = s->face;
308   struct font *font = s->font;
309   XPoint p[0x700];
310   int n[7];
311   unsigned *code;
312   int len = to - from;
313   int i;
314   GC *gcs;
315   int xadvance;
316 
317   n[0] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = 0;
318 
319   BLOCK_INPUT;
320   if (with_background)
321     ftxfont_draw_backgrond (f, font, s->gc, x, y, s->width);
322   code = alloca (sizeof (unsigned) * len);
323   for (i = 0; i < len; i++)
324     code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
325                | XCHAR2B_BYTE2 (s->char2b + from + i));
326 
327   if (face->gc == s->gc)
328     {
329       gcs = ftxfont_get_gcs (f, face->foreground, face->background);
330     }
331   else
332     {
333       XGCValues xgcv;
334       unsigned long mask = GCForeground | GCBackground;
335 
336       XGetGCValues (FRAME_X_DISPLAY (f), s->gc, mask, &xgcv);
337       gcs = ftxfont_get_gcs (f, xgcv.foreground, xgcv.background);
338     }
339 
340   if (gcs)
341     {
342       if (s->num_clips)
343         for (i = 0; i < 6; i++)
344           XSetClipRectangles (FRAME_X_DISPLAY (f), gcs[i], 0, 0,
345                               s->clip, s->num_clips, Unsorted);
346 
347       for (i = 0; i < len; i++)
348         {
349           xadvance = ftxfont_draw_bitmap (f, s->gc, gcs, font, code[i], x, y,
350                                           p, 0x100, n, i + 1 == len);
351           x += (s->padding_p ? 1 : xadvance);
352         }
353       if (s->num_clips)
354         for (i = 0; i < 6; i++)
355           XSetClipMask (FRAME_X_DISPLAY (f), gcs[i], None);
356     }
357   else
358     {
359       /* We can't draw with antialiasing.
360          s->gc should already have a proper clipping setting. */
361       for (i = 0; i < len; i++)
362         {
363           xadvance = ftxfont_draw_bitmap (f, s->gc, NULL, font, code[i], x, y,
364                                           p, 0x700, n, i + 1 == len);
365           x += (s->padding_p ? 1 : xadvance);
366         }
367     }
368 
369   UNBLOCK_INPUT;
370 
371   return len;
372 }
373 
374 static int
375 ftxfont_end_for_frame (f)
376      FRAME_PTR f;
377 {
378   struct ftxfont_frame_data *data = font_get_frame_data (f, &ftxfont_driver);
379   
380   BLOCK_INPUT;
381   while (data)
382     {
383       struct ftxfont_frame_data *next = data->next;
384       int i;
385       
386       for (i = 0; i < 6; i++)
387         XFreeGC (FRAME_X_DISPLAY (f), data->gcs[i]);
388       free (data);
389       data = next;
390     }
391   UNBLOCK_INPUT;
392   font_put_frame_data (f, &ftxfont_driver, NULL);
393   return 0;
394 }
395 
396 
397 
398 void
399 syms_of_ftxfont ()
400 {
401   DEFSYM (Qftx, "ftx");
402 
403   ftxfont_driver = ftfont_driver;
404   ftxfont_driver.type = Qftx;
405   ftxfont_driver.list = ftxfont_list;
406   ftxfont_driver.match = ftxfont_match;
407   ftxfont_driver.open = ftxfont_open;
408   ftxfont_driver.close = ftxfont_close;
409   ftxfont_driver.draw = ftxfont_draw;
410   ftxfont_driver.end_for_frame = ftxfont_end_for_frame;
411   register_font_driver (&ftxfont_driver, NULL);
412 }
413 
414 /* arch-tag: 59bd3469-5330-413f-b29d-1aa36492abe8
415    (do not change this comment) */