Skip to content

Commit

Permalink
Upgraded font resource format. Now supports sparse glyph maps. Not co…
Browse files Browse the repository at this point in the history
…mpatible with old files.

Added UTF-8 decoding to the fctx_draw_string function.
  • Loading branch information
jrmobley committed Jan 31, 2016
1 parent 41cd33c commit 9cd558f
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 34 deletions.
25 changes: 16 additions & 9 deletions fctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -911,14 +911,19 @@ void fctx_set_text_size(FContext* fctx, FFont* font, int16_t pixels) {
void fctx_draw_string(FContext* fctx, const char* text, FFont* font, GTextAlignment alignment, FTextAnchor anchor) {

FPoint advance = {0, 0};
uint16_t code_point;
uint16_t decode_state;
const char* p;

if (alignment != GTextAlignmentLeft) {
fixed_t width = 0;
decode_state = 0;
for (p = text; *p; ++p) {
FGlyph* glyph = ffont_glyph_info(font, *p);
if (glyph) {
width += glyph->horiz_adv_x;
if (0 == decode_utf8_byte(*p, &decode_state, &code_point)) {
FGlyph* glyph = ffont_glyph_info(font, *p);
if (glyph) {
width += glyph->horiz_adv_x;
}
}
}
if (alignment == GTextAlignmentRight) {
Expand All @@ -938,13 +943,15 @@ void fctx_draw_string(FContext* fctx, const char* text, FFont* font, GTextAlignm
advance.y = -font->descent;
}

decode_state = 0;
for (p = text; *p; ++p) {
char ch = *p;
FGlyph* glyph = ffont_glyph_info(font, ch);
if (glyph) {
void* path_data = ffont_glyph_outline(font, glyph);
fctx_draw_commands(fctx, advance, path_data, glyph->path_data_length);
advance.x += glyph->horiz_adv_x;
if (0 == decode_utf8_byte(*p, &decode_state, &code_point)) {
FGlyph* glyph = ffont_glyph_info(font, code_point);
if (glyph) {
void* path_data = ffont_glyph_outline(font, glyph);
fctx_draw_commands(fctx, advance, path_data, glyph->path_data_length);
advance.x += glyph->horiz_adv_x;
}
}
}
}
145 changes: 126 additions & 19 deletions ffont.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,86 @@ FFont* ffont_create_from_resource(uint32_t resource_id) {
return NULL;
}

FGlyphRange* ffont_glyph_index(FFont* font) {
void* buffer = (void*)font;
void* index = buffer + sizeof(FFont);
return (FGlyphRange*)index;
}

FGlyph* ffont_glyph_table(FFont* font) {
return (FGlyph*)(((void*)font) + sizeof(FFont));
void* buffer = (void*)font;
void* table = buffer + sizeof(FFont)
+ font->glyph_index_length * sizeof(FGlyphRange);
return (FGlyph*)table;
}

void* ffont_path_data(FFont* font) {
void* buffer = (void*)font;
void* path_data = buffer + sizeof(FFont)
+ font->glyph_index_length * sizeof(FGlyphRange)
+ font->glyph_table_length * sizeof(FGlyph);
return path_data;
}

FGlyph* ffont_glyph_info(FFont* font, uint16_t unicode) {
if (unicode < font->unicode_offset) {
return NULL;
}
uint16_t glyph_index = unicode - font->unicode_offset;
if (glyph_index >= font->glyph_count) {
return NULL;
FGlyphRange* range = ffont_glyph_index(font);
FGlyphRange* end = range + font->glyph_index_length;
uint16_t offset = 0;
while (range < end) {
if (unicode < range->begin) {
break;
}
if (unicode < range->end) {
FGlyph* table = ffont_glyph_table(font);
FGlyph* g = table + offset + (unicode - range->begin);
/*APP_LOG(APP_LOG_LEVEL_DEBUG, "U+%04X @ U+%04X + %02X",
unicode, range->begin, unicode - range->begin);*/
return g;
}
offset += (range->end - range->begin);
++range;
}
FGlyph* glyph_table = ffont_glyph_table(font);
return glyph_table + glyph_index;
#if 0
APP_LOG(APP_LOG_LEVEL_WARNING, "U+%04x no glyph", unicode);
#endif
return NULL;
}

void* ffont_glyph_outline(FFont* font, FGlyph* glyph) {
void* buffer = (void*)font;
void* path_data = buffer + sizeof(FFont) + font->glyph_count * sizeof(FGlyph) + glyph->path_data_offset;
return path_data;
void* path_data = ffont_path_data(font);
return path_data + glyph->path_data_offset;
}

void ffont_debug_log(FFont* font) {
void ffont_debug_log(FFont* font, uint8_t log_level) {
#if 0
APP_LOG(APP_LOG_LEVEL_DEBUG, "font gc:%d uo:%d", font->glyph_count, font->unicode_offset);
FGlyph* glyphs = ffont_glyph_table(font);
for (uint16_t k = 0; k < font->glyph_count; ++k) {
FGlyph* g = glyphs + k;
APP_LOG(APP_LOG_LEVEL_DEBUG, "glyph[%d] \"%c\" |%d| : %d + %d",
k, (char)(k + font->unicode_offset), g->horiz_adv_x, g->path_data_offset, g->path_data_length);
if (log_level >= APP_LOG_LEVEL_WARNING && font == NULL) {
APP_LOG(APP_LOG_LEVEL_WARNING, "font not loaded");
return;
}

if (log_level >= APP_LOG_LEVEL_DEBUG_VERBOSE) {
APP_LOG(APP_LOG_LEVEL_DEBUG_VERBOSE, "so(FF):%d so(FGR):%d so(FG):%d", sizeof(FFont), sizeof(FGlyphRange), sizeof(FGlyph));
APP_LOG(APP_LOG_LEVEL_DEBUG_VERBOSE, "upm:%d a:%d d:%d gil:%d gtl:%d", font->units_per_em, font->ascent, font->descent, font->glyph_index_length, font->glyph_table_length);
}

if (log_level >= APP_LOG_LEVEL_DEBUG) {
uint16_t glyph_count = 0;
FGlyphRange* index = ffont_glyph_index(font);
for (uint16_t k = 0; k < font->glyph_index_length; ++k) {
FGlyphRange* r = index + k;
glyph_count += (r->end - r->begin);
APP_LOG(APP_LOG_LEVEL_DEBUG, "U+%04X-%04X", r->begin, r->end - 1);
}
APP_LOG(APP_LOG_LEVEL_DEBUG, "gc:%d", glyph_count);
}

if (log_level >= APP_LOG_LEVEL_DEBUG_VERBOSE) {
FGlyph* glyphs = ffont_glyph_table(font);
for (uint16_t k = 0; k < font->glyph_table_length; ++k) {
FGlyph* g = glyphs + k;
APP_LOG(APP_LOG_LEVEL_DEBUG, "glyph[%d] |%d| : %d + %d",
k, g->horiz_adv_x, g->path_data_offset, g->path_data_length);
}
}
#endif
}
Expand All @@ -50,3 +100,60 @@ void ffont_destroy(FFont* font) {
free(font);
}


/**
* Decode the next byte of a UTF-8 byte stream.
* Initialize state to 0 the before calling this function for the first
* time for a given stream. If the returned value is 0, then cp has been
* set to a valid code point. Other return values indicate that a multi-
* byte sequence is in progress, or there was a decoding error.
*
* @param byte the byte to decode.
* @state the current state of the decoder.
* @cp the decoded unitcode code point.
* @return the state of the decode process after decoding the byte.
*/
uint16_t decode_utf8_byte(uint8_t byte, uint16_t* state, uint16_t* cp) {

/* unicode code points are encoded as follows.
* U+00000000 – U+0000007F: 0xxxxxxx
* U+00000080 – U+000007FF: 110xxxxx 10xxxxxx
* U+00000800 – U+0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
* U+00010000 – U+001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
* U+00200000 – U+03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
* U+04000000 – U+7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
*/

if (*state == 0 || *state == 6) {
if (byte < 0b10000000) { // (<128) ascii character
*cp = byte;
} else if (byte < 0b11000000) { // (<192) unexpected continuation byte
*cp = 0;
*state = 6;
} else if (byte < 0b11100000) { // (<224) 2 byte sequence
*cp = byte & 0b00011111;
*state = 1;
} else if (byte < 0b11110000) { // (<240) 3 byte sequence
*cp = byte & 0b00001111;
*state = 2;
} else if (byte < 0b11111000) { // (<248) 4 byte sequence
*cp = byte & 0b00000111;
*state = 3;
} else if (byte < 0b11111100) { // (<252) 5 byte sequence
*cp = byte & 0b00000011;
*state = 4;
} else if (byte < 0b11111110) { // (<254) 6 byte sequence
*cp = byte & 0b00000001;
*state = 5;
}
} else if (*state < 6) {
if (byte < 0b11000000) {
*cp = (*cp << 6) | (byte & 0b00111111);
*state = *state - 1;
} else {
*cp = 0;
*state = 6;
}
}
return *state;
}
19 changes: 13 additions & 6 deletions ffont.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
#include "fctx.h"

typedef struct __attribute__((__packed__)) FFont {
uint16_t glyph_count;
uint16_t unicode_offset;
fixed16_t units_per_em;
fixed16_t ascent;
fixed16_t descent;
fixed16_t units_per_em;
fixed16_t ascent;
fixed16_t descent;
uint16_t glyph_index_length;
uint16_t glyph_table_length;
} FFont;

typedef struct __attribute__((__packed__)) FGlyphRange {
uint16_t begin;
uint16_t end;
} FGlyphRange;

typedef struct __attribute__((__packed__)) FGlyph {
uint16_t path_data_offset;
uint16_t path_data_length;
Expand All @@ -18,6 +23,8 @@ typedef struct __attribute__((__packed__)) FGlyph {

FFont* ffont_create_from_resource(uint32_t resource_id);
void ffont_destroy(FFont* font);
void ffont_debug_log(FFont* font);
void ffont_debug_log(FFont* font, uint8_t log_level);
FGlyph* ffont_glyph_info(FFont* font, uint16_t unicode);
void* ffont_glyph_outline(FFont* font, FGlyph* glyph);

uint16_t decode_utf8_byte(uint8_t byte, uint16_t* state, uint16_t* cp);

0 comments on commit 9cd558f

Please sign in to comment.