diff -r 000000000000 -r 88d965579617 components/u8g2/csrc/u8g2_font.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/components/u8g2/csrc/u8g2_font.c Tue Oct 08 12:00:31 2019 +0200 @@ -0,0 +1,1248 @@ +/* + + u8g2_font.c + + Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/) + + Copyright (c) 2016, olikraus@gmail.com + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "u8g2.h" + +/* size of the font data structure, there is no struct or class... */ +/* this is the size for the new font format */ +#define U8G2_FONT_DATA_STRUCT_SIZE 23 + +/* + font data: + + offset bytes description + 0 1 glyph_cnt number of glyphs + 1 1 bbx_mode 0: proportional, 1: common height, 2: monospace, 3: multiple of 8 + 2 1 bits_per_0 glyph rle parameter + 3 1 bits_per_1 glyph rle parameter + + 4 1 bits_per_char_width glyph rle parameter + 5 1 bits_per_char_height glyph rle parameter + 6 1 bits_per_char_x glyph rle parameter + 7 1 bits_per_char_y glyph rle parameter + 8 1 bits_per_delta_x glyph rle parameter + + 9 1 max_char_width + 10 1 max_char_height + 11 1 x offset + 12 1 y offset (descent) + + 13 1 ascent (capital A) + 14 1 descent (lower g) + 15 1 ascent '(' + 16 1 descent ')' + + 17 1 start pos 'A' high byte + 18 1 start pos 'A' low byte + + 19 1 start pos 'a' high byte + 20 1 start pos 'a' low byte + + 21 1 start pos unicode high byte + 22 1 start pos unicode low byte + + Font build mode, 0: proportional, 1: common height, 2: monospace, 3: multiple of 8 + + Font build mode 0: + - "t" + - Ref height mode: U8G2_FONT_HEIGHT_MODE_TEXT, U8G2_FONT_HEIGHT_MODE_XTEXT or U8G2_FONT_HEIGHT_MODE_ALL + - use in transparent mode only (does not look good in solid mode) + - most compact format + - different font heights possible + + Font build mode 1: + - "h" + - Ref height mode: U8G2_FONT_HEIGHT_MODE_ALL + - transparent or solid mode + - The height of the glyphs depend on the largest glyph in the font. This means font height depends on postfix "r", "f" and "n". + +*/ + +/* use case: What is the width and the height of the minimal box into which string s fints? */ +void u8g2_font_GetStrSize(const void *font, const char *s, u8g2_uint_t *width, u8g2_uint_t *height); +void u8g2_font_GetStrSizeP(const void *font, const char *s, u8g2_uint_t *width, u8g2_uint_t *height); + +/* use case: lower left edge of a minimal box is known, what is the correct x, y position for the string draw procedure */ +void u8g2_font_AdjustXYToDraw(const void *font, const char *s, u8g2_uint_t *x, u8g2_uint_t *y); +void u8g2_font_AdjustXYToDrawP(const void *font, const char *s, u8g2_uint_t *x, u8g2_uint_t *y); + +/* use case: Baseline origin known, return minimal box */ +void u8g2_font_GetStrMinBox(u8g2_t *u8g2, const void *font, const char *s, u8g2_uint_t *x, u8g2_uint_t *y, u8g2_uint_t *width, u8g2_uint_t *height); + +/* procedures */ + +/*========================================================================*/ +/* low level byte and word access */ + +/* removed NOINLINE, because it leads to smaller code, might also be faster */ +//static uint8_t u8g2_font_get_byte(const uint8_t *font, uint8_t offset) U8G2_NOINLINE; +static uint8_t u8g2_font_get_byte(const uint8_t *font, uint8_t offset) +{ + font += offset; + return u8x8_pgm_read( font ); +} + +static uint16_t u8g2_font_get_word(const uint8_t *font, uint8_t offset) U8G2_NOINLINE; +static uint16_t u8g2_font_get_word(const uint8_t *font, uint8_t offset) +{ + uint16_t pos; + font += offset; + pos = u8x8_pgm_read( font ); + font++; + pos <<= 8; + pos += u8x8_pgm_read( font); + return pos; +} + +/*========================================================================*/ +/* new font format */ +void u8g2_read_font_info(u8g2_font_info_t *font_info, const uint8_t *font) +{ + /* offset 0 */ + font_info->glyph_cnt = u8g2_font_get_byte(font, 0); + font_info->bbx_mode = u8g2_font_get_byte(font, 1); + font_info->bits_per_0 = u8g2_font_get_byte(font, 2); + font_info->bits_per_1 = u8g2_font_get_byte(font, 3); + + /* offset 4 */ + font_info->bits_per_char_width = u8g2_font_get_byte(font, 4); + font_info->bits_per_char_height = u8g2_font_get_byte(font, 5); + font_info->bits_per_char_x = u8g2_font_get_byte(font, 6); + font_info->bits_per_char_y = u8g2_font_get_byte(font, 7); + font_info->bits_per_delta_x = u8g2_font_get_byte(font, 8); + + /* offset 9 */ + font_info->max_char_width = u8g2_font_get_byte(font, 9); + font_info->max_char_height = u8g2_font_get_byte(font, 10); + font_info->x_offset = u8g2_font_get_byte(font, 11); + font_info->y_offset = u8g2_font_get_byte(font, 12); + + /* offset 13 */ + font_info->ascent_A = u8g2_font_get_byte(font, 13); + font_info->descent_g = u8g2_font_get_byte(font, 14); + font_info->ascent_para = u8g2_font_get_byte(font, 15); + font_info->descent_para = u8g2_font_get_byte(font, 16); + + /* offset 17 */ + font_info->start_pos_upper_A = u8g2_font_get_word(font, 17); + font_info->start_pos_lower_a = u8g2_font_get_word(font, 19); + + /* offset 21 */ +#ifdef U8G2_WITH_UNICODE + font_info->start_pos_unicode = u8g2_font_get_word(font, 21); +#endif +} + + +/* calculate the overall length of the font, only used to create the picture for the google wiki */ +size_t u8g2_GetFontSize(const uint8_t *font_arg) +{ + uint16_t e; + const uint8_t *font = font_arg; + font += U8G2_FONT_DATA_STRUCT_SIZE; + + for(;;) + { + if ( u8x8_pgm_read( font + 1 ) == 0 ) + break; + font += u8x8_pgm_read( font + 1 ); + } + + /* continue with unicode section */ + font += 2; + + /* skip unicode lookup table */ + font += u8g2_font_get_word(font, 0); + + for(;;) + { + e = u8x8_pgm_read( font ); + e <<= 8; + e |= u8x8_pgm_read( font + 1 ); + if ( e == 0 ) + break; + font += u8x8_pgm_read( font + 2 ); + } + + return (font - font_arg) + 2; +} + +/*========================================================================*/ +/* u8g2 interface, font access */ + +uint8_t u8g2_GetFontBBXWidth(u8g2_t *u8g2) +{ + return u8g2->font_info.max_char_width; /* new font info structure */ +} + +uint8_t u8g2_GetFontBBXHeight(u8g2_t *u8g2) +{ + return u8g2->font_info.max_char_height; /* new font info structure */ +} + +int8_t u8g2_GetFontBBXOffX(u8g2_t *u8g2) U8G2_NOINLINE; +int8_t u8g2_GetFontBBXOffX(u8g2_t *u8g2) +{ + return u8g2->font_info.x_offset; /* new font info structure */ +} + +int8_t u8g2_GetFontBBXOffY(u8g2_t *u8g2) U8G2_NOINLINE; +int8_t u8g2_GetFontBBXOffY(u8g2_t *u8g2) +{ + return u8g2->font_info.y_offset; /* new font info structure */ +} + +uint8_t u8g2_GetFontCapitalAHeight(u8g2_t *u8g2) U8G2_NOINLINE; +uint8_t u8g2_GetFontCapitalAHeight(u8g2_t *u8g2) +{ + return u8g2->font_info.ascent_A; /* new font info structure */ +} + +/*========================================================================*/ +/* glyph handling */ + +/* optimized */ +uint8_t u8g2_font_decode_get_unsigned_bits(u8g2_font_decode_t *f, uint8_t cnt) +{ + uint8_t val; + uint8_t bit_pos = f->decode_bit_pos; + uint8_t bit_pos_plus_cnt; + + //val = *(f->decode_ptr); + val = u8x8_pgm_read( f->decode_ptr ); + + val >>= bit_pos; + bit_pos_plus_cnt = bit_pos; + bit_pos_plus_cnt += cnt; + if ( bit_pos_plus_cnt >= 8 ) + { + uint8_t s = 8; + s -= bit_pos; + f->decode_ptr++; + //val |= *(f->decode_ptr) << (8-bit_pos); + val |= u8x8_pgm_read( f->decode_ptr ) << (s); + //bit_pos -= 8; + bit_pos_plus_cnt -= 8; + } + val &= (1U<decode_bit_pos = bit_pos_plus_cnt; + return val; +} + + +/* + 2 bit --> cnt = 2 + -2,-1,0. 1 + + 3 bit --> cnt = 3 + -2,-1,0. 1 + -4,-3,-2,-1,0,1,2,3 + + if ( x < 0 ) + r = bits(x-1)+1; + else + r = bits(x)+1; + +*/ +/* optimized */ +int8_t u8g2_font_decode_get_signed_bits(u8g2_font_decode_t *f, uint8_t cnt) +{ + int8_t v, d; + v = (int8_t)u8g2_font_decode_get_unsigned_bits(f, cnt); + d = 1; + cnt--; + d <<= cnt; + v -= d; + return v; + //return (int8_t)u8g2_font_decode_get_unsigned_bits(f, cnt) - ((1<>1); +} + + +#ifdef U8G2_WITH_FONT_ROTATION +static u8g2_uint_t u8g2_add_vector_y(u8g2_uint_t dy, int8_t x, int8_t y, uint8_t dir) U8G2_NOINLINE; +static u8g2_uint_t u8g2_add_vector_y(u8g2_uint_t dy, int8_t x, int8_t y, uint8_t dir) +{ + switch(dir) + { + case 0: + dy += y; + break; + case 1: + dy += x; + break; + case 2: + dy -= y; + break; + default: + dy -= x; + break; + } + return dy; +} + +static u8g2_uint_t u8g2_add_vector_x(u8g2_uint_t dx, int8_t x, int8_t y, uint8_t dir) U8G2_NOINLINE; +static u8g2_uint_t u8g2_add_vector_x(u8g2_uint_t dx, int8_t x, int8_t y, uint8_t dir) +{ + switch(dir) + { + case 0: + dx += x; + break; + case 1: + dx -= y; + break; + case 2: + dx -= x; + break; + default: + dx += y; + break; + } + return dx; +} +#endif + + + +/* + Description: + Draw a run-length area of the glyph. "len" can have any size and the line + length has to be wrapped at the glyph border. + Args: + len: Length of the line + is_foreground foreground/background? + u8g2->font_decode.target_x X position + u8g2->font_decode.target_y Y position + u8g2->font_decode.is_transparent Transparent mode + Return: + - + Calls: + u8g2_Draw90Line() + Called by: + u8g2_font_decode_glyph() +*/ +/* optimized */ +void u8g2_font_decode_len(u8g2_t *u8g2, uint8_t len, uint8_t is_foreground) +{ + uint8_t cnt; /* total number of remaining pixels, which have to be drawn */ + uint8_t rem; /* remaining pixel to the right edge of the glyph */ + uint8_t current; /* number of pixels, which need to be drawn for the draw procedure */ + /* current is either equal to cnt or equal to rem */ + + /* local coordinates of the glyph */ + uint8_t lx,ly; + + /* target position on the screen */ + u8g2_uint_t x, y; + + u8g2_font_decode_t *decode = &(u8g2->font_decode); + + cnt = len; + + /* get the local position */ + lx = decode->x; + ly = decode->y; + + for(;;) + { + /* calculate the number of pixel to the right edge of the glyph */ + rem = decode->glyph_width; + rem -= lx; + + /* calculate how many pixel to draw. This is either to the right edge */ + /* or lesser, if not enough pixel are left */ + current = rem; + if ( cnt < rem ) + current = cnt; + + + /* now draw the line, but apply the rotation around the glyph target position */ + //u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground); + + /* get target position */ + x = decode->target_x; + y = decode->target_y; + + /* apply rotation */ +#ifdef U8G2_WITH_FONT_ROTATION + x = u8g2_add_vector_x(x, lx, ly, decode->dir); + y = u8g2_add_vector_y(y, lx, ly, decode->dir); +#else + x += lx; + y += ly; +#endif + + /* draw foreground and background (if required) */ + if ( is_foreground ) + { + u8g2->draw_color = decode->fg_color; /* draw_color will be restored later */ + u8g2_DrawHVLine(u8g2, + x, + y, + current, +#ifdef U8G2_WITH_FONT_ROTATION + /* dir */ decode->dir +#else + 0 +#endif + ); + } + else if ( decode->is_transparent == 0 ) + { + u8g2->draw_color = decode->bg_color; /* draw_color will be restored later */ + u8g2_DrawHVLine(u8g2, + x, + y, + current, +#ifdef U8G2_WITH_FONT_ROTATION + /* dir */ decode->dir +#else + 0 +#endif + ); + } + + /* check, whether the end of the run length code has been reached */ + if ( cnt < rem ) + break; + cnt -= rem; + lx = 0; + ly++; + } + lx += cnt; + + decode->x = lx; + decode->y = ly; + +} + +static void u8g2_font_setup_decode(u8g2_t *u8g2, const uint8_t *glyph_data) +{ + u8g2_font_decode_t *decode = &(u8g2->font_decode); + decode->decode_ptr = glyph_data; + decode->decode_bit_pos = 0; + + /* 8 Nov 2015, this is already done in the glyph data search procedure */ + /* + decode->decode_ptr += 1; + decode->decode_ptr += 1; + */ + + decode->glyph_width = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_char_width); + decode->glyph_height = u8g2_font_decode_get_unsigned_bits(decode,u8g2->font_info.bits_per_char_height); + + decode->fg_color = u8g2->draw_color; + decode->bg_color = (decode->fg_color == 0 ? 1 : 0); +} + + +/* + Description: + Decode and draw a glyph. + Args: + glyph_data: Pointer to the compressed glyph data of the font + u8g2->font_decode.target_x X position + u8g2->font_decode.target_y Y position + u8g2->font_decode.is_transparent Transparent mode + Return: + Width (delta x advance) of the glyph. + Calls: + u8g2_font_decode_len() +*/ +/* optimized */ +int8_t u8g2_font_decode_glyph(u8g2_t *u8g2, const uint8_t *glyph_data) +{ + uint8_t a, b; + int8_t x, y; + int8_t d; + int8_t h; + u8g2_font_decode_t *decode = &(u8g2->font_decode); + + u8g2_font_setup_decode(u8g2, glyph_data); + h = u8g2->font_decode.glyph_height; + + x = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_x); + y = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_y); + d = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_delta_x); + + if ( decode->glyph_width > 0 ) + { +#ifdef U8G2_WITH_FONT_ROTATION + decode->target_x = u8g2_add_vector_x(decode->target_x, x, -(h+y), decode->dir); + decode->target_y = u8g2_add_vector_y(decode->target_y, x, -(h+y), decode->dir); +#else + decode->target_x += x; + decode->target_y -= h+y; +#endif + //u8g2_add_vector(&(decode->target_x), &(decode->target_y), x, -(h+y), decode->dir); + +#ifdef U8G2_WITH_INTERSECTION + { + u8g2_uint_t x0, x1, y0, y1; + x0 = decode->target_x; + y0 = decode->target_y; + x1 = x0; + y1 = y0; + +#ifdef U8G2_WITH_FONT_ROTATION + switch(decode->dir) + { + case 0: + x1 += decode->glyph_width; + y1 += h; + break; + case 1: + x0 -= h; + x0++; /* shift down, because of assymetric boundaries for the interseciton test */ + x1++; + y1 += decode->glyph_width; + break; + case 2: + x0 -= decode->glyph_width; + x0++; /* shift down, because of assymetric boundaries for the interseciton test */ + x1++; + y0 -= h; + y0++; /* shift down, because of assymetric boundaries for the interseciton test */ + y1++; + break; + case 3: + x1 += h; + y0 -= decode->glyph_width; + y0++; /* shift down, because of assymetric boundaries for the interseciton test */ + y1++; + break; + } +#else /* U8G2_WITH_FONT_ROTATION */ + x1 += decode->glyph_width; + y1 += h; +#endif + + if ( u8g2_IsIntersection(u8g2, x0, y0, x1, y1) == 0 ) + return d; + } +#endif /* U8G2_WITH_INTERSECTION */ + + /* reset local x/y position */ + decode->x = 0; + decode->y = 0; + + /* decode glyph */ + for(;;) + { + a = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_0); + b = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_1); + do + { + u8g2_font_decode_len(u8g2, a, 0); + u8g2_font_decode_len(u8g2, b, 1); + } while( u8g2_font_decode_get_unsigned_bits(decode, 1) != 0 ); + + if ( decode->y >= h ) + break; + } + + /* restore the u8g2 draw color, because this is modified by the decode algo */ + u8g2->draw_color = decode->fg_color; + } + return d; +} + +/* + Description: + Find the starting point of the glyph data. + Args: + encoding: Encoding (ASCII or Unicode) of the glyph + Return: + Address of the glyph data or NULL, if the encoding is not avialable in the font. +*/ +const uint8_t *u8g2_font_get_glyph_data(u8g2_t *u8g2, uint16_t encoding) +{ + const uint8_t *font = u8g2->font; + font += U8G2_FONT_DATA_STRUCT_SIZE; + + + if ( encoding <= 255 ) + { + if ( encoding >= 'a' ) + { + font += u8g2->font_info.start_pos_lower_a; + } + else if ( encoding >= 'A' ) + { + font += u8g2->font_info.start_pos_upper_A; + } + + for(;;) + { + if ( u8x8_pgm_read( font + 1 ) == 0 ) + break; + if ( u8x8_pgm_read( font ) == encoding ) + { + return font+2; /* skip encoding and glyph size */ + } + font += u8x8_pgm_read( font + 1 ); + } + } +#ifdef U8G2_WITH_UNICODE + else + { + uint16_t e; + const uint8_t *unicode_lookup_table; + +// removed, there is now the new index table +//#ifdef __unix__ +// if ( u8g2->last_font_data != NULL && encoding >= u8g2->last_unicode ) +// { +// font = u8g2->last_font_data; +// } +// else +//#endif + + font += u8g2->font_info.start_pos_unicode; + unicode_lookup_table = font; + + /* issue 596: search for the glyph start in the unicode lookup table */ + do + { + font += u8g2_font_get_word(unicode_lookup_table, 0); + e = u8g2_font_get_word(unicode_lookup_table, 2); + unicode_lookup_table+=4; + } while( e < encoding ); + + + for(;;) + { + e = u8x8_pgm_read( font ); + e <<= 8; + e |= u8x8_pgm_read( font + 1 ); + +// removed, there is now the new index table +//#ifdef __unix__ +// if ( encoding < e ) +// break; +//#endif + + if ( e == 0 ) + break; + + if ( e == encoding ) + { +// removed, there is now the new index table +//#ifdef __unix__ +// u8g2->last_font_data = font; +// u8g2->last_unicode = encoding; +//#endif + return font+3; /* skip encoding and glyph size */ + } + font += u8x8_pgm_read( font + 2 ); + } + } +#endif + + return NULL; +} + +static u8g2_uint_t u8g2_font_draw_glyph(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding) +{ + u8g2_uint_t dx = 0; + u8g2->font_decode.target_x = x; + u8g2->font_decode.target_y = y; + //u8g2->font_decode.is_transparent = is_transparent; this is already set + //u8g2->font_decode.dir = dir; + const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, encoding); + if ( glyph_data != NULL ) + { + dx = u8g2_font_decode_glyph(u8g2, glyph_data); + } + return dx; +} + + + +uint8_t u8g2_IsGlyph(u8g2_t *u8g2, uint16_t requested_encoding) +{ + /* updated to new code */ + if ( u8g2_font_get_glyph_data(u8g2, requested_encoding) != NULL ) + return 1; + return 0; +} + +/* side effect: updates u8g2->font_decode and u8g2->glyph_x_offset */ +int8_t u8g2_GetGlyphWidth(u8g2_t *u8g2, uint16_t requested_encoding) +{ + const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, requested_encoding); + if ( glyph_data == NULL ) + return 0; + + u8g2_font_setup_decode(u8g2, glyph_data); + u8g2->glyph_x_offset = u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_char_x); + u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_char_y); + + /* glyph width is here: u8g2->font_decode.glyph_width */ + + return u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_delta_x); +} + + +/* + set one of: + U8G2_FONT_MODE_TRANSPARENT + U8G2_FONT_MODE_SOLID + U8G2_FONT_MODE_NONE + This has been changed for the new font procedures +*/ +void u8g2_SetFontMode(u8g2_t *u8g2, uint8_t is_transparent) +{ + u8g2->font_decode.is_transparent = is_transparent; // new font procedures +} + +u8g2_uint_t u8g2_DrawGlyph(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding) +{ +#ifdef U8G2_WITH_FONT_ROTATION + switch(u8g2->font_decode.dir) + { + case 0: + y += u8g2->font_calc_vref(u8g2); + break; + case 1: + x -= u8g2->font_calc_vref(u8g2); + break; + case 2: + y -= u8g2->font_calc_vref(u8g2); + break; + case 3: + x += u8g2->font_calc_vref(u8g2); + break; + } +#else + y += u8g2->font_calc_vref(u8g2); +#endif + return u8g2_font_draw_glyph(u8g2, x, y, encoding); +} + +static u8g2_uint_t u8g2_draw_string(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str) U8G2_NOINLINE; +static u8g2_uint_t u8g2_draw_string(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str) +{ + uint16_t e; + u8g2_uint_t delta, sum; + u8x8_utf8_init(u8g2_GetU8x8(u8g2)); + sum = 0; + for(;;) + { + e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str); + if ( e == 0x0ffff ) + break; + str++; + if ( e != 0x0fffe ) + { + delta = u8g2_DrawGlyph(u8g2, x, y, e); + +#ifdef U8G2_WITH_FONT_ROTATION + switch(u8g2->font_decode.dir) + { + case 0: + x += delta; + break; + case 1: + y += delta; + break; + case 2: + x -= delta; + break; + case 3: + y -= delta; + break; + } +#else + x += delta; +#endif + + sum += delta; + } + } + return sum; +} + +u8g2_uint_t u8g2_DrawStr(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str) +{ + u8g2->u8x8.next_cb = u8x8_ascii_next; + return u8g2_draw_string(u8g2, x, y, str); +} + +/* +source: https://en.wikipedia.org/wiki/UTF-8 +Bits from to bytes Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 + 7 U+0000 U+007F 1 0xxxxxxx +11 U+0080 U+07FF 2 110xxxxx 10xxxxxx +16 U+0800 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx +21 U+10000 U+1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +26 U+200000 U+3FFFFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +31 U+4000000 U+7FFFFFFF 6 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +*/ +u8g2_uint_t u8g2_DrawUTF8(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str) +{ + u8g2->u8x8.next_cb = u8x8_utf8_next; + return u8g2_draw_string(u8g2, x, y, str); +} + + + +u8g2_uint_t u8g2_DrawExtendedUTF8(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, uint8_t to_left, u8g2_kerning_t *kerning, const char *str) +{ + u8g2->u8x8.next_cb = u8x8_utf8_next; + uint16_t e_prev = 0x0ffff; + uint16_t e; + u8g2_uint_t delta, sum, k; + u8x8_utf8_init(u8g2_GetU8x8(u8g2)); + sum = 0; + for(;;) + { + e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str); + if ( e == 0x0ffff ) + break; + str++; + if ( e != 0x0fffe ) + { + delta = u8g2_GetGlyphWidth(u8g2, e); + + if ( to_left ) + { + k = u8g2_GetKerning(u8g2, kerning, e, e_prev); + delta -= k; + x -= delta; + } + else + { + k = u8g2_GetKerning(u8g2, kerning, e_prev, e); + delta -= k; + } + e_prev = e; + + u8g2_DrawGlyph(u8g2, x, y, e); + if ( to_left ) + { + } + else + { + x += delta; + x -= k; + } + + sum += delta; + } + } + return sum; +} + +u8g2_uint_t u8g2_DrawExtUTF8(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, uint8_t to_left, const uint16_t *kerning_table, const char *str) +{ + u8g2->u8x8.next_cb = u8x8_utf8_next; + uint16_t e_prev = 0x0ffff; + uint16_t e; + u8g2_uint_t delta, sum, k; + u8x8_utf8_init(u8g2_GetU8x8(u8g2)); + sum = 0; + for(;;) + { + e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str); + if ( e == 0x0ffff ) + break; + str++; + if ( e != 0x0fffe ) + { + delta = u8g2_GetGlyphWidth(u8g2, e); + + if ( to_left ) + { + k = u8g2_GetKerningByTable(u8g2, kerning_table, e, e_prev); + delta -= k; + x -= delta; + } + else + { + k = u8g2_GetKerningByTable(u8g2, kerning_table, e_prev, e); + delta -= k; + } + e_prev = e; + + if ( to_left ) + { + } + else + { + x += delta; + } + u8g2_DrawGlyph(u8g2, x, y, e); + if ( to_left ) + { + } + else + { + //x += delta; + //x -= k; + } + + sum += delta; + } + } + return sum; +} + + + +/*===============================================*/ + +/* set ascent/descent for reference point calculation */ + +void u8g2_UpdateRefHeight(u8g2_t *u8g2) +{ + if ( u8g2->font == NULL ) + return; + u8g2->font_ref_ascent = u8g2->font_info.ascent_A; + u8g2->font_ref_descent = u8g2->font_info.descent_g; + if ( u8g2->font_height_mode == U8G2_FONT_HEIGHT_MODE_TEXT ) + { + } + else if ( u8g2->font_height_mode == U8G2_FONT_HEIGHT_MODE_XTEXT ) + { + if ( u8g2->font_ref_ascent < u8g2->font_info.ascent_para ) + u8g2->font_ref_ascent = u8g2->font_info.ascent_para; + if ( u8g2->font_ref_descent > u8g2->font_info.descent_para ) + u8g2->font_ref_descent = u8g2->font_info.descent_para; + } + else + { + if ( u8g2->font_ref_ascent < u8g2->font_info.max_char_height+u8g2->font_info.y_offset ) + u8g2->font_ref_ascent = u8g2->font_info.max_char_height+u8g2->font_info.y_offset; + if ( u8g2->font_ref_descent > u8g2->font_info.y_offset ) + u8g2->font_ref_descent = u8g2->font_info.y_offset; + } +} + +void u8g2_SetFontRefHeightText(u8g2_t *u8g2) +{ + u8g2->font_height_mode = U8G2_FONT_HEIGHT_MODE_TEXT; + u8g2_UpdateRefHeight(u8g2); +} + +void u8g2_SetFontRefHeightExtendedText(u8g2_t *u8g2) +{ + u8g2->font_height_mode = U8G2_FONT_HEIGHT_MODE_XTEXT; + u8g2_UpdateRefHeight(u8g2); +} + +void u8g2_SetFontRefHeightAll(u8g2_t *u8g2) +{ + u8g2->font_height_mode = U8G2_FONT_HEIGHT_MODE_ALL; + u8g2_UpdateRefHeight(u8g2); +} + +/*===============================================*/ +/* callback procedures to correct the y position */ + +u8g2_uint_t u8g2_font_calc_vref_font(U8X8_UNUSED u8g2_t *u8g2) +{ + return 0; +} + +void u8g2_SetFontPosBaseline(u8g2_t *u8g2) +{ + u8g2->font_calc_vref = u8g2_font_calc_vref_font; +} + + +u8g2_uint_t u8g2_font_calc_vref_bottom(u8g2_t *u8g2) +{ + return (u8g2_uint_t)(u8g2->font_ref_descent); +} + +void u8g2_SetFontPosBottom(u8g2_t *u8g2) +{ + u8g2->font_calc_vref = u8g2_font_calc_vref_bottom; +} + +u8g2_uint_t u8g2_font_calc_vref_top(u8g2_t *u8g2) +{ + u8g2_uint_t tmp; + /* reference pos is one pixel above the upper edge of the reference glyph */ + tmp = (u8g2_uint_t)(u8g2->font_ref_ascent); + tmp++; + return tmp; +} + +void u8g2_SetFontPosTop(u8g2_t *u8g2) +{ + u8g2->font_calc_vref = u8g2_font_calc_vref_top; +} + +u8g2_uint_t u8g2_font_calc_vref_center(u8g2_t *u8g2) +{ + int8_t tmp; + tmp = u8g2->font_ref_ascent; + tmp -= u8g2->font_ref_descent; + tmp /= 2; + tmp += u8g2->font_ref_descent; + return tmp; +} + +void u8g2_SetFontPosCenter(u8g2_t *u8g2) +{ + u8g2->font_calc_vref = u8g2_font_calc_vref_center; +} + +/*===============================================*/ + +void u8g2_SetFont(u8g2_t *u8g2, const uint8_t *font) +{ + if ( u8g2->font != font ) + { +//#ifdef __unix__ +// u8g2->last_font_data = NULL; +// u8g2->last_unicode = 0x0ffff; +//#endif + u8g2->font = font; + u8g2_read_font_info(&(u8g2->font_info), font); + u8g2_UpdateRefHeight(u8g2); + /* u8g2_SetFontPosBaseline(u8g2); */ /* removed with issue 195 */ + } +} + +/*===============================================*/ + +static uint8_t u8g2_is_all_valid(u8g2_t *u8g2, const char *str) U8G2_NOINLINE; +static uint8_t u8g2_is_all_valid(u8g2_t *u8g2, const char *str) +{ + uint16_t e; + u8x8_utf8_init(u8g2_GetU8x8(u8g2)); + for(;;) + { + e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str); + if ( e == 0x0ffff ) + break; + str++; + if ( e != 0x0fffe ) + { + if ( u8g2_font_get_glyph_data(u8g2, e) == NULL ) + return 0; + } + } + return 1; +} + +uint8_t u8g2_IsAllValidUTF8(u8g2_t *u8g2, const char *str) +{ + u8g2->u8x8.next_cb = u8x8_utf8_next; + return u8g2_is_all_valid(u8g2, str); +} + + +/* string calculation is stilll not 100% perfect as it addes the initial string offset to the overall size */ +static u8g2_uint_t u8g2_string_width(u8g2_t *u8g2, const char *str) U8G2_NOINLINE; +static u8g2_uint_t u8g2_string_width(u8g2_t *u8g2, const char *str) +{ + uint16_t e; + u8g2_uint_t w, dx; + + u8g2->font_decode.glyph_width = 0; + u8x8_utf8_init(u8g2_GetU8x8(u8g2)); + + /* reset the total width to zero, this will be expanded during calculation */ + w = 0; + dx = 0; + + // printf("str=<%s>\n", str); + + for(;;) + { + e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str); + if ( e == 0x0ffff ) + break; + str++; + if ( e != 0x0fffe ) + { + dx = u8g2_GetGlyphWidth(u8g2, e); /* delta x value of the glyph */ + w += dx; + } + } + + /* adjust the last glyph, check for issue #16: do not adjust if width is 0 */ + if ( u8g2->font_decode.glyph_width != 0 ) + { + w -= dx; + w += u8g2->font_decode.glyph_width; /* the real pixel width of the glyph, sideeffect of GetGlyphWidth */ + /* issue #46: we have to add the x offset also */ + w += u8g2->glyph_x_offset; /* this value is set as a side effect of u8g2_GetGlyphWidth() */ + } + // printf("w=%d \n", w); + + return w; +} + +static void u8g2_GetGlyphHorizontalProperties(u8g2_t *u8g2, uint16_t requested_encoding, uint8_t *w, int8_t *ox, int8_t *dx) +{ + const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, requested_encoding); + if ( glyph_data == NULL ) + return; + + u8g2_font_setup_decode(u8g2, glyph_data); + *w = u8g2->font_decode.glyph_width; + *ox = u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_char_x); + u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_char_y); + *dx = u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_delta_x); +} + +/* u8g compatible GetStrX function */ +int8_t u8g2_GetStrX(u8g2_t *u8g2, const char *s) +{ + uint8_t w; + int8_t ox, dx; + u8g2_GetGlyphHorizontalProperties(u8g2, *s, &w, &ox, &dx); + return ox; +} + + + +static u8g2_uint_t u8g2_calculate_exact_string_width(u8g2_t *u8g2, const char *str) +{ + + u8g2_uint_t w; + uint16_t enc; + uint8_t gw; + int8_t ox, dx; + + /* reset the total minimal width to zero, this will be expanded during calculation */ + w = 0; + + + /* check for empty string, width is already 0 */ + do + { + enc = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str); + str++; + } while( enc == 0x0fffe ); + + if ( enc== 0x0ffff ) + return w; + + /* get the glyph information of the first char. This must be valid, because we already checked for the empty string */ + /* if *s is not inside the font, then the cached parameters of the glyph are all zero */ + u8g2_GetGlyphHorizontalProperties(u8g2, enc, &gw, &ox, &dx); + + /* strlen(s) == 1: width = width(s[0]) */ + /* strlen(s) == 2: width = - offx(s[0]) + deltax(s[0]) + offx(s[1]) + width(s[1]) */ + /* strlen(s) == 3: width = - offx(s[0]) + deltax(s[0]) + deltax(s[1]) + offx(s[2]) + width(s[2]) */ + + /* assume that the string has size 2 or more, than start with negative offset-x */ + /* for string with size 1, this will be nullified after the loop */ + w = -ox; + for(;;) + { + + /* check and stop if the end of the string is reached */ + do + { + enc = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str); + str++; + } while( enc == 0x0fffe ); + if ( enc== 0x0ffff ) + break; + + u8g2_GetGlyphHorizontalProperties(u8g2, enc, &gw, &ox, &dx); + + /* if there are still more characters, add the delta to the next glyph */ + w += dx; + } + + /* finally calculate the width of the last char */ + /* here is another exception, if the last char is a black, use the dx value instead */ + if ( enc != ' ' ) + { + /* if g was not updated in the for loop (strlen() == 1), then the initial offset x gets removed */ + w += gw; + w += ox; + } + else + { + w += dx; + } + + + return w; + +} + + + + + +u8g2_uint_t u8g2_GetStrWidth(u8g2_t *u8g2, const char *s) +{ + u8g2->u8x8.next_cb = u8x8_ascii_next; + return u8g2_string_width(u8g2, s); +} + +u8g2_uint_t u8g2_GetExactStrWidth(u8g2_t *u8g2, const char *s) +{ + u8g2->u8x8.next_cb = u8x8_ascii_next; + return u8g2_calculate_exact_string_width(u8g2, s); +} + +/* +source: https://en.wikipedia.org/wiki/UTF-8 +Bits from to bytes Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 + 7 U+0000 U+007F 1 0xxxxxxx +11 U+0080 U+07FF 2 110xxxxx 10xxxxxx +16 U+0800 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx +21 U+10000 U+1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +26 U+200000 U+3FFFFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +31 U+4000000 U+7FFFFFFF 6 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +*/ +u8g2_uint_t u8g2_GetUTF8Width(u8g2_t *u8g2, const char *str) +{ + u8g2->u8x8.next_cb = u8x8_utf8_next; + return u8g2_string_width(u8g2, str); +} + + + +void u8g2_SetFontDirection(u8g2_t *u8g2, uint8_t dir) +{ +#ifdef U8G2_WITH_FONT_ROTATION + u8g2->font_decode.dir = dir; +#endif +} +