#include #include #include //--- // Internal //--- /* dfont_utf8_next(): Read the next UTF-8 code point of a string */ static uint32_t dfont_utf8_next(uint8_t const **str_pointer) { uint8_t const *str = *str_pointer; uint8_t lead = *str++; /* Skip non-leaders which are invalid as starting bytes */ while((lead >= 0x80 && lead <= 0xbf) || lead == 0xc0 || lead == 0xc1 || lead == 0xfe || lead == 0xff) { lead = *str++; } /* This base case will handle the NUL terminator */ if(lead <= 0x7f) { *str_pointer = str; return lead; } uint8_t n2 = (*str++ & 0x3f); if(lead <= 0xdf) { *str_pointer = str; return ((lead & 0x1f) << 6) | n2; } uint8_t n3 = (*str++ & 0x3f); if(lead <= 0xef) { *str_pointer = str; return ((lead & 0x0f) << 12) | (n2 << 6) | n3; } uint8_t n4 = (*str++ & 0x3f); if(lead <= 0xf7) { *str_pointer = str; return ((lead & 0x07) << 18) | (n2 << 12) | (n3 << 6) | n4; } /* It the string is too invalid, force a space and try to continue */ *str_pointer = str; return 0x20; } #if 0 /* dfont_glyph_index(): Obtain the glyph index of a Unicode code point */ int dfont_glyph_index(font_t const *f, uint32_t code_point) { int glyph_start = 0; for(int i = 0; i < f->block_count; i++) { int diff = code_point - f->blocks[i].start; if(diff >= 0 && diff < f->blocks[i].length) { return glyph_start + diff; } glyph_start += f->blocks[i].length; } return -1; } #endif /* dfont_glyph_index(): Obtain the glyph index of a Unicode code point */ //TODO: suport unicode block int dfont_glyph_index(font_t const *f, uint32_t code_point) { code_point -= ' '; if ((int)code_point < 0 || code_point >= f->glyph.count) return (-1); return code_point; } /* dfont_char_render() : */ void dfont_char_render( struct dshader_surface *surface, int glyph_idx, uint32_t *arg ) { uint32_t glyph_bitmap; uint32_t glyph_shift; int glyph_width; int glyph_size; font_t *font; int counter; int sx; int x; int y; x = arg[0]; y = arg[1]; /* generate font index / shift information */ font = dfont_get(); if (font->shape.prop == 1) { glyph_width = font->glyph.prop[glyph_idx].width; glyph_shift = font->glyph.prop[glyph_idx].shift; glyph_idx = font->glyph.prop[glyph_idx].index; glyph_size = glyph_width * font->glyph.height; } else { glyph_width = font->glyph.mono.width; glyph_size = font->glyph.mono.storage_size; glyph_shift = glyph_size * glyph_idx; glyph_idx = glyph_shift >> 8; glyph_shift = glyph_shift & 0xff; } /* drawing algo */ //TODO: cache surface data (limit read/write) sx = x; counter = 0; glyph_shift = 0x80000000 >> glyph_shift; glyph_bitmap = font->glyph.data[glyph_idx]; for (int i = 0; i < glyph_size; ++i) { if (glyph_bitmap & glyph_shift) { dpixel_render(surface, x, y, arg[4]); } else { dpixel_render(surface, x, y, arg[5]); } /* update font bitmap index / shift */ glyph_shift >>= 1; if (glyph_shift == 0x00000000) { glyph_shift = 0x80000000; glyph_bitmap = font->glyph.data[++glyph_idx]; } /* update bitmap position */ x += 1; counter += 1; if (counter >= glyph_width) { counter = 0; x = sx; y += 1; } } } //--- // Kernel-level API //--- /* dfont_render() : draw caracter in surface */ void dfont_text_render(struct dshader_surface *surface, uint32_t *arg) { uint32_t code_point; uint8_t const * str; font_t *font; int glyph_idx; int glyph_width; int counter; int sx; int sy; /* check culling */ if ( ( (int)arg[3] < surface->y && (int)arg[1] >= (int)(surface->y + surface->height) ) || ( (int)arg[2] < surface->x && (int)arg[0] >= (int)(surface->x + surface->width) )) { return; } /* draw algo (update me) */ sx = arg[0]; sy = arg[1]; counter = -1; font = dfont_get(); str = (void*)(uintptr_t)arg[6]; while (++counter < (int)arg[7]) { code_point = dfont_utf8_next(&str); if (code_point == '\n') { arg[1] += font->glyph.height; arg[0] = sx; continue; } glyph_idx = dfont_glyph_index(font, code_point); glyph_width = font->glyph.mono.width; if (font->shape.prop == 1) glyph_width = font->glyph.prop[glyph_idx].width; dfont_char_render(surface, glyph_idx, arg); arg[0] += glyph_width + font->char_spacing; } arg[1] = sy; arg[0] = sx; } //--- // Public API //--- /* dfont_get() : get the current font */ font_t *dfont_get(void) { extern font_t font8x9; return &font8x9; } /* dfont_geometry() : get the char geometry */ int dfont_text_geometry( font_t *font, char const * const str_char, int *size, size_t *w, size_t *h ) { uint8_t const *str0 = (void *)str_char; uint8_t const *str1 = (void *)str_char; uint32_t code_point; size_t length = 0; size_t mx = 0; size_t x = 0; size_t y = 0; size_t glyph_width; int glyph_idx; int limit; /* handle special behaviour */ if (font == NULL) font = dfont_get(); limit = -1; if (size != NULL && *size >= 0) limit = *size; /* generate geometry information */ while (1) { code_point = dfont_utf8_next(&str0); if (code_point == 0 || (limit > 0 && str0 - str1 >= limit)) break; /* line discipline */ length++; if (code_point == '\n') { y += font->glyph.height; x = 0; continue; } glyph_width = font->glyph.mono.width; if (font->shape.prop == 1) { glyph_idx = dfont_glyph_index(font, code_point); if (glyph_idx < 0) { if (w != NULL) *w = 0; if (h != NULL) *h = 0; if (size != NULL) *size = length; return (-1); } glyph_width = font->glyph.prop[glyph_idx].width; } x += glyph_width + font->char_spacing; if (x > mx) mx = x; } /* set geometry information */ if (w != NULL) *w = mx - font->char_spacing; if (h != NULL) *h = y; if (size != NULL) *size = length; return (0); }