2 * Copyright (c) 2014 Martin Sucha
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
39 #include <byteorder.h>
46 #include "../drawctx.h"
47 #include "bitmap_backend.h"
49 #define PCF_TABLE_ACCELERATORS 0x02
50 #define PCF_TABLE_METRICS 0x04
51 #define PCF_TABLE_BITMAPS 0x08
52 #define PCF_TABLE_INK_METRICS 0x10
53 #define PCF_TABLE_ENCODINGS 0x20
55 #define PCF_FORMAT_DEFAULT 0x00000000
56 #define PCF_FORMAT_MASK 0xffffff00
57 #define PCF_FORMAT_MSBYTE_FIRST 0x00000004
58 #define PCF_FORMAT_MSBIT_FIRST 0x00000008
59 #define PCF_FORMAT_COMPRESSED_METRICS 0x00000100
64 uint32_t size
; /* in bytes */
65 uint32_t offset
; /* in bytes from beginning of file */
66 } __attribute__((__packed__
)) pcf_toc_entry_t
;
73 uint16_t default_char
;
74 } __attribute__((__packed__
)) pcf_encoding_t
;
77 uint8_t left_side_bearing
;
78 uint8_t right_side_bearing
;
79 uint8_t character_width
;
80 uint8_t character_ascent
;
81 uint8_t character_descent
;
82 } __attribute__((__packed__
)) pcf_compressed_metrics_t
;
85 int16_t left_side_bearing
;
86 int16_t right_side_bearing
;
87 int16_t character_width
;
88 int16_t character_ascent
;
89 int16_t character_descent
;
90 uint16_t character_attributes
;
91 } __attribute__((__packed__
)) pcf_default_metrics_t
;
94 uint8_t unused_font_information
[8];
97 } __attribute__((__packed__
)) pcf_accelerators_t
;
101 uint32_t glyph_count
;
102 pcf_toc_entry_t bitmap_table
;
103 pcf_toc_entry_t metrics_table
;
104 pcf_toc_entry_t encodings_table
;
105 pcf_toc_entry_t accelerators_table
;
106 pcf_encoding_t encoding
;
107 font_metrics_t font_metrics
;
110 static inline uint32_t uint32_t_pcf2host(uint32_t val
, uint32_t format
)
112 if (format
& PCF_FORMAT_MSBYTE_FIRST
) {
113 return uint32_t_be2host(val
);
116 return uint32_t_le2host(val
);
120 static inline uint16_t uint16_t_pcf2host(uint16_t val
, uint32_t format
)
122 if (format
& PCF_FORMAT_MSBYTE_FIRST
) {
123 return uint16_t_be2host(val
);
126 return uint16_t_le2host(val
);
130 static inline int16_t int16_t_pcf2host(int16_t val
, uint32_t format
)
132 return (int16_t) uint16_t_pcf2host((uint16_t) val
, format
);
135 static inline int32_t int32_t_pcf2host(int32_t val
, uint32_t format
)
137 return (int32_t) uint32_t_pcf2host((uint32_t) val
, format
);
141 static int16_t compressed2int(uint8_t compressed
)
143 int16_t ret
= compressed
;
148 static errno_t
pcf_resolve_glyph(void *opaque_data
, const wchar_t chr
,
149 glyph_id_t
*glyph_id
)
151 pcf_data_t
*data
= (pcf_data_t
*) opaque_data
;
153 /* TODO is this correct? */
154 uint8_t byte1
= (chr
>> 8) & 0xff;
155 uint8_t byte2
= chr
& 0xff;
156 pcf_encoding_t
*e
= &data
->encoding
;
158 aoff64_t entry_index
=
159 (byte1
- e
->min_byte1
) * (e
->max_byte2
- e
->min_byte2
+ 1) +
160 (byte2
- e
->min_byte2
);
162 aoff64_t entry_offset
= data
->encodings_table
.offset
+
163 (sizeof(uint32_t) + 5 * sizeof(uint16_t)) +
164 entry_index
* sizeof(uint16_t);
166 int rc
= fseek(data
->file
, entry_offset
, SEEK_SET
);
171 size_t records_read
= fread(&glyph
, sizeof(uint16_t), 1, data
->file
);
172 if (records_read
!= 1)
175 glyph
= uint16_t_pcf2host(glyph
, data
->encodings_table
.format
);
185 static errno_t
load_glyph_metrics(pcf_data_t
*data
, uint32_t glyph_id
,
186 pcf_toc_entry_t
*table
, pcf_default_metrics_t
*metrics
)
192 if (table
->format
& PCF_FORMAT_COMPRESSED_METRICS
) {
193 offset
= table
->offset
+ sizeof(uint32_t) + sizeof(uint16_t) +
194 glyph_id
* sizeof(pcf_compressed_metrics_t
);
196 rc
= fseek(data
->file
, offset
, SEEK_SET
);
200 pcf_compressed_metrics_t compressed_metrics
;
201 records_read
= fread(&compressed_metrics
,
202 sizeof(pcf_compressed_metrics_t
), 1,data
->file
);
203 if (records_read
!= 1)
206 metrics
->left_side_bearing
=
207 compressed2int(compressed_metrics
.left_side_bearing
);
208 metrics
->right_side_bearing
=
209 compressed2int(compressed_metrics
.right_side_bearing
);
210 metrics
->character_width
=
211 compressed2int(compressed_metrics
.character_width
);
212 metrics
->character_ascent
=
213 compressed2int(compressed_metrics
.character_ascent
);
214 metrics
->character_descent
=
215 compressed2int(compressed_metrics
.character_descent
);
216 metrics
->character_attributes
= 0;
219 offset
= table
->offset
+ 2 * sizeof(uint32_t) +
220 glyph_id
* sizeof(pcf_default_metrics_t
);
222 rc
= fseek(data
->file
, offset
, SEEK_SET
);
226 pcf_default_metrics_t uncompressed_metrics
;
227 records_read
= fread(&uncompressed_metrics
,
228 sizeof(pcf_default_metrics_t
), 1,data
->file
);
229 if (records_read
!= 1)
232 metrics
->left_side_bearing
=
233 int16_t_pcf2host(uncompressed_metrics
.left_side_bearing
,
235 metrics
->right_side_bearing
=
236 int16_t_pcf2host(uncompressed_metrics
.right_side_bearing
,
238 metrics
->character_width
=
239 int16_t_pcf2host(uncompressed_metrics
.character_width
,
241 metrics
->character_ascent
=
242 int16_t_pcf2host(uncompressed_metrics
.character_ascent
,
244 metrics
->character_descent
=
245 int16_t_pcf2host(uncompressed_metrics
.character_descent
,
247 metrics
->character_attributes
=
248 uint16_t_pcf2host(uncompressed_metrics
.character_attributes
,
255 static errno_t
pcf_load_glyph_surface(void *opaque_data
, glyph_id_t glyph_id
,
256 surface_t
**out_surface
)
258 pcf_data_t
*data
= (pcf_data_t
*) opaque_data
;
260 pcf_default_metrics_t pcf_metrics
;
261 memset(&pcf_metrics
, 0, sizeof(pcf_default_metrics_t
));
262 errno_t rc
= load_glyph_metrics(data
, glyph_id
, &data
->metrics_table
,
267 aoff64_t offset
= data
->bitmap_table
.offset
+ (2 * sizeof(uint32_t)) +
268 (glyph_id
* sizeof(uint32_t));
270 if (fseek(data
->file
, offset
, SEEK_SET
) < 0)
273 uint32_t bitmap_offset
= 0;
274 size_t records_read
= fread(&bitmap_offset
, sizeof(uint32_t), 1,
276 if (records_read
!= 1)
278 bitmap_offset
= uint32_t_pcf2host(bitmap_offset
,
279 data
->bitmap_table
.format
);
281 offset
= data
->bitmap_table
.offset
+ (2 * sizeof(uint32_t)) +
282 (data
->glyph_count
* sizeof(uint32_t)) + (4 * sizeof(uint32_t))
285 if (fseek(data
->file
, offset
, SEEK_SET
) < 0)
288 surface_coord_t width
= pcf_metrics
.character_width
;
289 surface_coord_t height
= pcf_metrics
.character_ascent
+
290 pcf_metrics
.character_descent
;
291 size_t row_padding_bytes
= (1 << (data
->bitmap_table
.format
& 3));
292 size_t word_size_bytes
= (1 << ((data
->bitmap_table
.format
>> 4) & 3));
293 size_t row_bytes
= ALIGN_UP(ALIGN_UP(width
, 8) / 8, row_padding_bytes
);
294 size_t bitmap_bytes
= height
* row_bytes
;
296 uint8_t *bitmap
= malloc(bitmap_bytes
);
300 records_read
= fread(bitmap
, sizeof(uint8_t), bitmap_bytes
,
303 surface_t
*surface
= surface_create(width
, height
, NULL
, 0);
309 for (unsigned int y
= 0; y
< height
; ++y
) {
310 size_t row_offset
= row_bytes
* y
;
311 for (unsigned int x
= 0; x
< width
; ++x
) {
312 size_t word_index
= x
/ (word_size_bytes
* 8);
313 size_t column_offset1
= word_index
* word_size_bytes
;
314 size_t byte_index_within_word
=
315 (x
% (word_size_bytes
* 8)) / 8;
316 size_t column_offset2
;
317 if (data
->bitmap_table
.format
& PCF_FORMAT_MSBYTE_FIRST
) {
318 column_offset2
= (word_size_bytes
- 1) - byte_index_within_word
;
321 column_offset2
= byte_index_within_word
;
323 uint8_t b
= bitmap
[row_offset
+ column_offset1
+ column_offset2
];
325 if (data
->bitmap_table
.format
& PCF_FORMAT_MSBIT_FIRST
) {
326 set
= (b
>> (7 - (x
% 8))) & 1;
329 set
= (b
>> (x
% 8)) & 1;
331 pixel_t p
= set
? PIXEL(255, 0, 0, 0) : PIXEL(0, 0, 0, 0);
332 surface_put_pixel(surface
, x
, y
, p
);
336 *out_surface
= surface
;
341 static errno_t
pcf_load_glyph_metrics(void *opaque_data
, glyph_id_t glyph_id
,
344 pcf_data_t
*data
= (pcf_data_t
*) opaque_data
;
346 pcf_default_metrics_t pcf_metrics
;
347 memset(&pcf_metrics
, 0, sizeof(pcf_default_metrics_t
));
348 errno_t rc
= load_glyph_metrics(data
, glyph_id
, &data
->metrics_table
,
353 gm
->left_side_bearing
= pcf_metrics
.left_side_bearing
;
354 gm
->width
= pcf_metrics
.character_width
;
355 gm
->right_side_bearing
= pcf_metrics
.right_side_bearing
-
356 pcf_metrics
.character_width
;
357 gm
->height
= pcf_metrics
.character_descent
+
358 pcf_metrics
.character_ascent
;
359 gm
->ascender
= pcf_metrics
.character_ascent
;
364 static void pcf_release(void *opaque_data
)
366 pcf_data_t
*data
= (pcf_data_t
*) opaque_data
;
372 bitmap_font_decoder_t fd_pcf
= {
373 .resolve_glyph
= pcf_resolve_glyph
,
374 .load_glyph_surface
= pcf_load_glyph_surface
,
375 .load_glyph_metrics
= pcf_load_glyph_metrics
,
376 .release
= pcf_release
379 static errno_t
pcf_read_toc(pcf_data_t
*data
)
381 int rc
= fseek(data
->file
, 0, SEEK_END
);
385 aoff64_t file_size
= ftell(data
->file
);
387 rc
= fseek(data
->file
, 0, SEEK_SET
);
392 size_t records_read
= fread(header
, sizeof(char), 4, data
->file
);
393 if (records_read
!= 4)
396 if (header
[0] != 1 || header
[1] != 'f' || header
[2] != 'c' ||
400 uint32_t table_count
;
401 records_read
= fread(&table_count
, sizeof(uint32_t), 1,
403 if (records_read
!= 1)
406 table_count
= uint32_t_le2host(table_count
);
408 bool found_bitmap_table
= false;
409 bool found_metrics_table
= false;
410 bool found_encodings_table
= false;
411 bool found_accelerators_table
= false;
413 for (uint32_t index
= 0; index
< table_count
; index
++) {
414 pcf_toc_entry_t toc_entry
;
415 records_read
= fread(&toc_entry
, sizeof(pcf_toc_entry_t
), 1,
417 toc_entry
.type
= uint32_t_le2host(toc_entry
.type
);
418 toc_entry
.format
= uint32_t_le2host(toc_entry
.format
);
419 toc_entry
.size
= uint32_t_le2host(toc_entry
.size
);
420 toc_entry
.offset
= uint32_t_le2host(toc_entry
.offset
);
422 if (toc_entry
.offset
>= file_size
)
425 aoff64_t end
= ((aoff64_t
) toc_entry
.offset
) + ((aoff64_t
) toc_entry
.size
);
429 if (toc_entry
.type
== PCF_TABLE_BITMAPS
) {
430 if (found_bitmap_table
)
432 found_bitmap_table
= true;
433 data
->bitmap_table
= toc_entry
;
435 else if (toc_entry
.type
== PCF_TABLE_METRICS
) {
436 if (found_metrics_table
)
438 found_metrics_table
= true;
439 data
->metrics_table
= toc_entry
;
441 else if (toc_entry
.type
== PCF_TABLE_ENCODINGS
) {
442 if (found_encodings_table
)
444 found_encodings_table
= true;
445 data
->encodings_table
= toc_entry
;
447 else if (toc_entry
.type
== PCF_TABLE_ACCELERATORS
) {
448 if (found_accelerators_table
)
450 found_accelerators_table
= true;
451 data
->accelerators_table
= toc_entry
;
455 if (!found_bitmap_table
|| !found_metrics_table
||
456 !found_encodings_table
|| !found_accelerators_table
)
462 static errno_t
pcf_seek_table_header(pcf_data_t
*data
, pcf_toc_entry_t
*table
)
465 int rc
= fseek(data
->file
, table
->offset
, SEEK_SET
);
469 size_t records_read
= fread(&format
, sizeof(uint32_t), 1, data
->file
);
470 if (records_read
!= 1)
473 format
= uint32_t_le2host(format
);
474 if (format
!= table
->format
)
480 static errno_t
pcf_read_bitmap_table_header(pcf_data_t
*data
)
482 errno_t rc
= pcf_seek_table_header(data
, &data
->bitmap_table
);
486 if ((data
->bitmap_table
.format
& PCF_FORMAT_MASK
) != PCF_FORMAT_DEFAULT
)
489 uint32_t glyph_count
= 0;
490 size_t records_read
= fread(&glyph_count
, sizeof(uint32_t), 1,
492 if (records_read
!= 1)
494 glyph_count
= uint32_t_pcf2host(glyph_count
, data
->bitmap_table
.format
);
496 data
->glyph_count
= glyph_count
;
500 static errno_t
pcf_read_metrics_table_header(pcf_data_t
*data
)
502 errno_t rc
= pcf_seek_table_header(data
, &data
->metrics_table
);
507 uint32_t metrics_count
;
508 if (data
->metrics_table
.format
& PCF_FORMAT_COMPRESSED_METRICS
) {
509 uint16_t metrics_count_16
;
510 records_read
= fread(&metrics_count_16
, sizeof(uint16_t), 1,
512 if (records_read
!= 1)
514 metrics_count_16
= uint16_t_pcf2host(metrics_count_16
,
515 data
->metrics_table
.format
);
516 metrics_count
= metrics_count_16
;
519 records_read
= fread(&metrics_count
, sizeof(uint32_t), 1,
521 if (records_read
!= 1)
523 metrics_count
= uint32_t_pcf2host(metrics_count
,
524 data
->metrics_table
.format
);
527 if (metrics_count
!= data
->glyph_count
)
533 static errno_t
pcf_read_encodings_table_header(pcf_data_t
*data
)
535 errno_t rc
= pcf_seek_table_header(data
, &data
->encodings_table
);
539 pcf_encoding_t encoding
;
540 size_t records_read
= fread(&encoding
, sizeof(pcf_encoding_t
), 1,
542 if (records_read
!= 1)
545 encoding
.min_byte1
= uint16_t_pcf2host(encoding
.min_byte1
,
546 data
->encodings_table
.format
);
547 encoding
.max_byte1
= uint16_t_pcf2host(encoding
.max_byte1
,
548 data
->encodings_table
.format
);
549 encoding
.min_byte2
= uint16_t_pcf2host(encoding
.min_byte2
,
550 data
->encodings_table
.format
);
551 encoding
.max_byte2
= uint16_t_pcf2host(encoding
.max_byte2
,
552 data
->encodings_table
.format
);
553 encoding
.default_char
= uint16_t_pcf2host(encoding
.default_char
,
554 data
->encodings_table
.format
);
556 data
->encoding
= encoding
;
560 static errno_t
pcf_read_accelerators_table(pcf_data_t
*data
)
562 errno_t rc
= pcf_seek_table_header(data
, &data
->accelerators_table
);
566 pcf_accelerators_t accelerators
;
567 size_t records_read
= fread(&accelerators
, sizeof(pcf_accelerators_t
),
569 if (records_read
!= 1)
572 data
->font_metrics
.ascender
= int32_t_pcf2host(accelerators
.font_ascent
,
573 data
->accelerators_table
.format
);
574 data
->font_metrics
.descender
= int32_t_pcf2host(accelerators
.font_descent
,
575 data
->accelerators_table
.format
);
576 data
->font_metrics
.leading
= 0;
581 errno_t
pcf_font_create(font_t
**font
, char *filename
, uint16_t points
)
584 pcf_data_t
*data
= malloc(sizeof(pcf_data_t
));
588 data
->file
= fopen(filename
, "rb");
589 if (data
->file
== NULL
)
592 rc
= pcf_read_toc(data
);
596 rc
= pcf_read_bitmap_table_header(data
);
600 rc
= pcf_read_metrics_table_header(data
);
604 rc
= pcf_read_encodings_table_header(data
);
608 rc
= pcf_read_accelerators_table(data
);
612 rc
= bitmap_font_create(&fd_pcf
, data
, data
->glyph_count
,
613 data
->font_metrics
, points
, font
);