]> code.delx.au - gnu-emacs/blob - src/ftcrfont.c
Merge branch 'master' into cairo, fixes tooltips not shown.
[gnu-emacs] / src / ftcrfont.c
1 /* ftcrfont.c -- FreeType font driver on cairo.
2 Copyright (C) 2015 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <cairo-ft.h>
23
24 #include "lisp.h"
25 #include "dispextern.h"
26 #include "xterm.h"
27 #include "frame.h"
28 #include "blockinput.h"
29 #include "character.h"
30 #include "charset.h"
31 #include "fontset.h"
32 #include "font.h"
33 #include "ftfont.h"
34
35 /* FTCR font driver. */
36
37 /* The actual structure for ftcr font that can be casted to struct
38 font. */
39
40 struct ftcrfont_info
41 {
42 struct font font;
43 /* The following six members must be here in this order to be
44 compatible with struct ftfont_info (in ftfont.c). */
45 #ifdef HAVE_LIBOTF
46 bool maybe_otf; /* Flag to tell if this may be OTF or not. */
47 OTF *otf;
48 #endif /* HAVE_LIBOTF */
49 FT_Size ft_size;
50 int index;
51 FT_Matrix matrix;
52
53 cairo_font_face_t *cr_font_face;
54 /* To prevent cairo from cluttering the activated FT_Size maintained
55 in ftfont.c, we activate this special FT_Size before drawing. */
56 FT_Size ft_size_draw;
57 /* Font metrics cache. */
58 struct font_metrics **metrics;
59 short metrics_nrows;
60 };
61
62 #define METRICS_NCOLS_PER_ROW (128)
63
64 enum metrics_status
65 {
66 METRICS_INVALID = -1, /* metrics entry is invalid */
67 };
68
69 #define METRICS_STATUS(metrics) ((metrics)->ascent + (metrics)->descent)
70 #define METRICS_SET_STATUS(metrics, status) \
71 ((metrics)->ascent = 0, (metrics)->descent = (status))
72
73 /* Prototypes for helper function. */
74 static int ftcrfont_glyph_extents (struct font *, unsigned,
75 struct font_metrics *);
76
77 /* Prototypes for font-driver methods. */
78 static Lisp_Object ftcrfont_list (struct frame*, Lisp_Object);
79 static Lisp_Object ftcrfont_match (struct frame*, Lisp_Object);
80 static Lisp_Object ftcrfont_open (struct frame*, Lisp_Object, int);
81 static void ftcrfont_close (struct font *);
82 static void ftcrfont_text_extents (struct font *, unsigned *, int,
83 struct font_metrics *);
84 static int ftcrfont_draw (struct glyph_string *, int, int, int, int, bool);
85
86 struct font_driver ftcrfont_driver;
87
88 static int
89 ftcrfont_glyph_extents (struct font *font,
90 unsigned glyph,
91 struct font_metrics *metrics)
92 {
93 struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) font;
94 int row, col;
95 struct font_metrics *cache;
96
97 row = glyph / METRICS_NCOLS_PER_ROW;
98 col = glyph % METRICS_NCOLS_PER_ROW;
99 if (row >= ftcrfont_info->metrics_nrows)
100 {
101 ftcrfont_info->metrics =
102 xrealloc (ftcrfont_info->metrics,
103 sizeof (struct font_metrics *) * (row + 1));
104 bzero (ftcrfont_info->metrics + ftcrfont_info->metrics_nrows,
105 (sizeof (struct font_metrics *)
106 * (row + 1 - ftcrfont_info->metrics_nrows)));
107 ftcrfont_info->metrics_nrows = row + 1;
108 }
109 if (ftcrfont_info->metrics[row] == NULL)
110 {
111 struct font_metrics *new;
112 int i;
113
114 new = xmalloc (sizeof (struct font_metrics) * METRICS_NCOLS_PER_ROW);
115 for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
116 METRICS_SET_STATUS (new + i, METRICS_INVALID);
117 ftcrfont_info->metrics[row] = new;
118 }
119 cache = ftcrfont_info->metrics[row] + col;
120
121 if (METRICS_STATUS (cache) == METRICS_INVALID)
122 ftfont_driver.text_extents (font, &glyph, 1, cache);
123
124 if (metrics)
125 *metrics = *cache;
126
127 return cache->width;
128 }
129
130 static Lisp_Object
131 ftcrfont_list (struct frame *f, Lisp_Object spec)
132 {
133 Lisp_Object list = ftfont_driver.list (f, spec), tail;
134
135 for (tail = list; CONSP (tail); tail = XCDR (tail))
136 ASET (XCAR (tail), FONT_TYPE_INDEX, Qftcr);
137 return list;
138 }
139
140 static Lisp_Object
141 ftcrfont_match (struct frame *f, Lisp_Object spec)
142 {
143 Lisp_Object entity = ftfont_driver.match (f, spec);
144
145 if (VECTORP (entity))
146 ASET (entity, FONT_TYPE_INDEX, Qftcr);
147 return entity;
148 }
149
150 extern FT_Face ftfont_get_ft_face (Lisp_Object);
151
152 static Lisp_Object
153 ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
154 {
155 Lisp_Object font_object;
156 struct font *font;
157 struct ftcrfont_info *ftcrfont_info;
158 FT_Face ft_face;
159 FT_UInt size;
160
161 block_input ();
162 size = XINT (AREF (entity, FONT_SIZE_INDEX));
163 if (size == 0)
164 size = pixel_size;
165 font_object = font_build_object (VECSIZE (struct ftcrfont_info),
166 Qftcr, entity, size);
167 font_object = ftfont_open2 (f, entity, pixel_size, font_object);
168 if (NILP (font_object)) return Qnil;
169
170 font = XFONT_OBJECT (font_object);
171 font->driver = &ftcrfont_driver;
172 ftcrfont_info = (struct ftcrfont_info *) font;
173 ft_face = ftcrfont_info->ft_size->face;
174 FT_New_Size (ft_face, &ftcrfont_info->ft_size_draw);
175 FT_Activate_Size (ftcrfont_info->ft_size_draw);
176 FT_Set_Pixel_Sizes (ft_face, 0, font->pixel_size);
177 ftcrfont_info->cr_font_face =
178 cairo_ft_font_face_create_for_ft_face (ft_face, 0);
179 ftcrfont_info->metrics = NULL;
180 ftcrfont_info->metrics_nrows = 0;
181 unblock_input ();
182
183 return font_object;
184 }
185
186 static void
187 ftcrfont_close (struct font *font)
188 {
189 struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) font;
190 int i;
191
192 block_input ();
193 for (i = 0; i < ftcrfont_info->metrics_nrows; i++)
194 if (ftcrfont_info->metrics[i])
195 xfree (ftcrfont_info->metrics[i]);
196 if (ftcrfont_info->metrics)
197 xfree (ftcrfont_info->metrics);
198 FT_Done_Size (ftcrfont_info->ft_size_draw);
199 cairo_font_face_destroy (ftcrfont_info->cr_font_face);
200 unblock_input ();
201
202 ftfont_driver.close (font);
203 }
204
205 static void
206 ftcrfont_text_extents (struct font *font,
207 unsigned *code,
208 int nglyphs,
209 struct font_metrics *metrics)
210 {
211 int width, i;
212
213 block_input ();
214 width = ftcrfont_glyph_extents (font, code[0], metrics);
215 for (i = 1; i < nglyphs; i++)
216 {
217 struct font_metrics m;
218 int w = ftcrfont_glyph_extents (font, code[i], metrics ? &m : NULL);
219
220 if (metrics)
221 {
222 if (width + m.lbearing < metrics->lbearing)
223 metrics->lbearing = width + m.lbearing;
224 if (width + m.rbearing > metrics->rbearing)
225 metrics->rbearing = width + m.rbearing;
226 if (m.ascent > metrics->ascent)
227 metrics->ascent = m.ascent;
228 if (m.descent > metrics->descent)
229 metrics->descent = m.descent;
230 }
231 width += w;
232 }
233 unblock_input ();
234
235 if (metrics)
236 metrics->width = width;
237 }
238
239 static int
240 ftcrfont_draw (struct glyph_string *s,
241 int from, int to, int x, int y, bool with_background)
242 {
243 struct frame *f = s->f;
244 struct face *face = s->face;
245 struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) s->font;
246 cairo_t *cr;
247 cairo_glyph_t *glyphs;
248 cairo_surface_t *surface;
249 cairo_surface_type_t surface_type;
250 int len = to - from;
251 int i;
252
253 block_input ();
254
255 cr = x_begin_cr_clip (f, s->gc);
256
257 if (with_background)
258 {
259 x_set_cr_source_with_gc_background (f, s->gc);
260 cairo_rectangle (cr, x, y - FONT_BASE (face->font),
261 s->width, FONT_HEIGHT (face->font));
262 cairo_fill (cr);
263 }
264
265 glyphs = alloca (sizeof (cairo_glyph_t) * len);
266 for (i = 0; i < len; i++)
267 {
268 unsigned code = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
269 | XCHAR2B_BYTE2 (s->char2b + from + i));
270
271 glyphs[i].index = code;
272 glyphs[i].x = x;
273 glyphs[i].y = y;
274 x += (s->padding_p ? 1 : ftcrfont_glyph_extents (s->font, code, NULL));
275 }
276
277 x_set_cr_source_with_gc_foreground (f, s->gc);
278 cairo_set_font_face (cr, ftcrfont_info->cr_font_face);
279 cairo_set_font_size (cr, s->font->pixel_size);
280 /* cairo_set_font_matrix */
281 /* cairo_set_font_options */
282
283 FT_Activate_Size (ftcrfont_info->ft_size_draw);
284 cairo_show_glyphs (cr, glyphs, len);
285 surface = cairo_get_target (cr);
286 /* XXX: It used to be necessary to flush when exporting. It might
287 be the case that this is no longer necessary. */
288 surface_type = cairo_surface_get_type (surface);
289 if (surface_type != CAIRO_SURFACE_TYPE_XLIB
290 && (surface_type != CAIRO_SURFACE_TYPE_IMAGE
291 || cairo_image_surface_get_format (surface) != CAIRO_FORMAT_ARGB32))
292 cairo_surface_flush (surface);
293
294 x_end_cr_clip (f);
295
296 unblock_input ();
297
298 return len;
299 }
300
301 \f
302
303 void
304 syms_of_ftcrfont (void)
305 {
306 if (ftfont_info_size != offsetof (struct ftcrfont_info, cr_font_face))
307 abort ();
308
309 DEFSYM (Qftcr, "ftcr");
310
311 ftcrfont_driver = ftfont_driver;
312 ftcrfont_driver.type = Qftcr;
313 ftcrfont_driver.list = ftcrfont_list;
314 ftcrfont_driver.match = ftcrfont_match;
315 ftcrfont_driver.open = ftcrfont_open;
316 ftcrfont_driver.close = ftcrfont_close;
317 ftcrfont_driver.text_extents = ftcrfont_text_extents;
318 ftcrfont_driver.draw = ftcrfont_draw;
319 register_font_driver (&ftcrfont_driver, NULL);
320 }