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

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

Reading typeface from TPF file

  • Property mode set to 100644
File size: 13.1 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/** Load glyph metrics from RIFF TPF file.
318 *
319 * @param parent Parent chunk
320 * @param metrics Place to store glyph metrics
321 * @return EOK on success or an error code
322 */
323static errno_t gfx_glyph_metrics_load(riff_rchunk_t *parent,
324 gfx_glyph_metrics_t *metrics)
325{
326 errno_t rc;
327 riff_rchunk_t mtrck;
328 size_t nread;
329
330 rc = riff_rchunk_match(parent, CKID_gmtr, &mtrck);
331 if (rc != EOK)
332 return rc;
333
334 rc = riff_read(&mtrck, (void *) metrics, sizeof(*metrics), &nread);
335 if (rc != EOK || nread != sizeof(*metrics))
336 return EIO;
337
338 rc = riff_rchunk_end(&mtrck);
339 if (rc != EOK)
340 return rc;
341
342 return EOK;
343}
344
345/** Save glyph metrics to RIFF TPF file.
346 *
347 * @param metrics Glyph metrics
348 * @param riffw RIFF writer
349 * @return EOK on success or an error code
350 */
351static errno_t gfx_glyph_metrics_save(gfx_glyph_metrics_t *metrics,
352 riffw_t *riffw)
353{
354 errno_t rc;
355 riff_wchunk_t mtrck;
356
357 rc = riff_wchunk_start(riffw, CKID_gmtr, &mtrck);
358 if (rc != EOK)
359 return rc;
360
361 rc = riff_write(riffw, (void *) metrics, sizeof(*metrics));
362 if (rc != EOK)
363 return rc;
364
365 rc = riff_wchunk_end(riffw, &mtrck);
366 if (rc != EOK)
367 return rc;
368
369 return EOK;
370}
371
372/** Load glyph patterns from RIFF TPF file.
373 *
374 * @param parent Parent chunk
375 * @param glyph Glyph
376 * @return EOK on success or an error code
377 */
378static errno_t gfx_glyph_patterns_load(riff_rchunk_t *parent,
379 gfx_glyph_t *glyph)
380{
381 errno_t rc;
382 riff_rchunk_t patck;
383 uint32_t cksize;
384 size_t i;
385 size_t nread;
386 char *buf = NULL;
387
388 rc = riff_rchunk_match(parent, CKID_gpat, &patck);
389 if (rc != EOK)
390 goto error;
391
392 cksize = riff_rchunk_size(&patck);
393 buf = malloc(cksize);
394 if (buf == NULL) {
395 rc = ENOMEM;
396 goto error;
397 }
398
399 rc = riff_read(&patck, buf, cksize, &nread);
400 if (rc != EOK || nread != cksize)
401 goto error;
402
403 i = 0;
404 while (i < cksize) {
405 rc = gfx_glyph_set_pattern(glyph, &buf[i]);
406 if (rc != EOK)
407 goto error;
408
409 i += str_size(&buf[i]) + 1;
410 }
411
412 rc = riff_rchunk_end(&patck);
413 if (rc != EOK)
414 goto error;
415
416 free(buf);
417 return EOK;
418error:
419 if (buf != NULL)
420 free(buf);
421 return rc;
422}
423/** Save glyph patterns to RIFF TPF file.
424 *
425 * @param glyph Glyph
426 * @param riffw RIFF writer
427 * @return EOK on success or an error code
428 */
429static errno_t gfx_glyph_patterns_save(gfx_glyph_t *glyph, riffw_t *riffw)
430{
431 errno_t rc;
432 riff_wchunk_t patck;
433 gfx_glyph_pattern_t *pat;
434 const char *str;
435
436 rc = riff_wchunk_start(riffw, CKID_gpat, &patck);
437 if (rc != EOK)
438 return rc;
439
440 pat = gfx_glyph_first_pattern(glyph);
441 while (pat != NULL) {
442 str = gfx_glyph_pattern_str(pat);
443
444 rc = riff_write(riffw, (void *) str, 1 + str_size(str));
445 if (rc != EOK)
446 return rc;
447
448 pat = gfx_glyph_next_pattern(pat);
449 }
450
451 rc = riff_wchunk_end(riffw, &patck);
452 if (rc != EOK)
453 return rc;
454
455 return EOK;
456}
457
458/** Load glyph rectangle/origin from RIFF TPF file.
459 *
460 * @param parent Parent chunk
461 * @param glyph Glyph
462 * @return EOK on success or an error code
463 */
464static errno_t gfx_glyph_rectangle_origin_load(riff_rchunk_t *parent,
465 gfx_glyph_t *glyph)
466{
467 errno_t rc;
468 riff_rchunk_t rorck;
469 size_t nread;
470
471 rc = riff_rchunk_match(parent, CKID_gror, &rorck);
472 if (rc != EOK)
473 return rc;
474
475 rc = riff_read(&rorck, (void *) &glyph->rect, sizeof(glyph->rect),
476 &nread);
477 if (rc != EOK || nread != sizeof(glyph->rect))
478 return EIO;
479
480 rc = riff_read(&rorck, (void *) &glyph->origin, sizeof(glyph->origin),
481 &nread);
482 if (rc != EOK || nread != sizeof(glyph->origin))
483 return EIO;
484
485 rc = riff_rchunk_end(&rorck);
486 if (rc != EOK)
487 return rc;
488
489 return EOK;
490}
491
492/** Save glyph rectangle/origin to RIFF TPF file.
493 *
494 * @param glyph Glyph
495 * @param riffw RIFF writer
496 * @return EOK on success or an error code
497 */
498static errno_t gfx_glyph_rectangle_origin_save(gfx_glyph_t *glyph,
499 riffw_t *riffw)
500{
501 errno_t rc;
502 riff_wchunk_t rorck;
503
504 rc = riff_wchunk_start(riffw, CKID_gror, &rorck);
505 if (rc != EOK)
506 return rc;
507
508 rc = riff_write(riffw, (void *) &glyph->rect, sizeof(glyph->rect));
509 if (rc != EOK)
510 return rc;
511
512 rc = riff_write(riffw, (void *) &glyph->origin, sizeof(glyph->origin));
513 if (rc != EOK)
514 return rc;
515
516 rc = riff_wchunk_end(riffw, &rorck);
517 if (rc != EOK)
518 return rc;
519
520 return EOK;
521}
522
523/** Load glyph from RIFF TPF file.
524 *
525 * @param font Containing font
526 * @param parent Parent chunk
527 * @return EOK on success or an error code
528 */
529errno_t gfx_glyph_load(gfx_font_t *font, riff_rchunk_t *parent)
530{
531 errno_t rc;
532 gfx_glyph_metrics_t metrics;
533 gfx_glyph_t *glyph = NULL;
534 riff_rchunk_t glyphck;
535
536 rc = riff_rchunk_list_match(parent, LTYPE_glph, &glyphck);
537 if (rc != EOK)
538 goto error;
539
540 rc = gfx_glyph_metrics_load(&glyphck, &metrics);
541 if (rc != EOK)
542 goto error;
543
544 rc = gfx_glyph_create(font, &metrics, &glyph);
545 if (rc != EOK)
546 goto error;
547
548 rc = gfx_glyph_patterns_load(&glyphck, glyph);
549 if (rc != EOK)
550 goto error;
551
552 rc = gfx_glyph_rectangle_origin_load(&glyphck, glyph);
553 if (rc != EOK)
554 goto error;
555
556 rc = riff_rchunk_end(&glyphck);
557 if (rc != EOK)
558 goto error;
559
560 return EOK;
561error:
562 if (glyph != NULL)
563 gfx_glyph_destroy(glyph);
564 return rc;
565}
566
567/** Save glyph into RIFF TPF file.
568 *
569 * @param glyph Glyph
570 * @param riffw RIFF writer
571 * @return EOK on success or an error code
572 */
573errno_t gfx_glyph_save(gfx_glyph_t *glyph, riffw_t *riffw)
574{
575 errno_t rc;
576 riff_wchunk_t glyphck;
577
578 rc = riff_wchunk_start(riffw, CKID_LIST, &glyphck);
579 if (rc != EOK)
580 return rc;
581
582 rc = riff_write_uint32(riffw, LTYPE_glph);
583 if (rc != EOK)
584 return rc;
585
586 rc = gfx_glyph_metrics_save(&glyph->metrics, riffw);
587 if (rc != EOK)
588 return rc;
589
590 rc = gfx_glyph_patterns_save(glyph, riffw);
591 if (rc != EOK)
592 return rc;
593
594 rc = gfx_glyph_rectangle_origin_save(glyph, riffw);
595 if (rc != EOK)
596 return rc;
597
598 rc = riff_wchunk_end(riffw, &glyphck);
599 if (rc != EOK)
600 return rc;
601
602 return EOK;
603}
604
605/** @}
606 */
Note: See TracBrowser for help on using the repository browser.