source: mainline/uspace/lib/gfxfont/src/font.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: 17.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
125 rc = gfx_bitmap_create(tface->gc, &params, NULL, &font->bitmap);
126 if (rc != EOK)
127 goto error;
128
129 font->metrics = *metrics;
130 list_initialize(&font->glyphs);
131 *rfont = font;
132 return EOK;
133error:
134 if (font != NULL)
135 free(font);
136 return rc;
137}
138
139/** Create font.
140 *
141 * @param tface Typeface
142 * @param props Font properties
143 * @param metrics Font metrics
144 * @param rfont Place to store pointer to new font
145 *
146 * @return EOK on success, EINVAL if parameters are invald,
147 * ENOMEM if insufficient resources, EIO if graphic device connection
148 * was lost
149 */
150errno_t gfx_font_create(gfx_typeface_t *tface, gfx_font_props_t *props,
151 gfx_font_metrics_t *metrics, gfx_font_t **rfont)
152{
153 gfx_font_info_t *finfo = NULL;
154 gfx_font_t *font = NULL;
155 errno_t rc;
156
157 finfo = calloc(1, sizeof(gfx_font_info_t));
158 if (finfo == NULL) {
159 rc = ENOMEM;
160 goto error;
161 }
162
163 finfo->typeface = tface;
164 finfo->props = *props;
165
166 rc = gfx_font_create_with_info(tface, finfo, metrics, &font);
167 if (rc != EOK)
168 goto error;
169
170 finfo->font = font;
171 list_append(&finfo->lfonts, &tface->fonts);
172 *rfont = font;
173 return EOK;
174error:
175 if (finfo != NULL)
176 free(finfo);
177 return rc;
178}
179
180/** Open font.
181 *
182 * @param finfo Font info
183 * @param rfont Place to store pointer to open font
184 * @return EOK on success or an error code
185 */
186errno_t gfx_font_open(gfx_font_info_t *finfo, gfx_font_t **rfont)
187{
188 errno_t rc;
189
190 if (finfo->font == NULL) {
191 /* Load absent font from TPF file */
192 rc = gfx_font_load(finfo);
193 if (rc != EOK)
194 return rc;
195
196 assert(finfo->font != NULL);
197 finfo->font->finfo = finfo;
198 }
199
200 *rfont = finfo->font;
201 return EOK;
202}
203
204/** Close font.
205 *
206 * @param font Font
207 */
208void gfx_font_close(gfx_font_t *font)
209{
210 gfx_glyph_t *glyph;
211
212 glyph = gfx_font_first_glyph(font);
213 while (glyph != NULL) {
214 gfx_glyph_destroy(glyph);
215 glyph = gfx_font_first_glyph(font);
216 }
217
218 font->finfo->font = NULL;
219 free(font);
220}
221
222/** Get font metrics.
223 *
224 * @param font Font
225 * @param metrics Place to store metrics
226 */
227void gfx_font_get_metrics(gfx_font_t *font, gfx_font_metrics_t *metrics)
228{
229 *metrics = font->metrics;
230}
231
232/** Set font metrics.
233 *
234 * @param font Font
235 * @param metrics Place to store metrics
236 * @return EOK on success, EINVAL if supplied metrics are invalid
237 */
238errno_t gfx_font_set_metrics(gfx_font_t *font, gfx_font_metrics_t *metrics)
239{
240 font->metrics = *metrics;
241 return EOK;
242}
243
244/** Get first glyph in font.
245 *
246 * @param font Font
247 * @return First glyph or @c NULL if there are none
248 */
249gfx_glyph_t *gfx_font_first_glyph(gfx_font_t *font)
250{
251 link_t *link;
252
253 link = list_first(&font->glyphs);
254 if (link == NULL)
255 return NULL;
256
257 return list_get_instance(link, gfx_glyph_t, lglyphs);
258}
259
260/** Get next glyph in font.
261 *
262 * @param cur Current glyph
263 * @return Next glyph in font or @c NULL if @a cur was the last one
264 */
265gfx_glyph_t *gfx_font_next_glyph(gfx_glyph_t *cur)
266{
267 link_t *link;
268
269 link = list_next(&cur->lglyphs, &cur->font->glyphs);
270 if (link == NULL)
271 return NULL;
272
273 return list_get_instance(link, gfx_glyph_t, lglyphs);
274}
275
276/** Search for glyph that should be set for the beginning of a string.
277 *
278 * @param font Font
279 * @param str String whose beginning we would like to set
280 * @param rglyph Place to store glyph that should be set
281 * @param rsize Place to store number of bytes to advance in the string
282 * @return EOK on success, ENOENT if no matching glyph was found
283 */
284errno_t gfx_font_search_glyph(gfx_font_t *font, const char *str,
285 gfx_glyph_t **rglyph, size_t *rsize)
286{
287 gfx_glyph_t *glyph;
288 size_t msize;
289
290 glyph = gfx_font_first_glyph(font);
291 while (glyph != NULL) {
292 if (gfx_glyph_matches(glyph, str, &msize)) {
293 *rglyph = glyph;
294 *rsize = msize;
295 return EOK;
296 }
297
298 glyph = gfx_font_next_glyph(glyph);
299 }
300
301 return ENOENT;
302}
303
304/** Replace glyph graphic with empty space of specified width.
305 *
306 * This is used to resize a glyph in the font bitmap. This changes
307 * the bitmap widht might also make the bitmap taller.
308 * Dimensions of the glyph are also adjusted according to @a nrect.
309 *
310 * @param font Font
311 * @param glyph Glyph to replace
312 * @param nrect Replacement rectangle
313 */
314errno_t gfx_font_splice_at_glyph(gfx_font_t *font, gfx_glyph_t *glyph,
315 gfx_rect_t *nrect)
316{
317 gfx_glyph_t *g;
318 gfx_bitmap_t *nbitmap;
319 gfx_bitmap_params_t params;
320 gfx_coord_t dwidth;
321 gfx_coord_t x0;
322 errno_t rc;
323
324 /* Change of width of glyph */
325 dwidth = (nrect->p1.x - nrect->p0.x) -
326 (glyph->rect.p1.x - glyph->rect.p0.x);
327
328 /* Create new font bitmap, wider by dwidth pixels */
329 gfx_bitmap_params_init(&params);
330 params.rect = font->rect;
331 params.rect.p1.x += dwidth;
332 if (nrect->p1.y - nrect->p0.y > params.rect.p1.y)
333 params.rect.p1.y = nrect->p1.y - nrect->p0.y;
334
335 rc = gfx_bitmap_create(font->typeface->gc, &params, NULL, &nbitmap);
336 if (rc != EOK)
337 goto error;
338
339 /*
340 * In x0 we compute the left margin of @a glyph. We start with
341 * zero and then, if there are any preceding glyphs, we set it
342 * to the right margin of the last one.
343 */
344 x0 = 0;
345
346 /* Transfer glyphs before @a glyph */
347 g = gfx_font_first_glyph(font);
348 while (g != glyph) {
349 assert(g != NULL);
350
351 rc = gfx_glyph_transfer(g, 0, nbitmap, &params.rect);
352 if (rc != EOK)
353 goto error;
354
355 /* Left margin of the next glyph */
356 x0 = g->rect.p1.x;
357
358 g = gfx_font_next_glyph(g);
359 }
360
361 /* Skip @a glyph */
362 g = gfx_font_next_glyph(g);
363
364 /* Transfer glyphs after glyph */
365 while (g != NULL) {
366 rc = gfx_glyph_transfer(g, dwidth, nbitmap, &params.rect);
367 if (rc != EOK)
368 goto error;
369
370 /* Update glyph coordinates */
371 g->rect.p0.x += dwidth;
372 g->rect.p1.x += dwidth;
373 g->origin.x += dwidth;
374
375 g = gfx_font_next_glyph(g);
376 }
377
378 /* Place glyph rectangle inside the newly created space */
379 glyph->origin.x = x0 - nrect->p0.x;
380 glyph->origin.y = 0 - nrect->p0.y;
381 gfx_rect_translate(&glyph->origin, nrect, &glyph->rect);
382
383 /* Update font bitmap */
384 gfx_bitmap_destroy(font->bitmap);
385 font->bitmap = nbitmap;
386 font->rect = params.rect;
387
388 return EOK;
389error:
390 if (nbitmap != NULL)
391 gfx_bitmap_destroy(nbitmap);
392 return rc;
393}
394
395/** Load font properties from RIFF TPF file.
396 *
397 * @param parent Parent chunk
398 * @param props Font properties
399 * @return EOK on success or an error code
400 */
401static errno_t gfx_font_props_load(riff_rchunk_t *parent,
402 gfx_font_props_t *props)
403{
404 errno_t rc;
405 riff_rchunk_t propsck;
406 tpf_font_props_t tprops;
407 size_t nread;
408
409 rc = riff_rchunk_match(parent, CKID_fprp, &propsck);
410 if (rc != EOK)
411 return rc;
412
413 rc = riff_read(&propsck, (void *) &tprops, sizeof(tprops), &nread);
414 if (rc != EOK || nread != sizeof(tprops))
415 return EIO;
416
417 rc = riff_rchunk_end(&propsck);
418 if (rc != EOK)
419 return rc;
420
421 props->size = uint16_t_le2host(tprops.size);
422 props->flags = uint16_t_le2host(tprops.flags);
423
424 return EOK;
425}
426
427/** Save font properties to RIFF TPF file.
428 *
429 * @param props Font properties
430 * @param riffw RIFF writer
431 * @return EOK on success or an error code
432 */
433static errno_t gfx_font_props_save(gfx_font_props_t *props, riffw_t *riffw)
434{
435 errno_t rc;
436 riff_wchunk_t propsck;
437 tpf_font_props_t tprops;
438
439 tprops.size = host2uint16_t_le(props->size);
440 tprops.flags = host2uint16_t_le(props->flags);
441
442 rc = riff_wchunk_start(riffw, CKID_fprp, &propsck);
443 if (rc != EOK)
444 return rc;
445
446 rc = riff_write(riffw, (void *) &tprops, sizeof(tprops));
447 if (rc != EOK)
448 return rc;
449
450 rc = riff_wchunk_end(riffw, &propsck);
451 if (rc != EOK)
452 return rc;
453
454 return EOK;
455}
456
457/** Load font metrics from RIFF TPF file.
458 *
459 * @param parent Parent chunk
460 * @param metrics Font metrics
461 * @return EOK on success or an error code
462 */
463static errno_t gfx_font_metrics_load(riff_rchunk_t *parent,
464 gfx_font_metrics_t *metrics)
465{
466 errno_t rc;
467 riff_rchunk_t mtrck;
468 tpf_font_metrics_t tmetrics;
469 size_t nread;
470
471 rc = riff_rchunk_match(parent, CKID_fmtr, &mtrck);
472 if (rc != EOK)
473 return rc;
474
475 rc = riff_read(&mtrck, (void *) &tmetrics, sizeof(tmetrics), &nread);
476 if (rc != EOK || nread != sizeof(tmetrics))
477 return EIO;
478
479 rc = riff_rchunk_end(&mtrck);
480 if (rc != EOK)
481 return rc;
482
483 metrics->ascent = uint16_t_le2host(tmetrics.ascent);
484 metrics->descent = uint16_t_le2host(tmetrics.descent);
485 metrics->leading = uint16_t_le2host(tmetrics.leading);
486 return EOK;
487}
488
489/** Save font metrics to RIFF TPF file.
490 *
491 * @param metrics Font metrics
492 * @param riffw RIFF writer
493 * @return EOK on success or an error code
494 */
495static errno_t gfx_font_metrics_save(gfx_font_metrics_t *metrics,
496 riffw_t *riffw)
497{
498 errno_t rc;
499 tpf_font_metrics_t tmetrics;
500 riff_wchunk_t mtrck;
501
502 tmetrics.ascent = host2uint16_t_le(metrics->ascent);
503 tmetrics.descent = host2uint16_t_le(metrics->descent);
504 tmetrics.leading = host2uint16_t_le(metrics->leading);
505
506 rc = riff_wchunk_start(riffw, CKID_fmtr, &mtrck);
507 if (rc != EOK)
508 return rc;
509
510 rc = riff_write(riffw, (void *) &tmetrics, sizeof(tmetrics));
511 if (rc != EOK)
512 return rc;
513
514 rc = riff_wchunk_end(riffw, &mtrck);
515 if (rc != EOK)
516 return rc;
517
518 return EOK;
519}
520
521/** Load font bitmap from RIFF TPF file.
522 *
523 * @param parent Parent chunk
524 * @param font Font
525 * @return EOK on success or an error code
526 */
527static errno_t gfx_font_bitmap_load(riff_rchunk_t *parent, gfx_font_t *font)
528{
529 errno_t rc;
530 riff_rchunk_t bmpck;
531 tpf_font_bmp_hdr_t thdr;
532 gfx_bitmap_params_t params;
533 gfx_bitmap_alloc_t alloc;
534 gfx_bitmap_t *bitmap = NULL;
535 uint32_t width;
536 uint32_t height;
537 uint16_t fmt;
538 uint16_t depth;
539 size_t nread;
540
541 rc = riff_rchunk_match(parent, CKID_fbmp, &bmpck);
542 if (rc != EOK)
543 goto error;
544
545 rc = riff_read(&bmpck, &thdr, sizeof(thdr), &nread);
546 if (rc != EOK || nread != sizeof(thdr))
547 goto error;
548
549 width = uint32_t_le2host(thdr.width);
550 height = uint32_t_le2host(thdr.height);
551 fmt = uint16_t_le2host(thdr.fmt);
552 depth = uint16_t_le2host(thdr.depth);
553
554 if (fmt != 0 || depth != 8 * sizeof(uint32_t)) {
555 rc = ENOTSUP;
556 goto error;
557 }
558
559 gfx_bitmap_params_init(&params);
560 params.rect.p0.x = 0;
561 params.rect.p0.y = 0;
562 params.rect.p1.x = width;
563 params.rect.p1.y = height;
564
565 rc = gfx_bitmap_create(font->typeface->gc, &params, NULL, &bitmap);
566 if (rc != EOK)
567 goto error;
568
569 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
570 if (rc != EOK)
571 goto error;
572
573 rc = riff_read(&bmpck, (void *) alloc.pixels,
574 width * height * sizeof(uint32_t), &nread);
575 if (rc != EOK)
576 goto error;
577
578 if (nread != width * height * sizeof(uint32_t)) {
579 rc = EIO;
580 goto error;
581 }
582
583 rc = riff_rchunk_end(&bmpck);
584 if (rc != EOK)
585 goto error;
586
587 gfx_bitmap_destroy(font->bitmap);
588 font->bitmap = bitmap;
589 font->rect = params.rect;
590 return EOK;
591error:
592 if (bitmap != NULL)
593 gfx_bitmap_destroy(bitmap);
594 return rc;
595}
596
597/** Save font bitmap to RIFF TPF file.
598 *
599 * @param font Font
600 * @param riffw RIFF writer
601 * @return EOK on success or an error code
602 */
603static errno_t gfx_font_bitmap_save(gfx_font_t *font, riffw_t *riffw)
604{
605 errno_t rc;
606 tpf_font_bmp_hdr_t thdr;
607 riff_wchunk_t bmpck;
608 gfx_bitmap_alloc_t alloc;
609
610 thdr.width = host2uint32_t_le(font->rect.p1.x);
611 thdr.height = host2uint32_t_le(font->rect.p1.y);
612 thdr.fmt = 0;
613 thdr.depth = host2uint16_t_le(8 * sizeof(uint32_t));
614
615 rc = gfx_bitmap_get_alloc(font->bitmap, &alloc);
616 if (rc != EOK)
617 return rc;
618
619 rc = riff_wchunk_start(riffw, CKID_fbmp, &bmpck);
620 if (rc != EOK)
621 return rc;
622
623 rc = riff_write(riffw, &thdr, sizeof(thdr));
624 if (rc != EOK)
625 return rc;
626
627 rc = riff_write(riffw, (void *) alloc.pixels,
628 font->rect.p1.x * font->rect.p1.y * sizeof(uint32_t));
629 if (rc != EOK)
630 return rc;
631
632 rc = riff_wchunk_end(riffw, &bmpck);
633 if (rc != EOK)
634 return rc;
635
636 return EOK;
637}
638
639/** Load font info from RIFF TPF file.
640 *
641 * @param tface Containing typeface
642 * @param parent Parent chunk
643 * @return EOK on success or an error code
644 */
645errno_t gfx_font_info_load(gfx_typeface_t *tface, riff_rchunk_t *parent)
646{
647 errno_t rc;
648 riff_rchunk_t fontck;
649 gfx_font_props_t props;
650 gfx_font_info_t *finfo = NULL;
651 gfx_font_t *font = NULL;
652
653 rc = riff_rchunk_list_match(parent, LTYPE_font, &fontck);
654 if (rc != EOK)
655 goto error;
656
657 finfo = calloc(1, sizeof(gfx_font_info_t));
658 if (finfo == NULL) {
659 rc = ENOMEM;
660 goto error;
661 }
662
663 finfo->fontck = fontck;
664
665 rc = gfx_font_props_load(&fontck, &props);
666 if (rc != EOK)
667 goto error;
668
669 rc = riff_rchunk_end(&fontck);
670 if (rc != EOK)
671 goto error;
672
673 finfo->typeface = tface;
674 list_append(&finfo->lfonts, &tface->fonts);
675 finfo->props = props;
676 finfo->font = NULL;
677
678 return EOK;
679error:
680 if (finfo != NULL)
681 free(finfo);
682 if (font != NULL)
683 gfx_font_close(font);
684 return rc;
685}
686
687/** Load font from RIFF TPF file.
688 *
689 * @param finfo Font information
690 * @return EOK on success or an error code
691 */
692errno_t gfx_font_load(gfx_font_info_t *finfo)
693{
694 errno_t rc;
695 gfx_font_metrics_t metrics;
696 gfx_font_t *font = NULL;
697
698 /* Seek to beginning of chunk (just after list type) */
699 rc = riff_rchunk_seek(&finfo->fontck, sizeof(uint32_t), SEEK_SET);
700 if (rc != EOK)
701 goto error;
702
703 rc = gfx_font_props_load(&finfo->fontck, &finfo->props);
704 if (rc != EOK)
705 goto error;
706
707 rc = gfx_font_metrics_load(&finfo->fontck, &metrics);
708 if (rc != EOK)
709 goto error;
710
711 rc = gfx_font_create_with_info(finfo->typeface, finfo, &metrics, &font);
712 if (rc != EOK)
713 goto error;
714
715 rc = gfx_font_bitmap_load(&finfo->fontck, font);
716 if (rc != EOK)
717 goto error;
718
719 while (true) {
720 rc = gfx_glyph_load(font, &finfo->fontck);
721 if (rc == ENOENT)
722 break;
723 if (rc != EOK)
724 goto error;
725 }
726
727 finfo->font = font;
728 return EOK;
729error:
730 if (font != NULL)
731 gfx_font_close(font);
732 return rc;
733}
734
735/** Save font into RIFF TPF file.
736 *
737 * @param finfo Font info
738 * @param riffw RIFF writer
739 * @return EOK on success or an error code
740 */
741errno_t gfx_font_save(gfx_font_info_t *finfo, riffw_t *riffw)
742{
743 errno_t rc;
744 riff_wchunk_t fontck;
745 gfx_glyph_t *glyph;
746
747 rc = riff_wchunk_start(riffw, CKID_LIST, &fontck);
748 if (rc != EOK)
749 return rc;
750
751 rc = riff_write_uint32(riffw, LTYPE_font);
752 if (rc != EOK)
753 return rc;
754
755 rc = gfx_font_props_save(&finfo->props, riffw);
756 if (rc != EOK)
757 return rc;
758
759 rc = gfx_font_metrics_save(&finfo->font->metrics, riffw);
760 if (rc != EOK)
761 return rc;
762
763 rc = gfx_font_bitmap_save(finfo->font, riffw);
764 if (rc != EOK)
765 return rc;
766
767 glyph = gfx_font_first_glyph(finfo->font);
768 while (glyph != NULL) {
769 rc = gfx_glyph_save(glyph, riffw);
770 if (rc != EOK)
771 return rc;
772
773 glyph = gfx_font_next_glyph(glyph);
774 }
775
776 rc = riff_wchunk_end(riffw, &fontck);
777 if (rc != EOK)
778 return rc;
779
780 return EOK;
781}
782
783/** @}
784 */
Note: See TracBrowser for help on using the repository browser.