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

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

Cannot just write structures to TPF file

This would compromise portability of TPF files. What was I thinking?
Endianness and type widths must be fixed.

  • Property mode set to 100644
File size: 13.7 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 <byteorder.h>
38#include <errno.h>
39#include <gfx/bitmap.h>
40#include <gfx/glyph.h>
41#include <io/pixelmap.h>
42#include <mem.h>
43#include <stdlib.h>
44#include <str.h>
45#include "../private/font.h"
46#include "../private/glyph.h"
47#include "../private/tpf_file.h"
48
49/** Initialize glyph metrics structure.
50 *
51 * Glyph metrics structure must always be initialized using this function
52 * first.
53 *
54 * @param metrics Glyph metrics structure
55 */
56void gfx_glyph_metrics_init(gfx_glyph_metrics_t *metrics)
57{
58 memset(metrics, 0, sizeof(gfx_glyph_metrics_t));
59}
60
61/** Create glyph.
62 *
63 * @param font Containing font
64 * @param metrics Glyph metrics
65 * @param rglyph Place to store pointer to new glyph
66 *
67 * @return EOK on success, EINVAL if parameters are invald,
68 * ENOMEM if insufficient resources, EIO if graphic device connection
69 * was lost
70 */
71errno_t gfx_glyph_create(gfx_font_t *font, gfx_glyph_metrics_t *metrics,
72 gfx_glyph_t **rglyph)
73{
74 gfx_glyph_t *glyph;
75 errno_t rc;
76
77 glyph = calloc(1, sizeof(gfx_glyph_t));
78 if (glyph == NULL)
79 return ENOMEM;
80
81 glyph->font = font;
82
83 rc = gfx_glyph_set_metrics(glyph, metrics);
84 if (rc != EOK) {
85 assert(rc == EINVAL);
86 free(glyph);
87 return rc;
88 }
89
90 glyph->metrics = *metrics;
91 list_append(&glyph->lglyphs, &glyph->font->glyphs);
92 list_initialize(&glyph->patterns);
93 *rglyph = glyph;
94 return EOK;
95}
96
97/** Destroy glyph.
98 *
99 * @param glyph Glyph
100 */
101void gfx_glyph_destroy(gfx_glyph_t *glyph)
102{
103 list_remove(&glyph->lglyphs);
104 free(glyph);
105}
106
107/** Get glyph metrics.
108 *
109 * @param glyph Glyph
110 * @param metrics Place to store metrics
111 */
112void gfx_glyph_get_metrics(gfx_glyph_t *glyph, gfx_glyph_metrics_t *metrics)
113{
114 *metrics = glyph->metrics;
115}
116
117/** Set glyph metrics.
118 *
119 * @param glyph Glyph
120 * @param metrics Place to store metrics
121 * @return EOK on success, EINVAL if supplied metrics are invalid
122 */
123errno_t gfx_glyph_set_metrics(gfx_glyph_t *glyph, gfx_glyph_metrics_t *metrics)
124{
125 glyph->metrics = *metrics;
126 return EOK;
127}
128
129/** Set a pattern that the glyph will match.
130 *
131 * A glyph can match any number of patterns. Setting the same pattern
132 * again has no effect. The pattern is a simple (sub)string. Matching
133 * is done using maximum munch rule.
134 *
135 * @param glyph Glyph
136 * @param pattern Pattern
137 * @return EOK on success, ENOMEM if out of memory
138 */
139errno_t gfx_glyph_set_pattern(gfx_glyph_t *glyph, const char *pattern)
140{
141 gfx_glyph_pattern_t *pat;
142
143 pat = gfx_glyph_first_pattern(glyph);
144 while (pat != NULL) {
145 if (str_cmp(pat->text, pattern) == 0) {
146 /* Already set */
147 return EOK;
148 }
149
150 pat = gfx_glyph_next_pattern(pat);
151 }
152
153 pat = calloc(1, sizeof(gfx_glyph_pattern_t));
154 if (pat == NULL)
155 return ENOMEM;
156
157 pat->glyph = glyph;
158 pat->text = str_dup(pattern);
159 if (pat->text == NULL) {
160 free(pat);
161 return ENOMEM;
162 }
163
164 list_append(&pat->lpatterns, &glyph->patterns);
165 return EOK;
166}
167
168/** Clear a matching pattern from a glyph.
169 *
170 * Clearing a pattern that is not set has no effect.
171 *
172 * @param Glyph
173 * @param pattern Pattern
174 */
175void gfx_glyph_clear_pattern(gfx_glyph_t *glyph, const char *pattern)
176{
177 gfx_glyph_pattern_t *pat;
178
179 pat = gfx_glyph_first_pattern(glyph);
180 while (pat != NULL) {
181 if (str_cmp(pat->text, pattern) == 0) {
182 list_remove(&pat->lpatterns);
183 free(pat->text);
184 free(pat);
185 return;
186 }
187
188 pat = gfx_glyph_next_pattern(pat);
189 }
190}
191
192/** Determine if glyph maches the beginning of a string.
193 *
194 * @param glyph Glyph
195 * @param str String
196 * @param rsize Place to store number of bytes in the matching pattern
197 * @return @c true iff glyph matches the beginning of the string
198 */
199bool gfx_glyph_matches(gfx_glyph_t *glyph, const char *str, size_t *rsize)
200{
201 gfx_glyph_pattern_t *pat;
202
203 pat = gfx_glyph_first_pattern(glyph);
204 while (pat != NULL) {
205 if (str_test_prefix(str, pat->text)) {
206 *rsize = str_size(pat->text);
207 return true;
208 }
209
210 pat = gfx_glyph_next_pattern(pat);
211 }
212
213 return false;
214}
215
216/** Get first glyph pattern.
217 *
218 * @param glyph Glyph
219 * @return First pattern or @c NULL if there are none
220 */
221gfx_glyph_pattern_t *gfx_glyph_first_pattern(gfx_glyph_t *glyph)
222{
223 link_t *link;
224
225 link = list_first(&glyph->patterns);
226 if (link == NULL)
227 return NULL;
228
229 return list_get_instance(link, gfx_glyph_pattern_t, lpatterns);
230}
231
232/** Get next glyph pattern.
233 *
234 * @param cur Current pattern
235 * @return Next pattern or @c NULL if there are none
236 */
237gfx_glyph_pattern_t *gfx_glyph_next_pattern(gfx_glyph_pattern_t *cur)
238{
239 link_t *link;
240
241 link = list_next(&cur->lpatterns, &cur->glyph->patterns);
242 if (link == NULL)
243 return NULL;
244
245 return list_get_instance(link, gfx_glyph_pattern_t, lpatterns);
246}
247
248/** Return pattern string.
249 *
250 * @param pattern Pattern
251 * @return Pattern string (owned by @a pattern)
252 */
253const char *gfx_glyph_pattern_str(gfx_glyph_pattern_t *pattern)
254{
255 return pattern->text;
256}
257
258/** Render glyph to GC.
259 *
260 * @param glyph Glyph
261 * @param pos Position to render to (where glyph origin is placed)
262 */
263errno_t gfx_glyph_render(gfx_glyph_t *glyph, gfx_coord2_t *pos)
264{
265 gfx_coord2_t offs;
266
267 gfx_coord2_subtract(pos, &glyph->origin, &offs);
268
269 return gfx_bitmap_render(glyph->font->bitmap, &glyph->rect, &offs);
270}
271
272/** Transfer glyph to new font bitmap.
273 *
274 * @param glyph Glyph
275 * @param offs Offset in new font bitmap
276 * @param dest New font bitmap
277 * @param drect Bounding rectangle for @a dest
278 *
279 * @return EOK on success or an error code
280 */
281errno_t gfx_glyph_transfer(gfx_glyph_t *glyph, gfx_coord_t offs,
282 gfx_bitmap_t *dest, gfx_rect_t *drect)
283{
284 pixelmap_t smap;
285 pixelmap_t dmap;
286 gfx_bitmap_alloc_t salloc;
287 gfx_bitmap_alloc_t dalloc;
288 gfx_coord_t x, y;
289 pixel_t pixel;
290 errno_t rc;
291
292 rc = gfx_bitmap_get_alloc(glyph->font->bitmap, &salloc);
293 if (rc != EOK)
294 return rc;
295
296 rc = gfx_bitmap_get_alloc(dest, &dalloc);
297 if (rc != EOK)
298 return rc;
299
300 smap.width = glyph->font->rect.p1.x;
301 smap.height = glyph->font->rect.p1.y;
302 smap.data = salloc.pixels;
303
304 dmap.width = drect->p1.x;
305 dmap.height = drect->p1.y;
306 dmap.data = dalloc.pixels;
307
308 for (y = drect->p0.y; y < drect->p1.y; y++) {
309 for (x = drect->p0.x; x < drect->p1.x; x++) {
310 pixel = pixelmap_get_pixel(&smap, x, y);
311 pixelmap_put_pixel(&dmap, x + offs, y, pixel);
312 }
313 }
314
315 return EOK;
316}
317
318/** Load glyph metrics from RIFF TPF file.
319 *
320 * @param parent Parent chunk
321 * @param metrics Place to store glyph metrics
322 * @return EOK on success or an error code
323 */
324static errno_t gfx_glyph_metrics_load(riff_rchunk_t *parent,
325 gfx_glyph_metrics_t *metrics)
326{
327 errno_t rc;
328 riff_rchunk_t mtrck;
329 tpf_glyph_metrics_t tmetrics;
330 size_t nread;
331
332 rc = riff_rchunk_match(parent, CKID_gmtr, &mtrck);
333 if (rc != EOK)
334 return rc;
335
336 rc = riff_read(&mtrck, (void *) &tmetrics, sizeof(tmetrics), &nread);
337 if (rc != EOK || nread != sizeof(tmetrics))
338 return EIO;
339
340 rc = riff_rchunk_end(&mtrck);
341 if (rc != EOK)
342 return rc;
343
344 metrics->advance = uint16_t_le2host(tmetrics.advance);
345 return EOK;
346}
347
348/** Save glyph metrics to RIFF TPF file.
349 *
350 * @param metrics Glyph metrics
351 * @param riffw RIFF writer
352 * @return EOK on success or an error code
353 */
354static errno_t gfx_glyph_metrics_save(gfx_glyph_metrics_t *metrics,
355 riffw_t *riffw)
356{
357 errno_t rc;
358 tpf_glyph_metrics_t tmetrics;
359 riff_wchunk_t mtrck;
360
361 tmetrics.advance = host2uint16_t_le(metrics->advance);
362
363 rc = riff_wchunk_start(riffw, CKID_gmtr, &mtrck);
364 if (rc != EOK)
365 return rc;
366
367 rc = riff_write(riffw, (void *) &tmetrics, sizeof(tmetrics));
368 if (rc != EOK)
369 return rc;
370
371 rc = riff_wchunk_end(riffw, &mtrck);
372 if (rc != EOK)
373 return rc;
374
375 return EOK;
376}
377
378/** Load glyph patterns from RIFF TPF file.
379 *
380 * @param parent Parent chunk
381 * @param glyph Glyph
382 * @return EOK on success or an error code
383 */
384static errno_t gfx_glyph_patterns_load(riff_rchunk_t *parent,
385 gfx_glyph_t *glyph)
386{
387 errno_t rc;
388 riff_rchunk_t patck;
389 uint32_t cksize;
390 size_t i;
391 size_t nread;
392 char *buf = NULL;
393
394 rc = riff_rchunk_match(parent, CKID_gpat, &patck);
395 if (rc != EOK)
396 goto error;
397
398 cksize = riff_rchunk_size(&patck);
399 buf = malloc(cksize);
400 if (buf == NULL) {
401 rc = ENOMEM;
402 goto error;
403 }
404
405 rc = riff_read(&patck, buf, cksize, &nread);
406 if (rc != EOK || nread != cksize)
407 goto error;
408
409 i = 0;
410 while (i < cksize) {
411 rc = gfx_glyph_set_pattern(glyph, &buf[i]);
412 if (rc != EOK)
413 goto error;
414
415 i += str_size(&buf[i]) + 1;
416 }
417
418 rc = riff_rchunk_end(&patck);
419 if (rc != EOK)
420 goto error;
421
422 free(buf);
423 return EOK;
424error:
425 if (buf != NULL)
426 free(buf);
427 return rc;
428}
429/** Save glyph patterns to RIFF TPF file.
430 *
431 * @param glyph Glyph
432 * @param riffw RIFF writer
433 * @return EOK on success or an error code
434 */
435static errno_t gfx_glyph_patterns_save(gfx_glyph_t *glyph, riffw_t *riffw)
436{
437 errno_t rc;
438 riff_wchunk_t patck;
439 gfx_glyph_pattern_t *pat;
440 const char *str;
441
442 rc = riff_wchunk_start(riffw, CKID_gpat, &patck);
443 if (rc != EOK)
444 return rc;
445
446 pat = gfx_glyph_first_pattern(glyph);
447 while (pat != NULL) {
448 str = gfx_glyph_pattern_str(pat);
449
450 rc = riff_write(riffw, (void *) str, 1 + str_size(str));
451 if (rc != EOK)
452 return rc;
453
454 pat = gfx_glyph_next_pattern(pat);
455 }
456
457 rc = riff_wchunk_end(riffw, &patck);
458 if (rc != EOK)
459 return rc;
460
461 return EOK;
462}
463
464/** Load glyph rectangle/origin from RIFF TPF file.
465 *
466 * @param parent Parent chunk
467 * @param glyph Glyph
468 * @return EOK on success or an error code
469 */
470static errno_t gfx_glyph_rectangle_origin_load(riff_rchunk_t *parent,
471 gfx_glyph_t *glyph)
472{
473 errno_t rc;
474 tpf_glyph_ror_t tror;
475 riff_rchunk_t rorck;
476 size_t nread;
477
478 rc = riff_rchunk_match(parent, CKID_gror, &rorck);
479 if (rc != EOK)
480 return rc;
481
482 rc = riff_read(&rorck, (void *) &tror, sizeof(tror),
483 &nread);
484 if (rc != EOK || nread != sizeof(tror))
485 return EIO;
486
487 rc = riff_rchunk_end(&rorck);
488 if (rc != EOK)
489 return rc;
490
491 glyph->rect.p0.x = uint32_t_le2host(tror.p0x);
492 glyph->rect.p0.y = uint32_t_le2host(tror.p0y);
493 glyph->rect.p1.x = uint32_t_le2host(tror.p1x);
494 glyph->rect.p1.y = uint32_t_le2host(tror.p1y);
495 glyph->origin.x = uint32_t_le2host(tror.orig_x);
496 glyph->origin.y = uint32_t_le2host(tror.orig_y);
497 return EOK;
498}
499
500/** Save glyph rectangle/origin to RIFF TPF file.
501 *
502 * @param glyph Glyph
503 * @param riffw RIFF writer
504 * @return EOK on success or an error code
505 */
506static errno_t gfx_glyph_rectangle_origin_save(gfx_glyph_t *glyph,
507 riffw_t *riffw)
508{
509 errno_t rc;
510 tpf_glyph_ror_t tror;
511 riff_wchunk_t rorck;
512
513 tror.p0x = host2uint32_t_le(glyph->rect.p0.x);
514 tror.p0y = host2uint32_t_le(glyph->rect.p0.y);
515 tror.p1x = host2uint32_t_le(glyph->rect.p1.x);
516 tror.p1y = host2uint32_t_le(glyph->rect.p1.y);
517 tror.orig_x = host2uint32_t_le(glyph->origin.x);
518 tror.orig_y = host2uint32_t_le(glyph->origin.y);
519
520 rc = riff_wchunk_start(riffw, CKID_gror, &rorck);
521 if (rc != EOK)
522 return rc;
523
524 rc = riff_write(riffw, (void *) &tror, sizeof(tror));
525 if (rc != EOK)
526 return rc;
527
528 rc = riff_wchunk_end(riffw, &rorck);
529 if (rc != EOK)
530 return rc;
531
532 return EOK;
533}
534
535/** Load glyph from RIFF TPF file.
536 *
537 * @param font Containing font
538 * @param parent Parent chunk
539 * @return EOK on success or an error code
540 */
541errno_t gfx_glyph_load(gfx_font_t *font, riff_rchunk_t *parent)
542{
543 errno_t rc;
544 gfx_glyph_metrics_t metrics;
545 gfx_glyph_t *glyph = NULL;
546 riff_rchunk_t glyphck;
547
548 rc = riff_rchunk_list_match(parent, LTYPE_glph, &glyphck);
549 if (rc != EOK)
550 goto error;
551
552 rc = gfx_glyph_metrics_load(&glyphck, &metrics);
553 if (rc != EOK)
554 goto error;
555
556 rc = gfx_glyph_create(font, &metrics, &glyph);
557 if (rc != EOK)
558 goto error;
559
560 rc = gfx_glyph_patterns_load(&glyphck, glyph);
561 if (rc != EOK)
562 goto error;
563
564 rc = gfx_glyph_rectangle_origin_load(&glyphck, glyph);
565 if (rc != EOK)
566 goto error;
567
568 rc = riff_rchunk_end(&glyphck);
569 if (rc != EOK)
570 goto error;
571
572 return EOK;
573error:
574 if (glyph != NULL)
575 gfx_glyph_destroy(glyph);
576 return rc;
577}
578
579/** Save glyph into RIFF TPF file.
580 *
581 * @param glyph Glyph
582 * @param riffw RIFF writer
583 * @return EOK on success or an error code
584 */
585errno_t gfx_glyph_save(gfx_glyph_t *glyph, riffw_t *riffw)
586{
587 errno_t rc;
588 riff_wchunk_t glyphck;
589
590 rc = riff_wchunk_start(riffw, CKID_LIST, &glyphck);
591 if (rc != EOK)
592 return rc;
593
594 rc = riff_write_uint32(riffw, LTYPE_glph);
595 if (rc != EOK)
596 return rc;
597
598 rc = gfx_glyph_metrics_save(&glyph->metrics, riffw);
599 if (rc != EOK)
600 return rc;
601
602 rc = gfx_glyph_patterns_save(glyph, riffw);
603 if (rc != EOK)
604 return rc;
605
606 rc = gfx_glyph_rectangle_origin_save(glyph, riffw);
607 if (rc != EOK)
608 return rc;
609
610 rc = riff_wchunk_end(riffw, &glyphck);
611 if (rc != EOK)
612 return rc;
613
614 return EOK;
615}
616
617/** @}
618 */
Note: See TracBrowser for help on using the repository browser.