 389ff92cc1
			
		
	
	
		389ff92cc1
		
			
		
	
	
	
	
		
			
			* Makefile, Scripts: new linter * About: remove ID from IC * Firmware: remove double define for DIVC/DIVR * Scripts: check folder names too. Docker: replace syntax check with make lint. * Reformat Sources and Migrate to new file naming convention * Docker: symlink clang-format-12 to clang-format * Add coding style guide
		
			
				
	
	
		
			1162 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1162 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
| 
 | |
|   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
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| /*
 | |
| // does not make sense, 50 bytes more required on avr
 | |
| void u8g2_add_vector(u8g2_uint_t *xp, u8g2_uint_t *yp, int8_t x, int8_t y, uint8_t dir)
 | |
| {
 | |
|   u8g2_uint_t x_ = *xp;
 | |
|   u8g2_uint_t y_ = *yp;
 | |
|   switch(dir)
 | |
|   {
 | |
|     case 0:
 | |
|       y_ += y;
 | |
|       x_ += x;
 | |
|       break;
 | |
|     case 1:
 | |
|       y_ += x;
 | |
|       x_ -= y;
 | |
|       break;
 | |
|     case 2:
 | |
|       y_ -= y;
 | |
|       x_ -= x;
 | |
|       break;
 | |
|     default:
 | |
|       y_ -= x;
 | |
|       x_ += y;
 | |
|       break;      
 | |
|   }
 | |
|   *xp = x_;
 | |
|   *yp = y_;
 | |
| }
 | |
| */
 | |
| #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);
 | |
| 
 | |
|         //u8g2_add_vector(&x, &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);
 | |
| 
 | |
|         //u8g2_add_vector(&(decode->target_x), &(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;
 | |
|             }
 | |
| 
 | |
|             /*
 | |
|       // requires 10 bytes more on avr
 | |
|       x = u8g2_add_vector_x(x, delta, 0, u8g2->font_decode.dir);
 | |
|       y = u8g2_add_vector_y(y, delta, 0, u8g2->font_decode.dir);
 | |
|       */
 | |
| 
 | |
| #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_long_t u8g2_string_width(u8g2_t* u8g2, const char* str) U8G2_NOINLINE;
 | |
| static u8g2_long_t u8g2_string_width(u8g2_t* u8g2, const char* str) {
 | |
|     uint16_t e;
 | |
|     u8g2_uint_t dx;
 | |
|     u8g2_long_t w;
 | |
| 
 | |
|     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_long_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
 | |
| }
 |