source: mainline/uspace/lib/gfxfont/src/glyph.c@ aaf962e6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since aaf962e6 was d145ecb, checked in by Jiri Svoboda <jiri@…>, 5 years ago

Libriff needs unit tests

  • Property mode set to 100644
File size: 10.0 KB
Line 
1/*
2 * Copyright (c) 2020 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libgfxfont
30 * @{
31 */
32/**
33 * @file Glyph
34 */
35
36#include <assert.h>
37#include <errno.h>
38#include <gfx/bitmap.h>
39#include <gfx/glyph.h>
40#include <io/pixelmap.h>
41#include <mem.h>
42#include <stdlib.h>
43#include <str.h>
44#include "../private/font.h"
45#include "../private/glyph.h"
46#include "../private/tpf_file.h"
47
48/** Initialize glyph metrics structure.
49 *
50 * Glyph metrics structure must always be initialized using this function
51 * first.
52 *
53 * @param metrics Glyph metrics structure
54 */
55void gfx_glyph_metrics_init(gfx_glyph_metrics_t *metrics)
56{
57 memset(metrics, 0, sizeof(gfx_glyph_metrics_t));
58}
59
60/** Create glyph.
61 *
62 * @param font Containing font
63 * @param metrics Glyph metrics
64 * @param rglyph Place to store pointer to new glyph
65 *
66 * @return EOK on success, EINVAL if parameters are invald,
67 * ENOMEM if insufficient resources, EIO if graphic device connection
68 * was lost
69 */
70errno_t gfx_glyph_create(gfx_font_t *font, gfx_glyph_metrics_t *metrics,
71 gfx_glyph_t **rglyph)
72{
73 gfx_glyph_t *glyph;
74 errno_t rc;
75
76 glyph = calloc(1, sizeof(gfx_glyph_t));
77 if (glyph == NULL)
78 return ENOMEM;
79
80 glyph->font = font;
81
82 rc = gfx_glyph_set_metrics(glyph, metrics);
83 if (rc != EOK) {
84 assert(rc == EINVAL);
85 free(glyph);
86 return rc;
87 }
88
89 glyph->metrics = *metrics;
90 list_append(&glyph->lglyphs, &glyph->font->glyphs);
91 list_initialize(&glyph->patterns);
92 *rglyph = glyph;
93 return EOK;
94}
95
96/** Destroy glyph.
97 *
98 * @param glyph Glyph
99 */
100void gfx_glyph_destroy(gfx_glyph_t *glyph)
101{
102 list_remove(&glyph->lglyphs);
103 free(glyph);
104}
105
106/** Get glyph metrics.
107 *
108 * @param glyph Glyph
109 * @param metrics Place to store metrics
110 */
111void gfx_glyph_get_metrics(gfx_glyph_t *glyph, gfx_glyph_metrics_t *metrics)
112{
113 *metrics = glyph->metrics;
114}
115
116/** Set glyph metrics.
117 *
118 * @param glyph Glyph
119 * @param metrics Place to store metrics
120 * @return EOK on success, EINVAL if supplied metrics are invalid
121 */
122errno_t gfx_glyph_set_metrics(gfx_glyph_t *glyph, gfx_glyph_metrics_t *metrics)
123{
124 glyph->metrics = *metrics;
125 return EOK;
126}
127
128/** Set a pattern that the glyph will match.
129 *
130 * A glyph can match any number of patterns. Setting the same pattern
131 * again has no effect. The pattern is a simple (sub)string. Matching
132 * is done using maximum munch rule.
133 *
134 * @param glyph Glyph
135 * @param pattern Pattern
136 * @return EOK on success, ENOMEM if out of memory
137 */
138errno_t gfx_glyph_set_pattern(gfx_glyph_t *glyph, const char *pattern)
139{
140 gfx_glyph_pattern_t *pat;
141
142 pat = gfx_glyph_first_pattern(glyph);
143 while (pat != NULL) {
144 if (str_cmp(pat->text, pattern) == 0) {
145 /* Already set */
146 return EOK;
147 }
148
149 pat = gfx_glyph_next_pattern(pat);
150 }
151
152 pat = calloc(1, sizeof(gfx_glyph_pattern_t));
153 if (pat == NULL)
154 return ENOMEM;
155
156 pat->glyph = glyph;
157 pat->text = str_dup(pattern);
158 if (pat->text == NULL) {
159 free(pat);
160 return ENOMEM;
161 }
162
163 list_append(&pat->lpatterns, &glyph->patterns);
164 return EOK;
165}
166
167/** Clear a matching pattern from a glyph.
168 *
169 * Clearing a pattern that is not set has no effect.
170 *
171 * @param Glyph
172 * @param pattern Pattern
173 */
174void gfx_glyph_clear_pattern(gfx_glyph_t *glyph, const char *pattern)
175{
176 gfx_glyph_pattern_t *pat;
177
178 pat = gfx_glyph_first_pattern(glyph);
179 while (pat != NULL) {
180 if (str_cmp(pat->text, pattern) == 0) {
181 list_remove(&pat->lpatterns);
182 free(pat->text);
183 free(pat);
184 return;
185 }
186
187 pat = gfx_glyph_next_pattern(pat);
188 }
189}
190
191/** Determine if glyph maches the beginning of a string.
192 *
193 * @param glyph Glyph
194 * @param str String
195 * @param rsize Place to store number of bytes in the matching pattern
196 * @return @c true iff glyph matches the beginning of the string
197 */
198bool gfx_glyph_matches(gfx_glyph_t *glyph, const char *str, size_t *rsize)
199{
200 gfx_glyph_pattern_t *pat;
201
202 pat = gfx_glyph_first_pattern(glyph);
203 while (pat != NULL) {
204 if (str_test_prefix(str, pat->text)) {
205 *rsize = str_size(pat->text);
206 return true;
207 }
208
209 pat = gfx_glyph_next_pattern(pat);
210 }
211
212 return false;
213}
214
215/** Get first glyph pattern.
216 *
217 * @param glyph Glyph
218 * @return First pattern or @c NULL if there are none
219 */
220gfx_glyph_pattern_t *gfx_glyph_first_pattern(gfx_glyph_t *glyph)
221{
222 link_t *link;
223
224 link = list_first(&glyph->patterns);
225 if (link == NULL)
226 return NULL;
227
228 return list_get_instance(link, gfx_glyph_pattern_t, lpatterns);
229}
230
231/** Get next glyph pattern.
232 *
233 * @param cur Current pattern
234 * @return Next pattern or @c NULL if there are none
235 */
236gfx_glyph_pattern_t *gfx_glyph_next_pattern(gfx_glyph_pattern_t *cur)
237{
238 link_t *link;
239
240 link = list_next(&cur->lpatterns, &cur->glyph->patterns);
241 if (link == NULL)
242 return NULL;
243
244 return list_get_instance(link, gfx_glyph_pattern_t, lpatterns);
245}
246
247/** Return pattern string.
248 *
249 * @param pattern Pattern
250 * @return Pattern string (owned by @a pattern)
251 */
252const char *gfx_glyph_pattern_str(gfx_glyph_pattern_t *pattern)
253{
254 return pattern->text;
255}
256
257/** Render glyph to GC.
258 *
259 * @param glyph Glyph
260 * @param pos Position to render to (where glyph origin is placed)
261 */
262errno_t gfx_glyph_render(gfx_glyph_t *glyph, gfx_coord2_t *pos)
263{
264 gfx_coord2_t offs;
265
266 gfx_coord2_subtract(pos, &glyph->origin, &offs);
267
268 return gfx_bitmap_render(glyph->font->bitmap, &glyph->rect, &offs);
269}
270
271/** Transfer glyph to new font bitmap.
272 *
273 * @param glyph Glyph
274 * @param offs Offset in new font bitmap
275 * @param dest New font bitmap
276 * @param drect Bounding rectangle for @a dest
277 *
278 * @return EOK on success or an error code
279 */
280errno_t gfx_glyph_transfer(gfx_glyph_t *glyph, gfx_coord_t offs,
281 gfx_bitmap_t *dest, gfx_rect_t *drect)
282{
283 pixelmap_t smap;
284 pixelmap_t dmap;
285 gfx_bitmap_alloc_t salloc;
286 gfx_bitmap_alloc_t dalloc;
287 gfx_coord_t x, y;
288 pixel_t pixel;
289 errno_t rc;
290
291 rc = gfx_bitmap_get_alloc(glyph->font->bitmap, &salloc);
292 if (rc != EOK)
293 return rc;
294
295 rc = gfx_bitmap_get_alloc(dest, &dalloc);
296 if (rc != EOK)
297 return rc;
298
299 smap.width = glyph->font->rect.p1.x;
300 smap.height = glyph->font->rect.p1.y;
301 smap.data = salloc.pixels;
302
303 dmap.width = drect->p1.x;
304 dmap.height = drect->p1.y;
305 dmap.data = dalloc.pixels;
306
307 for (y = drect->p0.y; y < drect->p1.y; y++) {
308 for (x = drect->p0.x; x < drect->p1.x; x++) {
309 pixel = pixelmap_get_pixel(&smap, x, y);
310 pixelmap_put_pixel(&dmap, x + offs, y, pixel);
311 }
312 }
313
314 return EOK;
315}
316
317/** Save glyph metrics to RIFF TPF file.
318 *
319 * @param metrics Glyph metrics
320 * @param riffw RIFF writer
321 * @return EOK on success or an error code
322 */
323static errno_t gfx_glyph_metrics_save(gfx_glyph_metrics_t *metrics,
324 riffw_t *riffw)
325{
326 errno_t rc;
327 riff_wchunk_t mtrck;
328
329 rc = riff_wchunk_start(riffw, CKID_gmtr, &mtrck);
330 if (rc != EOK)
331 return rc;
332
333 rc = riff_write(riffw, (void *) metrics, sizeof(*metrics));
334 if (rc != EOK)
335 return rc;
336
337 rc = riff_wchunk_end(riffw, &mtrck);
338 if (rc != EOK)
339 return rc;
340
341 return EOK;
342}
343
344/** Save glyph patterns to RIFF TPF file.
345 *
346 * @param glyph Glyph
347 * @param riffw RIFF writer
348 * @return EOK on success or an error code
349 */
350static errno_t gfx_glyph_patterns_save(gfx_glyph_t *glyph, riffw_t *riffw)
351{
352 errno_t rc;
353 riff_wchunk_t patck;
354 gfx_glyph_pattern_t *pat;
355 const char *str;
356
357 rc = riff_wchunk_start(riffw, CKID_gpat, &patck);
358 if (rc != EOK)
359 return rc;
360
361 pat = gfx_glyph_first_pattern(glyph);
362 while (pat != NULL) {
363 str = gfx_glyph_pattern_str(pat);
364
365 rc = riff_write(riffw, (void *) str, 1 + str_size(str));
366 if (rc != EOK)
367 return rc;
368
369 pat = gfx_glyph_next_pattern(pat);
370 }
371
372 rc = riff_wchunk_end(riffw, &patck);
373 if (rc != EOK)
374 return rc;
375
376 return EOK;
377}
378
379/** Save glyph rectangle/origin to RIFF TPF file.
380 *
381 * @param glyph Glyph
382 * @param riffw RIFF writer
383 * @return EOK on success or an error code
384 */
385static errno_t gfx_glyph_rectangle_origin_save(gfx_glyph_t *glyph,
386 riffw_t *riffw)
387{
388 errno_t rc;
389 riff_wchunk_t rorck;
390
391 rc = riff_wchunk_start(riffw, CKID_gror, &rorck);
392 if (rc != EOK)
393 return rc;
394
395 rc = riff_write(riffw, (void *) &glyph->rect, sizeof(glyph->rect));
396 if (rc != EOK)
397 return rc;
398
399 rc = riff_write(riffw, (void *) &glyph->origin, sizeof(glyph->origin));
400 if (rc != EOK)
401 return rc;
402
403 rc = riff_wchunk_end(riffw, &rorck);
404 if (rc != EOK)
405 return rc;
406
407 return EOK;
408}
409
410/** Save glyph into RIFF TPF file.
411 *
412 * @param glyph Glyph
413 * @param riffw RIFF writer
414 */
415errno_t gfx_glyph_save(gfx_glyph_t *glyph, riffw_t *riffw)
416{
417 errno_t rc;
418 riff_wchunk_t glyphck;
419
420 rc = riff_wchunk_start(riffw, CKID_LIST, &glyphck);
421 if (rc != EOK)
422 return rc;
423
424 rc = riff_write_uint32(riffw, LTYPE_glph);
425 if (rc != EOK)
426 return rc;
427
428 rc = gfx_glyph_metrics_save(&glyph->metrics, riffw);
429 if (rc != EOK)
430 return rc;
431
432 rc = gfx_glyph_patterns_save(glyph, riffw);
433 if (rc != EOK)
434 return rc;
435
436 rc = gfx_glyph_rectangle_origin_save(glyph, riffw);
437 if (rc != EOK)
438 return rc;
439
440 rc = riff_wchunk_end(riffw, &glyphck);
441 if (rc != EOK)
442 return rc;
443
444 return EOK;
445}
446
447/** @}
448 */
Note: See TracBrowser for help on using the repository browser.