source: mainline/uspace/lib/gfxfont/src/font.c

Last change on this file was 5c27e77, checked in by Jiri Svoboda <jiri@…>, 3 years ago

Text underlining support

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