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

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

Remove forgotten prototype code

  • Property mode set to 100644
File size: 21.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 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 return EOK;
549}
550
551/** Save font metrics to RIFF TPF file.
552 *
553 * @param metrics Font metrics
554 * @param riffw RIFF writer
555 * @return EOK on success or an error code
556 */
557static errno_t gfx_font_metrics_save(gfx_font_metrics_t *metrics,
558 riffw_t *riffw)
559{
560 errno_t rc;
561 tpf_font_metrics_t tmetrics;
562 riff_wchunk_t mtrck;
563
564 tmetrics.ascent = host2uint16_t_le(metrics->ascent);
565 tmetrics.descent = host2uint16_t_le(metrics->descent);
566 tmetrics.leading = host2uint16_t_le(metrics->leading);
567
568 rc = riff_wchunk_start(riffw, CKID_fmtr, &mtrck);
569 if (rc != EOK)
570 return rc;
571
572 rc = riff_write(riffw, (void *) &tmetrics, sizeof(tmetrics));
573 if (rc != EOK)
574 return rc;
575
576 rc = riff_wchunk_end(riffw, &mtrck);
577 if (rc != EOK)
578 return rc;
579
580 return EOK;
581}
582
583/** Bit pack font bitmap into 1 bits/pixel format.
584 *
585 * @param width Bitmap width
586 * @param height Bitmap height
587 * @param pixels Bitmap pixels
588 * @param rdata Place to store pointer to packed data
589 * @param rsize Place to store size of packed data
590 * @return EOK on sucess, ENOMEM if out of memory
591 */
592errno_t gfx_font_bitmap_pack(gfx_coord_t width, gfx_coord_t height,
593 uint32_t *pixels, void **rdata, size_t *rsize)
594{
595 void *data;
596 size_t size;
597 size_t bytes_line;
598 gfx_coord_t x, y;
599 uint8_t b;
600 uint8_t *dp;
601 uint32_t *sp;
602 uint32_t pix;
603
604 bytes_line = (width + 7) / 8;
605 size = height * bytes_line;
606
607 data = malloc(size);
608 if (data == NULL)
609 return ENOMEM;
610
611 sp = pixels;
612 dp = data;
613 for (y = 0; y < height; y++) {
614 b = 0;
615 for (x = 0; x < width; x++) {
616 pix = *sp++;
617 b = (b << 1) | (pix & 1);
618 /* Write eight bits */
619 if ((x & 7) == 7) {
620 *dp++ = b;
621 b = 0;
622 }
623 }
624
625 /* Write remaining bits */
626 if ((x & 7) != 0) {
627 b = b << (8 - (x & 7));
628 *dp++ = b;
629 }
630 }
631
632 *rdata = data;
633 *rsize = size;
634 return EOK;
635}
636
637/** Unpack font bitmap from 1 bits/pixel format.
638 *
639 * @param width Bitmap width
640 * @param height Bitmap height
641 * @param data Packed data
642 * @param dsize Size of packed data
643 * @param pixels Bitmap pixels
644 * @return EOK on success, EINVAL if data size is invalid
645 */
646errno_t gfx_font_bitmap_unpack(gfx_coord_t width, gfx_coord_t height,
647 void *data, size_t dsize, uint32_t *pixels)
648{
649 size_t size;
650 size_t bytes_line;
651 gfx_coord_t x, y;
652 uint8_t b;
653 uint8_t *sp;
654 uint32_t *dp;
655
656 bytes_line = (width + 7) / 8;
657 size = height * bytes_line;
658
659 if (dsize != size)
660 return EINVAL;
661
662 sp = data;
663 dp = pixels;
664 for (y = 0; y < height; y++) {
665 b = 0;
666 for (x = 0; x < width; x++) {
667 if ((x & 7) == 0)
668 b = *sp++;
669 *dp++ = (b >> 7) ? PIXEL(255, 255, 255, 255) :
670 PIXEL(0, 0, 0, 0);
671 b = b << 1;
672 }
673 }
674
675 return EOK;
676}
677
678/** Load font bitmap from RIFF TPF file.
679 *
680 * @param parent Parent chunk
681 * @param font Font
682 * @return EOK on success or an error code
683 */
684static errno_t gfx_font_bitmap_load(riff_rchunk_t *parent, gfx_font_t *font)
685{
686 errno_t rc;
687 riff_rchunk_t bmpck;
688 tpf_font_bmp_hdr_t thdr;
689 gfx_bitmap_params_t params;
690 gfx_bitmap_alloc_t alloc;
691 gfx_bitmap_t *bitmap = NULL;
692 uint32_t width;
693 uint32_t height;
694 uint16_t fmt;
695 uint16_t depth;
696 size_t bytes_line;
697 void *data = NULL;
698 size_t size;
699 size_t nread;
700
701 rc = riff_rchunk_match(parent, CKID_fbmp, &bmpck);
702 if (rc != EOK)
703 goto error;
704
705 rc = riff_read(&bmpck, &thdr, sizeof(thdr), &nread);
706 if (rc != EOK || nread != sizeof(thdr))
707 goto error;
708
709 width = uint32_t_le2host(thdr.width);
710 height = uint32_t_le2host(thdr.height);
711 fmt = uint16_t_le2host(thdr.fmt);
712 depth = uint16_t_le2host(thdr.depth);
713
714 if (fmt != 0 || depth != 1) {
715 rc = ENOTSUP;
716 goto error;
717 }
718
719 bytes_line = (width + 7) / 8;
720 size = height * bytes_line;
721
722 data = malloc(size);
723 if (data == NULL) {
724 rc = ENOMEM;
725 goto error;
726 }
727
728 gfx_bitmap_params_init(&params);
729 params.rect.p0.x = 0;
730 params.rect.p0.y = 0;
731 params.rect.p1.x = width;
732 params.rect.p1.y = height;
733 params.flags = bmpf_color_key | bmpf_colorize;
734 params.key_color = PIXEL(0, 0, 0, 0);
735
736 rc = gfx_bitmap_create(font->typeface->gc, &params, NULL, &bitmap);
737 if (rc != EOK)
738 goto error;
739
740 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
741 if (rc != EOK)
742 goto error;
743
744 rc = riff_read(&bmpck, data, size, &nread);
745 if (rc != EOK)
746 goto error;
747
748 if (nread != size) {
749 rc = EIO;
750 goto error;
751 }
752
753 rc = riff_rchunk_end(&bmpck);
754 if (rc != EOK)
755 goto error;
756
757 rc = gfx_font_bitmap_unpack(width, height, data, size, alloc.pixels);
758 if (rc != EOK)
759 goto error;
760
761 free(data);
762 gfx_bitmap_destroy(font->bitmap);
763 font->bitmap = bitmap;
764 font->rect = params.rect;
765 return EOK;
766error:
767 if (data != NULL)
768 free(data);
769 if (bitmap != NULL)
770 gfx_bitmap_destroy(bitmap);
771 return rc;
772}
773
774/** Save font bitmap to RIFF TPF file.
775 *
776 * @param font Font
777 * @param riffw RIFF writer
778 * @return EOK on success or an error code
779 */
780static errno_t gfx_font_bitmap_save(gfx_font_t *font, riffw_t *riffw)
781{
782 errno_t rc;
783 tpf_font_bmp_hdr_t thdr;
784 riff_wchunk_t bmpck;
785 gfx_bitmap_alloc_t alloc;
786 void *data = NULL;
787 size_t dsize;
788
789 rc = gfx_bitmap_get_alloc(font->bitmap, &alloc);
790 if (rc != EOK)
791 return rc;
792
793 rc = gfx_font_bitmap_pack(font->rect.p1.x, font->rect.p1.y,
794 alloc.pixels, &data, &dsize);
795 if (rc != EOK)
796 return rc;
797
798 thdr.width = host2uint32_t_le(font->rect.p1.x);
799 thdr.height = host2uint32_t_le(font->rect.p1.y);
800 thdr.fmt = 0;
801 thdr.depth = host2uint16_t_le(1);
802
803 rc = riff_wchunk_start(riffw, CKID_fbmp, &bmpck);
804 if (rc != EOK)
805 goto error;
806
807 rc = riff_write(riffw, &thdr, sizeof(thdr));
808 if (rc != EOK)
809 goto error;
810
811 rc = riff_write(riffw, data, dsize);
812 if (rc != EOK)
813 goto error;
814
815 rc = riff_wchunk_end(riffw, &bmpck);
816 if (rc != EOK)
817 goto error;
818
819 free(data);
820 return EOK;
821error:
822 if (data != NULL)
823 free(data);
824 return rc;
825}
826
827/** Load font info from RIFF TPF file.
828 *
829 * @param tface Containing typeface
830 * @param parent Parent chunk
831 * @return EOK on success or an error code
832 */
833errno_t gfx_font_info_load(gfx_typeface_t *tface, riff_rchunk_t *parent)
834{
835 errno_t rc;
836 riff_rchunk_t fontck;
837 gfx_font_props_t props;
838 gfx_font_info_t *finfo = NULL;
839 gfx_font_t *font = NULL;
840
841 rc = riff_rchunk_list_match(parent, LTYPE_font, &fontck);
842 if (rc != EOK)
843 goto error;
844
845 finfo = calloc(1, sizeof(gfx_font_info_t));
846 if (finfo == NULL) {
847 rc = ENOMEM;
848 goto error;
849 }
850
851 finfo->fontck = fontck;
852
853 rc = gfx_font_props_load(&fontck, &props);
854 if (rc != EOK)
855 goto error;
856
857 rc = riff_rchunk_end(&fontck);
858 if (rc != EOK)
859 goto error;
860
861 finfo->typeface = tface;
862 list_append(&finfo->lfonts, &tface->fonts);
863 finfo->props = props;
864 finfo->font = NULL;
865
866 return EOK;
867error:
868 if (finfo != NULL)
869 free(finfo);
870 if (font != NULL)
871 gfx_font_close(font);
872 return rc;
873}
874
875/** Load font from RIFF TPF file.
876 *
877 * @param finfo Font information
878 * @return EOK on success or an error code
879 */
880errno_t gfx_font_load(gfx_font_info_t *finfo)
881{
882 errno_t rc;
883 gfx_font_metrics_t metrics;
884 gfx_font_t *font = NULL;
885
886 /* Seek to beginning of chunk (just after list type) */
887 rc = riff_rchunk_seek(&finfo->fontck, sizeof(uint32_t), SEEK_SET);
888 if (rc != EOK)
889 goto error;
890
891 rc = gfx_font_props_load(&finfo->fontck, &finfo->props);
892 if (rc != EOK)
893 goto error;
894
895 rc = gfx_font_metrics_load(&finfo->fontck, &metrics);
896 if (rc != EOK)
897 goto error;
898
899 rc = gfx_font_create_with_info(finfo->typeface, finfo, &metrics, &font);
900 if (rc != EOK)
901 goto error;
902
903 rc = gfx_font_bitmap_load(&finfo->fontck, font);
904 if (rc != EOK)
905 goto error;
906
907 while (true) {
908 rc = gfx_glyph_load(font, &finfo->fontck);
909 if (rc == ENOENT)
910 break;
911 if (rc != EOK)
912 goto error;
913 }
914
915 finfo->font = font;
916 return EOK;
917error:
918 if (font != NULL)
919 gfx_font_close(font);
920 return rc;
921}
922
923/** Save font into RIFF TPF file.
924 *
925 * @param finfo Font info
926 * @param riffw RIFF writer
927 * @return EOK on success or an error code
928 */
929errno_t gfx_font_save(gfx_font_info_t *finfo, riffw_t *riffw)
930{
931 errno_t rc;
932 riff_wchunk_t fontck;
933 gfx_glyph_t *glyph;
934
935 rc = riff_wchunk_start(riffw, CKID_LIST, &fontck);
936 if (rc != EOK)
937 return rc;
938
939 rc = riff_write_uint32(riffw, LTYPE_font);
940 if (rc != EOK)
941 return rc;
942
943 rc = gfx_font_props_save(&finfo->props, riffw);
944 if (rc != EOK)
945 return rc;
946
947 rc = gfx_font_metrics_save(&finfo->font->metrics, riffw);
948 if (rc != EOK)
949 return rc;
950
951 rc = gfx_font_bitmap_save(finfo->font, riffw);
952 if (rc != EOK)
953 return rc;
954
955 glyph = gfx_font_first_glyph(finfo->font);
956 while (glyph != NULL) {
957 rc = gfx_glyph_save(glyph, riffw);
958 if (rc != EOK)
959 return rc;
960
961 glyph = gfx_font_next_glyph(glyph);
962 }
963
964 rc = riff_wchunk_end(riffw, &fontck);
965 if (rc != EOK)
966 return rc;
967
968 return EOK;
969}
970
971/** @}
972 */
Note: See TracBrowser for help on using the repository browser.