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

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

gfx_glyph_transfer still not transferring the correct rectangle

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