You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1221 lines
31 KiB
1221 lines
31 KiB
/* |
|
|
|
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<<cnt)-1; |
|
//bit_pos += cnt; |
|
|
|
f->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<<cnt)>>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 */ |
|
} |
|
} |
|
|
|
/*===============================================*/ |
|
|
|
/* 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 |
|
} |
|
|
|
|