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

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

Glyph background pixels need keying out using color key

  • Property mode set to 100644
File size: 20.5 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 Font
34 */
35
36#include <adt/list.h>
37#include <assert.h>
38#include <byteorder.h>
39#include <errno.h>
40#include <gfx/bitmap.h>
41#include <gfx/font.h>
42#include <gfx/glyph.h>
43#include <mem.h>
44#include <stdlib.h>
45#include "../private/font.h"
46#include "../private/glyph.h"
47#include "../private/tpf_file.h"
48#include "../private/typeface.h"
49
50/** Initialize font metrics structure.
51 *
52 * Font metrics structure must always be initialized using this function
53 * first.
54 *
55 * @param metrics Font metrics structure
56 */
57void gfx_font_metrics_init(gfx_font_metrics_t *metrics)
58{
59 memset(metrics, 0, sizeof(gfx_font_metrics_t));
60}
61
62/** Initialize font properties structure.
63 *
64 * Font properties structure must always be initialized using this function
65 * first.
66 *
67 * @param props Font properties structure
68 */
69void gfx_font_props_init(gfx_font_props_t *props)
70{
71 memset(props, 0, sizeof(gfx_font_props_t));
72}
73
74/** Get font properties.
75 *
76 * @param finfo Font info
77 * @param props Place to store font properties
78 */
79void gfx_font_get_props(gfx_font_info_t *finfo, gfx_font_props_t *props)
80{
81 *props = finfo->props;
82}
83
84/** Create font with existing font info structure.
85 *
86 * @param tface Typeface
87 * @param finfo Font info
88 * @param metrics Font metrics
89 * @param rfont Place to store pointer to new font
90 *
91 * @return EOK on success, EINVAL if parameters are invald,
92 * ENOMEM if insufficient resources, EIO if graphic device connection
93 * was lost
94 */
95static errno_t gfx_font_create_with_info(gfx_typeface_t *tface,
96 gfx_font_info_t *finfo, gfx_font_metrics_t *metrics, gfx_font_t **rfont)
97{
98 gfx_font_t *font = NULL;
99 gfx_bitmap_params_t params;
100 errno_t rc;
101
102 font = calloc(1, sizeof(gfx_font_t));
103 if (font == NULL) {
104 rc = ENOMEM;
105 goto error;
106 }
107 font->typeface = tface;
108 font->finfo = finfo;
109
110 font->rect.p0.x = 0;
111 font->rect.p0.y = 0;
112 font->rect.p1.x = 1;
113 font->rect.p1.y = 1;
114
115 rc = gfx_font_set_metrics(font, metrics);
116 if (rc != EOK) {
117 assert(rc == EINVAL);
118 goto error;
119 }
120
121 /* Create font bitmap */
122 gfx_bitmap_params_init(&params);
123 params.rect = font->rect;
124 params.flags = bmpf_color_key;
125 params.key_color = PIXEL(0, 0, 0, 0);
126
127 rc = gfx_bitmap_create(tface->gc, &params, NULL, &font->bitmap);
128 if (rc != EOK)
129 goto error;
130
131 font->metrics = *metrics;
132 list_initialize(&font->glyphs);
133 *rfont = font;
134 return EOK;
135error:
136 if (font != NULL)
137 free(font);
138 return rc;
139}
140
141/** Create font.
142 *
143 * @param tface Typeface
144 * @param props Font properties
145 * @param metrics Font metrics
146 * @param rfont Place to store pointer to new font
147 *
148 * @return EOK on success, EINVAL if parameters are invald,
149 * ENOMEM if insufficient resources, EIO if graphic device connection
150 * was lost
151 */
152errno_t gfx_font_create(gfx_typeface_t *tface, gfx_font_props_t *props,
153 gfx_font_metrics_t *metrics, gfx_font_t **rfont)
154{
155 gfx_font_info_t *finfo = NULL;
156 gfx_font_t *font = NULL;
157 errno_t rc;
158
159 finfo = calloc(1, sizeof(gfx_font_info_t));
160 if (finfo == NULL) {
161 rc = ENOMEM;
162 goto error;
163 }
164
165 finfo->typeface = tface;
166 finfo->props = *props;
167
168 rc = gfx_font_create_with_info(tface, finfo, metrics, &font);
169 if (rc != EOK)
170 goto error;
171
172 finfo->font = font;
173 list_append(&finfo->lfonts, &tface->fonts);
174 *rfont = font;
175 return EOK;
176error:
177 if (finfo != NULL)
178 free(finfo);
179 return rc;
180}
181
182/** Open font.
183 *
184 * @param finfo Font info
185 * @param rfont Place to store pointer to open font
186 * @return EOK on success or an error code
187 */
188errno_t gfx_font_open(gfx_font_info_t *finfo, gfx_font_t **rfont)
189{
190 errno_t rc;
191
192 if (finfo->font == NULL) {
193 /* Load absent font from TPF file */
194 rc = gfx_font_load(finfo);
195 if (rc != EOK)
196 return rc;
197
198 assert(finfo->font != NULL);
199 finfo->font->finfo = finfo;
200 }
201
202 *rfont = finfo->font;
203 return EOK;
204}
205
206/** Close font.
207 *
208 * @param font Font
209 */
210void gfx_font_close(gfx_font_t *font)
211{
212 gfx_glyph_t *glyph;
213
214 glyph = gfx_font_first_glyph(font);
215 while (glyph != NULL) {
216 gfx_glyph_destroy(glyph);
217 glyph = gfx_font_first_glyph(font);
218 }
219
220 font->finfo->font = NULL;
221 free(font);
222}
223
224/** Get font metrics.
225 *
226 * @param font Font
227 * @param metrics Place to store metrics
228 */
229void gfx_font_get_metrics(gfx_font_t *font, gfx_font_metrics_t *metrics)
230{
231 *metrics = font->metrics;
232}
233
234/** Set font metrics.
235 *
236 * @param font Font
237 * @param metrics Place to store metrics
238 * @return EOK on success, EINVAL if supplied metrics are invalid
239 */
240errno_t gfx_font_set_metrics(gfx_font_t *font, gfx_font_metrics_t *metrics)
241{
242 font->metrics = *metrics;
243 return EOK;
244}
245
246/** Get first glyph in font.
247 *
248 * @param font Font
249 * @return First glyph or @c NULL if there are none
250 */
251gfx_glyph_t *gfx_font_first_glyph(gfx_font_t *font)
252{
253 link_t *link;
254
255 link = list_first(&font->glyphs);
256 if (link == NULL)
257 return NULL;
258
259 return list_get_instance(link, gfx_glyph_t, lglyphs);
260}
261
262/** Get next glyph in font.
263 *
264 * @param cur Current glyph
265 * @return Next glyph in font or @c NULL if @a cur was the last one
266 */
267gfx_glyph_t *gfx_font_next_glyph(gfx_glyph_t *cur)
268{
269 link_t *link;
270
271 link = list_next(&cur->lglyphs, &cur->font->glyphs);
272 if (link == NULL)
273 return NULL;
274
275 return list_get_instance(link, gfx_glyph_t, lglyphs);
276}
277
278/** Get last glyph in font.
279 *
280 * @param font Font
281 * @return Last glyph or @c NULL if there are none
282 */
283gfx_glyph_t *gfx_font_last_glyph(gfx_font_t *font)
284{
285 link_t *link;
286
287 link = list_last(&font->glyphs);
288 if (link == NULL)
289 return NULL;
290
291 return list_get_instance(link, gfx_glyph_t, lglyphs);
292}
293
294/** Get previous glyph in font.
295 *
296 * @param cur Current glyph
297 * @return Previous glyph in font or @c NULL if @a cur was the last one
298 */
299gfx_glyph_t *gfx_font_prev_glyph(gfx_glyph_t *cur)
300{
301 link_t *link;
302
303 link = list_prev(&cur->lglyphs, &cur->font->glyphs);
304 if (link == NULL)
305 return NULL;
306
307 return list_get_instance(link, gfx_glyph_t, lglyphs);
308}
309
310/** Search for glyph that should be set for the beginning of a string.
311 *
312 * @param font Font
313 * @param str String whose beginning we would like to set
314 * @param rglyph Place to store glyph that should be set
315 * @param rsize Place to store number of bytes to advance in the string
316 * @return EOK on success, ENOENT if no matching glyph was found
317 */
318errno_t gfx_font_search_glyph(gfx_font_t *font, const char *str,
319 gfx_glyph_t **rglyph, size_t *rsize)
320{
321 gfx_glyph_t *glyph;
322 size_t msize;
323
324 glyph = gfx_font_first_glyph(font);
325 while (glyph != NULL) {
326 if (gfx_glyph_matches(glyph, str, &msize)) {
327 *rglyph = glyph;
328 *rsize = msize;
329 return EOK;
330 }
331
332 glyph = gfx_font_next_glyph(glyph);
333 }
334
335 return ENOENT;
336}
337
338/** Replace glyph graphic with empty space of specified width.
339 *
340 * This is used to resize a glyph in the font bitmap. This changes
341 * the bitmap widht might also make the bitmap taller.
342 * Dimensions of the glyph are also adjusted according to @a nrect.
343 *
344 * @param font Font
345 * @param glyph Glyph to replace
346 * @param nrect Replacement rectangle
347 */
348errno_t gfx_font_splice_at_glyph(gfx_font_t *font, gfx_glyph_t *glyph,
349 gfx_rect_t *nrect)
350{
351 gfx_glyph_t *g;
352 gfx_bitmap_t *nbitmap;
353 gfx_bitmap_params_t params;
354 gfx_coord_t dwidth;
355 gfx_coord_t x0;
356 errno_t rc;
357
358 /* Change of width of glyph */
359 dwidth = (nrect->p1.x - nrect->p0.x) -
360 (glyph->rect.p1.x - glyph->rect.p0.x);
361
362 /* Create new font bitmap, wider by dwidth pixels */
363 gfx_bitmap_params_init(&params);
364 params.rect = font->rect;
365 params.rect.p1.x += dwidth;
366 if (nrect->p1.y - nrect->p0.y > params.rect.p1.y)
367 params.rect.p1.y = nrect->p1.y - nrect->p0.y;
368 params.flags = bmpf_color_key;
369 params.key_color = PIXEL(0, 0, 0, 0);
370
371 rc = gfx_bitmap_create(font->typeface->gc, &params, NULL, &nbitmap);
372 if (rc != EOK)
373 goto error;
374
375 /*
376 * In x0 we compute the left margin of @a glyph. We start with
377 * zero and then, if there are any preceding glyphs, we set it
378 * to the right margin of the last one.
379 */
380 x0 = 0;
381
382 /* Transfer glyphs before @a glyph */
383 g = gfx_font_first_glyph(font);
384 while (g != glyph) {
385 assert(g != NULL);
386
387 rc = gfx_glyph_transfer(g, 0, nbitmap, &params.rect);
388 if (rc != EOK)
389 goto error;
390
391 /* Left margin of the next glyph */
392 x0 = g->rect.p1.x;
393
394 g = gfx_font_next_glyph(g);
395 }
396
397 /* Skip @a glyph */
398 g = gfx_font_next_glyph(g);
399
400 /* Transfer glyphs after glyph */
401 while (g != NULL) {
402 rc = gfx_glyph_transfer(g, dwidth, nbitmap, &params.rect);
403 if (rc != EOK)
404 goto error;
405
406 /* Update glyph coordinates */
407 g->rect.p0.x += dwidth;
408 g->rect.p1.x += dwidth;
409 g->origin.x += dwidth;
410
411 g = gfx_font_next_glyph(g);
412 }
413
414 /* Place glyph rectangle inside the newly created space */
415 glyph->origin.x = x0 - nrect->p0.x;
416 glyph->origin.y = 0 - nrect->p0.y;
417 gfx_rect_translate(&glyph->origin, nrect, &glyph->rect);
418
419 /* Update font bitmap */
420 gfx_bitmap_destroy(font->bitmap);
421 font->bitmap = nbitmap;
422 font->rect = params.rect;
423
424 return EOK;
425error:
426 if (nbitmap != NULL)
427 gfx_bitmap_destroy(nbitmap);
428 return rc;
429}
430
431/** Load font properties from RIFF TPF file.
432 *
433 * @param parent Parent chunk
434 * @param props Font properties
435 * @return EOK on success or an error code
436 */
437static errno_t gfx_font_props_load(riff_rchunk_t *parent,
438 gfx_font_props_t *props)
439{
440 errno_t rc;
441 riff_rchunk_t propsck;
442 tpf_font_props_t tprops;
443 size_t nread;
444
445 rc = riff_rchunk_match(parent, CKID_fprp, &propsck);
446 if (rc != EOK)
447 return rc;
448
449 rc = riff_read(&propsck, (void *) &tprops, sizeof(tprops), &nread);
450 if (rc != EOK || nread != sizeof(tprops))
451 return EIO;
452
453 rc = riff_rchunk_end(&propsck);
454 if (rc != EOK)
455 return rc;
456
457 props->size = uint16_t_le2host(tprops.size);
458 props->flags = uint16_t_le2host(tprops.flags);
459
460 return EOK;
461}
462
463/** Save font properties to RIFF TPF file.
464 *
465 * @param props Font properties
466 * @param riffw RIFF writer
467 * @return EOK on success or an error code
468 */
469static errno_t gfx_font_props_save(gfx_font_props_t *props, riffw_t *riffw)
470{
471 errno_t rc;
472 riff_wchunk_t propsck;
473 tpf_font_props_t tprops;
474
475 tprops.size = host2uint16_t_le(props->size);
476 tprops.flags = host2uint16_t_le(props->flags);
477
478 rc = riff_wchunk_start(riffw, CKID_fprp, &propsck);
479 if (rc != EOK)
480 return rc;
481
482 rc = riff_write(riffw, (void *) &tprops, sizeof(tprops));
483 if (rc != EOK)
484 return rc;
485
486 rc = riff_wchunk_end(riffw, &propsck);
487 if (rc != EOK)
488 return rc;
489
490 return EOK;
491}
492
493/** Load font metrics from RIFF TPF file.
494 *
495 * @param parent Parent chunk
496 * @param metrics Font metrics
497 * @return EOK on success or an error code
498 */
499static errno_t gfx_font_metrics_load(riff_rchunk_t *parent,
500 gfx_font_metrics_t *metrics)
501{
502 errno_t rc;
503 riff_rchunk_t mtrck;
504 tpf_font_metrics_t tmetrics;
505 size_t nread;
506
507 rc = riff_rchunk_match(parent, CKID_fmtr, &mtrck);
508 if (rc != EOK)
509 return rc;
510
511 rc = riff_read(&mtrck, (void *) &tmetrics, sizeof(tmetrics), &nread);
512 if (rc != EOK || nread != sizeof(tmetrics))
513 return EIO;
514
515 rc = riff_rchunk_end(&mtrck);
516 if (rc != EOK)
517 return rc;
518
519 metrics->ascent = uint16_t_le2host(tmetrics.ascent);
520 metrics->descent = uint16_t_le2host(tmetrics.descent);
521 metrics->leading = uint16_t_le2host(tmetrics.leading);
522 return EOK;
523}
524
525/** Save font metrics to RIFF TPF file.
526 *
527 * @param metrics Font metrics
528 * @param riffw RIFF writer
529 * @return EOK on success or an error code
530 */
531static errno_t gfx_font_metrics_save(gfx_font_metrics_t *metrics,
532 riffw_t *riffw)
533{
534 errno_t rc;
535 tpf_font_metrics_t tmetrics;
536 riff_wchunk_t mtrck;
537
538 tmetrics.ascent = host2uint16_t_le(metrics->ascent);
539 tmetrics.descent = host2uint16_t_le(metrics->descent);
540 tmetrics.leading = host2uint16_t_le(metrics->leading);
541
542 rc = riff_wchunk_start(riffw, CKID_fmtr, &mtrck);
543 if (rc != EOK)
544 return rc;
545
546 rc = riff_write(riffw, (void *) &tmetrics, sizeof(tmetrics));
547 if (rc != EOK)
548 return rc;
549
550 rc = riff_wchunk_end(riffw, &mtrck);
551 if (rc != EOK)
552 return rc;
553
554 return EOK;
555}
556
557/** Bit pack font bitmap into 1 bits/pixel format.
558 *
559 * @param width Bitmap width
560 * @param height Bitmap height
561 * @param pixels Bitmap pixels
562 * @param rdata Place to store pointer to packed data
563 * @param rsize Place to store size of packed data
564 * @return EOK on sucess, ENOMEM if out of memory
565 */
566errno_t gfx_font_bitmap_pack(gfx_coord_t width, gfx_coord_t height,
567 uint32_t *pixels, void **rdata, size_t *rsize)
568{
569 void *data;
570 size_t size;
571 size_t bytes_line;
572 gfx_coord_t x, y;
573 uint8_t b;
574 uint8_t *dp;
575 uint32_t *sp;
576 uint32_t pix;
577
578 bytes_line = (width + 7) / 8;
579 size = height * bytes_line;
580
581 data = malloc(size);
582 if (data == NULL)
583 return ENOMEM;
584
585 sp = pixels;
586 dp = data;
587 for (y = 0; y < height; y++) {
588 b = 0;
589 for (x = 0; x < width; x++) {
590 pix = *sp++;
591 b = (b << 1) | (pix & 1);
592 /* Write eight bits */
593 if ((x & 7) == 7) {
594 *dp++ = b;
595 b = 0;
596 }
597 }
598
599 /* Write remaining bits */
600 if ((x & 7) != 0) {
601 b = b << (8 - (x & 7));
602 *dp++ = b;
603 }
604 }
605
606 *rdata = data;
607 *rsize = size;
608 return EOK;
609}
610
611/** Unpack font bitmap from 1 bits/pixel format.
612 *
613 * @param width Bitmap width
614 * @param height Bitmap height
615 * @param data Packed data
616 * @param dsize Size of packed data
617 * @param pixels Bitmap pixels
618 * @return EOK on success, EINVAL if data size is invalid
619 */
620errno_t gfx_font_bitmap_unpack(gfx_coord_t width, gfx_coord_t height,
621 void *data, size_t dsize, uint32_t *pixels)
622{
623 size_t size;
624 size_t bytes_line;
625 gfx_coord_t x, y;
626 uint8_t b;
627 uint8_t *sp;
628 uint32_t *dp;
629
630 bytes_line = (width + 7) / 8;
631 size = height * bytes_line;
632
633 if (dsize != size)
634 return EINVAL;
635
636 sp = data;
637 dp = pixels;
638 for (y = 0; y < height; y++) {
639 b = 0;
640 for (x = 0; x < width; x++) {
641 if ((x & 7) == 0)
642 b = *sp++;
643 *dp++ = (b >> 7) ? PIXEL(255, 255, 255, 255) :
644 PIXEL(0, 0, 0, 0);
645 b = b << 1;
646 }
647 }
648
649 return EOK;
650}
651
652/** Load font bitmap from RIFF TPF file.
653 *
654 * @param parent Parent chunk
655 * @param font Font
656 * @return EOK on success or an error code
657 */
658static errno_t gfx_font_bitmap_load(riff_rchunk_t *parent, gfx_font_t *font)
659{
660 errno_t rc;
661 riff_rchunk_t bmpck;
662 tpf_font_bmp_hdr_t thdr;
663 gfx_bitmap_params_t params;
664 gfx_bitmap_alloc_t alloc;
665 gfx_bitmap_t *bitmap = NULL;
666 uint32_t width;
667 uint32_t height;
668 uint16_t fmt;
669 uint16_t depth;
670 size_t bytes_line;
671 void *data = NULL;
672 size_t size;
673 size_t nread;
674
675 rc = riff_rchunk_match(parent, CKID_fbmp, &bmpck);
676 if (rc != EOK)
677 goto error;
678
679 rc = riff_read(&bmpck, &thdr, sizeof(thdr), &nread);
680 if (rc != EOK || nread != sizeof(thdr))
681 goto error;
682
683 width = uint32_t_le2host(thdr.width);
684 height = uint32_t_le2host(thdr.height);
685 fmt = uint16_t_le2host(thdr.fmt);
686 depth = uint16_t_le2host(thdr.depth);
687
688 if (fmt != 0 || depth != 1) {
689 rc = ENOTSUP;
690 goto error;
691 }
692
693 bytes_line = (width + 7) / 8;
694 size = height * bytes_line;
695
696 data = malloc(size);
697 if (data == NULL) {
698 rc = ENOMEM;
699 goto error;
700 }
701
702 gfx_bitmap_params_init(&params);
703 params.rect.p0.x = 0;
704 params.rect.p0.y = 0;
705 params.rect.p1.x = width;
706 params.rect.p1.y = height;
707 params.flags = bmpf_color_key;
708 params.key_color = PIXEL(0, 0, 0, 0);
709
710 rc = gfx_bitmap_create(font->typeface->gc, &params, NULL, &bitmap);
711 if (rc != EOK)
712 goto error;
713
714 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
715 if (rc != EOK)
716 goto error;
717
718 rc = riff_read(&bmpck, data, size, &nread);
719 if (rc != EOK)
720 goto error;
721
722 if (nread != size) {
723 rc = EIO;
724 goto error;
725 }
726
727 rc = riff_rchunk_end(&bmpck);
728 if (rc != EOK)
729 goto error;
730
731 rc = gfx_font_bitmap_unpack(width, height, data, size, alloc.pixels);
732 if (rc != EOK)
733 goto error;
734
735 free(data);
736 gfx_bitmap_destroy(font->bitmap);
737 font->bitmap = bitmap;
738 font->rect = params.rect;
739 return EOK;
740error:
741 if (data != NULL)
742 free(data);
743 if (bitmap != NULL)
744 gfx_bitmap_destroy(bitmap);
745 return rc;
746}
747
748/** Save font bitmap to RIFF TPF file.
749 *
750 * @param font Font
751 * @param riffw RIFF writer
752 * @return EOK on success or an error code
753 */
754static errno_t gfx_font_bitmap_save(gfx_font_t *font, riffw_t *riffw)
755{
756 errno_t rc;
757 tpf_font_bmp_hdr_t thdr;
758 riff_wchunk_t bmpck;
759 gfx_bitmap_alloc_t alloc;
760 void *data = NULL;
761 size_t dsize;
762
763 rc = gfx_bitmap_get_alloc(font->bitmap, &alloc);
764 if (rc != EOK)
765 return rc;
766
767 rc = gfx_font_bitmap_pack(font->rect.p1.x, font->rect.p1.y,
768 alloc.pixels, &data, &dsize);
769 if (rc != EOK)
770 return rc;
771
772 thdr.width = host2uint32_t_le(font->rect.p1.x);
773 thdr.height = host2uint32_t_le(font->rect.p1.y);
774 thdr.fmt = 0;
775 thdr.depth = host2uint16_t_le(1);
776
777 rc = riff_wchunk_start(riffw, CKID_fbmp, &bmpck);
778 if (rc != EOK)
779 goto error;
780
781 rc = riff_write(riffw, &thdr, sizeof(thdr));
782 if (rc != EOK)
783 goto error;
784
785 rc = riff_write(riffw, data, dsize);
786 if (rc != EOK)
787 goto error;
788
789 rc = riff_wchunk_end(riffw, &bmpck);
790 if (rc != EOK)
791 goto error;
792
793 free(data);
794 return EOK;
795error:
796 if (data != NULL)
797 free(data);
798 return rc;
799}
800
801/** Load font info from RIFF TPF file.
802 *
803 * @param tface Containing typeface
804 * @param parent Parent chunk
805 * @return EOK on success or an error code
806 */
807errno_t gfx_font_info_load(gfx_typeface_t *tface, riff_rchunk_t *parent)
808{
809 errno_t rc;
810 riff_rchunk_t fontck;
811 gfx_font_props_t props;
812 gfx_font_info_t *finfo = NULL;
813 gfx_font_t *font = NULL;
814
815 rc = riff_rchunk_list_match(parent, LTYPE_font, &fontck);
816 if (rc != EOK)
817 goto error;
818
819 finfo = calloc(1, sizeof(gfx_font_info_t));
820 if (finfo == NULL) {
821 rc = ENOMEM;
822 goto error;
823 }
824
825 finfo->fontck = fontck;
826
827 rc = gfx_font_props_load(&fontck, &props);
828 if (rc != EOK)
829 goto error;
830
831 rc = riff_rchunk_end(&fontck);
832 if (rc != EOK)
833 goto error;
834
835 finfo->typeface = tface;
836 list_append(&finfo->lfonts, &tface->fonts);
837 finfo->props = props;
838 finfo->font = NULL;
839
840 return EOK;
841error:
842 if (finfo != NULL)
843 free(finfo);
844 if (font != NULL)
845 gfx_font_close(font);
846 return rc;
847}
848
849/** Load font from RIFF TPF file.
850 *
851 * @param finfo Font information
852 * @return EOK on success or an error code
853 */
854errno_t gfx_font_load(gfx_font_info_t *finfo)
855{
856 errno_t rc;
857 gfx_font_metrics_t metrics;
858 gfx_font_t *font = NULL;
859
860 /* Seek to beginning of chunk (just after list type) */
861 rc = riff_rchunk_seek(&finfo->fontck, sizeof(uint32_t), SEEK_SET);
862 if (rc != EOK)
863 goto error;
864
865 rc = gfx_font_props_load(&finfo->fontck, &finfo->props);
866 if (rc != EOK)
867 goto error;
868
869 rc = gfx_font_metrics_load(&finfo->fontck, &metrics);
870 if (rc != EOK)
871 goto error;
872
873 rc = gfx_font_create_with_info(finfo->typeface, finfo, &metrics, &font);
874 if (rc != EOK)
875 goto error;
876
877 rc = gfx_font_bitmap_load(&finfo->fontck, font);
878 if (rc != EOK)
879 goto error;
880
881 while (true) {
882 rc = gfx_glyph_load(font, &finfo->fontck);
883 if (rc == ENOENT)
884 break;
885 if (rc != EOK)
886 goto error;
887 }
888
889 finfo->font = font;
890 return EOK;
891error:
892 if (font != NULL)
893 gfx_font_close(font);
894 return rc;
895}
896
897/** Save font into RIFF TPF file.
898 *
899 * @param finfo Font info
900 * @param riffw RIFF writer
901 * @return EOK on success or an error code
902 */
903errno_t gfx_font_save(gfx_font_info_t *finfo, riffw_t *riffw)
904{
905 errno_t rc;
906 riff_wchunk_t fontck;
907 gfx_glyph_t *glyph;
908
909 rc = riff_wchunk_start(riffw, CKID_LIST, &fontck);
910 if (rc != EOK)
911 return rc;
912
913 rc = riff_write_uint32(riffw, LTYPE_font);
914 if (rc != EOK)
915 return rc;
916
917 rc = gfx_font_props_save(&finfo->props, riffw);
918 if (rc != EOK)
919 return rc;
920
921 rc = gfx_font_metrics_save(&finfo->font->metrics, riffw);
922 if (rc != EOK)
923 return rc;
924
925 rc = gfx_font_bitmap_save(finfo->font, riffw);
926 if (rc != EOK)
927 return rc;
928
929 glyph = gfx_font_first_glyph(finfo->font);
930 while (glyph != NULL) {
931 rc = gfx_glyph_save(glyph, riffw);
932 if (rc != EOK)
933 return rc;
934
935 glyph = gfx_font_next_glyph(glyph);
936 }
937
938 rc = riff_wchunk_end(riffw, &fontck);
939 if (rc != EOK)
940 return rc;
941
942 return EOK;
943}
944
945/** @}
946 */
Note: See TracBrowser for help on using the repository browser.