build: replace genshader by binary linker
[platform/upstream/kmscon.git] / src / font.c
1 /*
2  * kmscon - Font handling
3  *
4  * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@googlemail.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files
8  * (the "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26 /**
27  * SECTION:font
28  * @short_description: Font handling
29  * @include: font.h
30  *
31  * The text renderer needs a backend that draws glyphs which then can be shown
32  * on the screen. This font handling subsystem provides a very simple API to
33  * load arbitrary font-renderer backends. That is, you can choose from
34  * in-memory bitmap fonts up to full Unicode compatible font libraries like
35  * pango during runtime.
36  *
37  * This system does not provide any renderer by itself. You need to register one
38  * of the available font-renderers first which then is used as backend for this
39  * system. kmscon_font_register() and kmscon_font_unregister() can be used to
40  * register font-renderers manually.
41  *
42  * @kmscon_font_attr is used to specify font-attributes for the fonts you want.
43  * Please see kmscon_font_find() for more information on font-attributes. This
44  * function returns a matching font which then can be used for drawing.
45  * kmscon_font_ref()/kmscon_font_unref() are used for reference counting.
46  * kmscon_font_render() renders a single unicode glyph and returns the glyph
47  * buffer. kmscon_font_drop() frees this buffer again. A kmscon_glyph object
48  * contains a memory-buffer with the rendered glyph plus some metrics like
49  * height/width but also ascent/descent.
50  *
51  * Font-backends must take into account that this API must be thread-safe as it
52  * is shared between different threads to reduce memory-footprint.
53  */
54
55 #include <errno.h>
56 #include <pthread.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include "font.h"
60 #include "kmscon_module.h"
61 #include "shl_dlist.h"
62 #include "shl_log.h"
63 #include "shl_misc.h"
64 #include "shl_register.h"
65
66 #define LOG_SUBSYSTEM "font"
67
68 static struct shl_register font_reg = SHL_REGISTER_INIT(font_reg);
69
70 /**
71  * kmscon_font_attr_normalize:
72  * @attr: Attribute to normalize
73  *
74  * This normalizes @attr and fills out missing entries. The following is done:
75  * - If attr->name is empty, then it is set to KMSCON_FONT_DEFAULT_NAME
76  * - If attr->ppi is 0, it is set to KMSCON_FONT_DEFAULT_PPI
77  * - If attr->height is not set but attr->points is given, then attr->heights is
78  *   calculated from attr->points.
79  * - If attr->height is set, then attr->points is recalculated and overwritten
80  *
81  * The other fields are not changed. If attr->points is set but attr->height is
82  * not set, then the height is calculated and after that the points are
83  * recalculated so we will never have division-errors.
84  */
85 SHL_EXPORT
86 void kmscon_font_attr_normalize(struct kmscon_font_attr *attr)
87 {
88         if (!attr)
89                 return;
90
91         if (!*attr->name)
92                 memcpy(attr->name, KMSCON_FONT_DEFAULT_NAME,
93                        sizeof(KMSCON_FONT_DEFAULT_NAME));
94
95         if (!attr->ppi)
96                 attr->ppi = KMSCON_FONT_DEFAULT_PPI;
97
98         if (!attr->height && attr->points)
99                 attr->height = attr->points * attr->ppi / 72;
100         if (attr->height)
101                 attr->points = attr->height * 72 / attr->ppi;
102 }
103
104 /**
105  * kmscon_font_attr_match:
106  * @a1: First attribute to match
107  * @a2: Second attribute to match
108  *
109  * Compares @a1 and @a2 and returns true if they match. Both must be normalized
110  * before comparing them, otherwise the comparison may return inexact results.
111  * If width, height or *name is 0, then the fields are _not_ compared so you can
112  * have wildmask matches.
113  * points and dpi are never compared as the normalization already computes the
114  * height correctly. So there is no need to use these.
115  *
116  * Returns: true if they match, otherwise false
117  */
118 SHL_EXPORT
119 bool kmscon_font_attr_match(const struct kmscon_font_attr *a1,
120                             const struct kmscon_font_attr *a2)
121 {
122         if (!a1 || !a2)
123                 return false;
124
125         if (a1->width && a2->width && a1->width != a2->width)
126                 return false;
127         if (a1->height && a2->height && a1->height != a2->height)
128                 return false;
129         if (a1->bold != a2->bold)
130                 return false;
131         if (a1->italic != a2->italic)
132                 return false;
133         if (*a1->name && *a2->name && strcmp(a1->name, a2->name))
134                 return false;
135
136         return true;
137 }
138
139 static inline void kmscon_font_destroy(void *data)
140 {
141         const struct kmscon_font_ops *ops = data;
142
143         kmscon_module_unref(ops->owner);
144 }
145
146 /**
147  * kmscon_font_register:
148  * @ops: Font operations and name for new font backend
149  *
150  * This register a new font backend with operations set to @ops. The name
151  * @ops->name must be valid.
152  *
153  * The first font that is registered automatically becomes the default font and
154  * the fallback font. So make sure you register a safe fallback as first font.
155  * If this font is unregistered, the next font in the list becomes the default
156  * and fallback font.
157  *
158  * Returns: 0 on success, negative error code on failure
159  */
160 SHL_EXPORT
161 int kmscon_font_register(const struct kmscon_font_ops *ops)
162 {
163         int ret;
164
165         if (!ops)
166                 return -EINVAL;
167
168         log_debug("register font backend %s", ops->name);
169
170         ret = shl_register_add_cb(&font_reg, ops->name, (void*)ops,
171                                   kmscon_font_destroy);
172         if (ret) {
173                 log_error("cannot register font backend %s: %d", ops->name,
174                           ret);
175                 return ret;
176         }
177
178         kmscon_module_ref(ops->owner);
179         return 0;
180 }
181
182 /**
183  * kmscon_font_unregister:
184  * @name: Name of font backend
185  *
186  * This unregisters the font-backend that is registered with name @name. If
187  * @name is not found, a warning is printed but nothing else is done.
188  */
189 SHL_EXPORT
190 void kmscon_font_unregister(const char *name)
191 {
192         log_debug("unregister font backend %s", name);
193         shl_register_remove(&font_reg, name);
194 }
195
196 static int new_font(struct kmscon_font *font,
197                     const struct kmscon_font_attr *attr, const char *backend)
198 {
199         struct shl_register_record *record;
200         const char *name = backend ? backend : "<default>";
201         int ret;
202
203         memset(font, 0, sizeof(*font));
204         font->ref = 1;
205
206         if (backend)
207                 record = shl_register_find(&font_reg, backend);
208         else
209                 record = shl_register_first(&font_reg);
210
211         if (!record) {
212                 log_error("requested backend '%s' not found", name);
213                 return -ENOENT;
214         }
215
216         font->record = record;
217         font->ops = record->data;
218
219         if (font->ops->init)
220                 ret = font->ops->init(font, attr);
221         else
222                 ret = 0;
223
224         if (ret) {
225                 log_warning("backend %s cannot create font", name);
226                 shl_register_record_unref(record);
227                 return ret;
228         }
229
230         return 0;
231 }
232
233 /**
234  * kmscon_font_find:
235  * @out: A pointer to the new font is stored here
236  * @attr: Attribute describing the font
237  * @backend: Backend to use or NULL for default backend
238  *
239  * Lookup a font by the given attributes. It uses the font backend @backend. If
240  * it is NULL, the default backend is used. If the given backend cannot find
241  * a suitable font, the fallback backend is tried. This backend should always
242  * find a suitable font.
243  *
244  * Stores a pointer to the new font in @out and returns 0. Otherwise, @out is
245  * not touched and an error is returned.
246  *
247  * The attributes in @attr are not always matched. There are even font backends
248  * which have only one fixed font and always return this one so you cannot rely
249  * on this behavior. That is, this function cannot be used to get an exact
250  * match, it rather returns the best matching font.
251  * There is currently no need to get an exact match so no API is available to
252  * get this. Instead, you should always use the best match and the user must be
253  * happy. We do print warnings if no close match can be found, though. The user
254  * should read them if they want more information what font fallback was used.
255  *
256  * If this functions fails, you must not assume that there is another font that
257  * might work. Moreover, you must not implement a fallback font yourself as this
258  * is already implemented inside of this function! This function fails only due
259  * to internal errors like failed memory allocations. If it fails, the chances
260  * that you can allocate your own fallback font are pretty small so don't do it.
261  *
262  * About DPI and Point Sizes:
263  * Many computer graphics systems use "Points" as measurement for font sizes.
264  * However, most of them also use 72 or 96 as fixed DPI size for monitors. This
265  * means, the Point sizes can be directly converted into pixels. But lets
266  * look at the facts:
267  *   1 Point is defined as 1/72 of an inch. That is, a 10 Point font will be
268  *   exactly 10 / 72 inches, which is ~0.13889 inches, which is
269  *   0.13889 * 2.54 cm, which is approximately 0.3528 cm. This applies to
270  *   printed paper. If we want the same on a monitor, we must need more
271  *   information. First, the monitor renders in pixels, that is, we must know
272  *   how many Pixels per Inch (PPI) are displayed. Often the same information is
273  *   given as Dots per Inch (DPI) but these two are identical in this context.
274  *   If the DPI is 96, we know that our 10 Point font is 10 / 72 inches. Which
275  *   then means it is 10 / 72 * 96 pixels, which is ~13.333 pixels. So we
276  *   internally render the font with 13 pixels and display it as 13 pixels. This
277  *   guarantees, that the font will be 10 Point big which means 0.3528 cm on the
278  *   display. This of course requires that we know the exact PPI/DPI of the
279  *   display.
280  * But if we take into account that Windows uses fixed 96 PPI and Mac OS X 72
281  * PPI (independent of the monitor), they drop all this information and instead
282  * render the font in pixel sizes. Because if you use fixed 72 PPI, a 10 Point
283  * font will always be 10 / 72 * 72 = 10 pixels high. This means, it would be
284  * rather convenient to directly specify pixel-sizes on the monitor. If you want
285  * to work with documents that shall be printed, you want to specify Points so
286  * the printed result will look nice. But the disadvantage is, that your monitor
287  * can print this font in the weirdest size if it uses PPI much bigger or lower
288  * than the common 96 or 72. Therefore, if you work with a monitor you probably
289  * want to also specify the pixel-height of the font as you probably don't know
290  * the PPI of your monitor and don't want to do all that math in your head.
291  * Therefore, for applications that will probably never print their output (like
292  * the virtual (!) console this is for), it is often requested that we can
293  * specify the pixel size instead of the Point size of a font so you can
294  * predict the output better.
295  * Hence, we provide both. If pixel information is given, that is, attr->height
296  * is not 0, then we try to return a font with this pixel height.
297  * If it is 0, attr->points is used together with attr->ppi to calculate the
298  * pixel size. If attr->ppi is 0, then 72 is used.
299  * After the font was chosen, all fields "points", "ppi", "height" and "width"
300  * will contain the exact values for this font. If "ppi" was zero and pixel
301  * sizes where specified, then the resulting "points" size is calculated with
302  * "ppi" = 72 again. So if you use the "points" field please always specify
303  * "ppi", either.
304  *
305  * Returns: 0 on success, error code on failure
306  */
307 int kmscon_font_find(struct kmscon_font **out,
308                      const struct kmscon_font_attr *attr,
309                      const char *backend)
310 {
311         struct kmscon_font *font;
312         int ret;
313
314         if (!out || !attr)
315                 return -EINVAL;
316
317         log_debug("searching for: be: %s nm: %s ppi: %u pt: %u b: %d i: %d he: %u wt: %u",
318                   backend, attr->name, attr->ppi, attr->points,
319                   attr->bold, attr->italic, attr->height,
320                   attr->width);
321
322         font = malloc(sizeof(*font));
323         if (!font) {
324                 log_error("cannot allocate memory for new font");
325                 return -ENOMEM;
326         }
327
328         ret = new_font(font, attr, backend);
329         if (ret) {
330                 if (backend)
331                         ret = new_font(font, attr, NULL);
332                 if (ret)
333                         goto err_free;
334         }
335
336         log_debug("using: be: %s nm: %s ppi: %u pt: %u b: %d i: %d he: %u wt: %u",
337                   font->ops->name, font->attr.name, font->attr.ppi,
338                   font->attr.points, font->attr.bold, font->attr.italic,
339                   font->attr.height, font->attr.width);
340         *out = font;
341         return 0;
342
343 err_free:
344         free(font);
345         return ret;
346 }
347
348 /**
349  * kmscon_font_ref:
350  * @font: Valid font object
351  *
352  * This increases the reference count of @font by one.
353  */
354 void kmscon_font_ref(struct kmscon_font *font)
355 {
356         if (!font || !font->ref)
357                 return;
358
359         ++font->ref;
360 }
361
362 /**
363  * kmscon_font_unref:
364  * @font: Valid font object
365  *
366  * This decreases the reference count of @font by one. If it drops to zero, the
367  * object is freed.
368  */
369 void kmscon_font_unref(struct kmscon_font *font)
370 {
371         if (!font || !font->ref || --font->ref)
372                 return;
373
374         log_debug("freeing font");
375         if (font->ops->destroy)
376                 font->ops->destroy(font);
377         shl_register_record_unref(font->record);
378         free(font);
379 }
380
381 /**
382  * kmscon_font_render:
383  * @font: Valid font object
384  * @id: Unique ID that identifies @ch globally
385  * @ch: Symbol to find a glyph for
386  * @len: Length of @ch
387  * @out: Output buffer for glyph
388  *
389  * Renders the glyph for symbol @sym and places a pointer to the glyph in @out.
390  * If the glyph cannot be found or is invalid, an error is returned. The glyph
391  * is cached internally and removed when the last reference to this font is
392  * dropped.
393  * If the glyph is no available in this font-set, then -ERANGE is returned.
394  *
395  * Returns: 0 on success, negative error code on failure
396  */
397 SHL_EXPORT
398 int kmscon_font_render(struct kmscon_font *font,
399                        uint32_t id, const uint32_t *ch, size_t len,
400                        const struct kmscon_glyph **out)
401 {
402         if (!font || !out || !ch || !len)
403                 return -EINVAL;
404
405         return font->ops->render(font, id, ch, len, out);
406 }
407
408 /**
409  * kmscon_font_render_empty:
410  * @font: Valid font object
411  * @out: Output buffer for glyph
412  *
413  * Same as kmscon_font_render() but this renders a glyph that has no content and
414  * can be used to blit solid backgrounds. That is, the resulting buffer will be
415  * all 0 but the dimensions are the same as for all other glyphs.
416  *
417  * Returns: 0 on success, negative error code on failure
418  */
419 SHL_EXPORT
420 int kmscon_font_render_empty(struct kmscon_font *font,
421                              const struct kmscon_glyph **out)
422 {
423         if (!font || !out)
424                 return -EINVAL;
425
426         return font->ops->render_empty(font, out);
427 }
428
429 /**
430  * kmscon_font_render_inval:
431  * @font: Valid font object
432  * @out: Output buffer for glyph
433  *
434  * Same sa kmscon_font_render_empty() but renders a glyph that can be used as
435  * replacement for any other non-drawable glyph. That is, if
436  * kmscon_font_render() returns -ERANGE, then this glyph can be used as
437  * replacement.
438  *
439  * Returns: 0 on success ,engative error code on failure
440  */
441 SHL_EXPORT
442 int kmscon_font_render_inval(struct kmscon_font *font,
443                              const struct kmscon_glyph **out)
444 {
445         if (!font || !out)
446                 return -EINVAL;
447
448         return font->ops->render_inval(font, out);
449 }