Krolyxon
Commit 1d55752

Branches

Tags

Refs →

orion-rf.piolibdepsesp32-s3-n16r8U8g2srcclibu8g2_font.c

1619 lines · 41.4 KB · C

1/*
2
3 u8g2_font.c
4
5 Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
6
7 Copyright (c) 2016, olikraus@gmail.com
8 All rights reserved.
9
10 Redistribution and use in source and binary forms, with or without modification,
11 are permitted provided that the following conditions are met:
12
13 * Redistributions of source code must retain the above copyright notice, this list
14 of conditions and the following disclaimer.
15
16 * Redistributions in binary form must reproduce the above copyright notice, this
17 list of conditions and the following disclaimer in the documentation and/or other
18 materials provided with the distribution.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
21 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
22 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
25 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34*/
35
36#include "u8g2.h"
37
38/* size of the font data structure, there is no struct or class... */
39/* this is the size for the new font format */
40#define U8G2_FONT_DATA_STRUCT_SIZE 23
41
42/*
43 font data:
44
45 offset bytes description
46 0 1 glyph_cnt number of glyphs
47 1 1 bbx_mode 0: proportional, 1: common height, 2: monospace, 3: multiple of 8
48 2 1 bits_per_0 glyph rle parameter
49 3 1 bits_per_1 glyph rle parameter
50
51 4 1 bits_per_char_width glyph rle parameter
52 5 1 bits_per_char_height glyph rle parameter
53 6 1 bits_per_char_x glyph rle parameter
54 7 1 bits_per_char_y glyph rle parameter
55 8 1 bits_per_delta_x glyph rle parameter
56
57 9 1 max_char_width
58 10 1 max_char_height
59 11 1 x offset
60 12 1 y offset (descent)
61
62 13 1 ascent (capital A)
63 14 1 descent (lower g)
64 15 1 ascent '('
65 16 1 descent ')'
66
67 17 1 start pos 'A' high byte
68 18 1 start pos 'A' low byte
69
70 19 1 start pos 'a' high byte
71 20 1 start pos 'a' low byte
72
73 21 1 start pos unicode high byte
74 22 1 start pos unicode low byte
75
76 Font build mode, 0: proportional, 1: common height, 2: monospace, 3: multiple of 8
77
78 Font build mode 0:
79 - "t"
80 - Ref height mode: U8G2_FONT_HEIGHT_MODE_TEXT, U8G2_FONT_HEIGHT_MODE_XTEXT or U8G2_FONT_HEIGHT_MODE_ALL
81 - use in transparent mode only (does not look good in solid mode)
82 - most compact format
83 - different font heights possible
84
85 Font build mode 1:
86 - "h"
87 - Ref height mode: U8G2_FONT_HEIGHT_MODE_ALL
88 - transparent or solid mode
89 - The height of the glyphs depend on the largest glyph in the font. This means font height depends on postfix "r", "f" and "n".
90
91*/
92
93/* use case: What is the width and the height of the minimal box into which string s fints? */
94void u8g2_font_GetStrSize(const void *font, const char *s, u8g2_uint_t *width, u8g2_uint_t *height);
95void u8g2_font_GetStrSizeP(const void *font, const char *s, u8g2_uint_t *width, u8g2_uint_t *height);
96
97/* use case: lower left edge of a minimal box is known, what is the correct x, y position for the string draw procedure */
98void u8g2_font_AdjustXYToDraw(const void *font, const char *s, u8g2_uint_t *x, u8g2_uint_t *y);
99void u8g2_font_AdjustXYToDrawP(const void *font, const char *s, u8g2_uint_t *x, u8g2_uint_t *y);
100
101/* use case: Baseline origin known, return minimal box */
102void 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);
103
104/* procedures */
105
106/*========================================================================*/
107/* low level byte and word access */
108
109/* removed NOINLINE, because it leads to smaller code, might also be faster */
110//static uint8_t u8g2_font_get_byte(const uint8_t *font, uint8_t offset) U8G2_NOINLINE;
111static uint8_t u8g2_font_get_byte(const uint8_t *font, uint8_t offset)
112{
113 font += offset;
114 return u8x8_pgm_read( font );
115}
116
117static uint16_t u8g2_font_get_word(const uint8_t *font, uint8_t offset) U8G2_NOINLINE;
118static uint16_t u8g2_font_get_word(const uint8_t *font, uint8_t offset)
119{
120 uint16_t pos;
121 font += offset;
122 pos = u8x8_pgm_read( font );
123 font++;
124 pos <<= 8;
125 pos += u8x8_pgm_read( font);
126 return pos;
127}
128
129/*========================================================================*/
130/* new font format */
131void u8g2_read_font_info(u8g2_font_info_t *font_info, const uint8_t *font)
132{
133 /* offset 0 */
134 font_info->glyph_cnt = u8g2_font_get_byte(font, 0);
135 font_info->bbx_mode = u8g2_font_get_byte(font, 1);
136 font_info->bits_per_0 = u8g2_font_get_byte(font, 2);
137 font_info->bits_per_1 = u8g2_font_get_byte(font, 3);
138
139 /* offset 4 */
140 font_info->bits_per_char_width = u8g2_font_get_byte(font, 4);
141 font_info->bits_per_char_height = u8g2_font_get_byte(font, 5);
142 font_info->bits_per_char_x = u8g2_font_get_byte(font, 6);
143 font_info->bits_per_char_y = u8g2_font_get_byte(font, 7);
144 font_info->bits_per_delta_x = u8g2_font_get_byte(font, 8);
145
146 /* offset 9 */
147 font_info->max_char_width = u8g2_font_get_byte(font, 9);
148 font_info->max_char_height = u8g2_font_get_byte(font, 10);
149 font_info->x_offset = u8g2_font_get_byte(font, 11);
150 font_info->y_offset = u8g2_font_get_byte(font, 12);
151
152 /* offset 13 */
153 font_info->ascent_A = u8g2_font_get_byte(font, 13);
154 font_info->descent_g = u8g2_font_get_byte(font, 14);
155 font_info->ascent_para = u8g2_font_get_byte(font, 15);
156 font_info->descent_para = u8g2_font_get_byte(font, 16);
157
158 /* offset 17 */
159 font_info->start_pos_upper_A = u8g2_font_get_word(font, 17);
160 font_info->start_pos_lower_a = u8g2_font_get_word(font, 19);
161
162 /* offset 21 */
163#ifdef U8G2_WITH_UNICODE
164 font_info->start_pos_unicode = u8g2_font_get_word(font, 21);
165#endif
166}
167
168
169/* calculate the overall length of the font, only used to create the picture for the google wiki */
170size_t u8g2_GetFontSize(const uint8_t *font_arg)
171{
172 uint16_t e;
173 const uint8_t *font = font_arg;
174 font += U8G2_FONT_DATA_STRUCT_SIZE;
175
176 for(;;)
177 {
178 if ( u8x8_pgm_read( font + 1 ) == 0 )
179 break;
180 font += u8x8_pgm_read( font + 1 );
181 }
182
183 /* continue with unicode section */
184 font += 2;
185
186 /* skip unicode lookup table */
187 font += u8g2_font_get_word(font, 0);
188
189 for(;;)
190 {
191 e = u8x8_pgm_read( font );
192 e <<= 8;
193 e |= u8x8_pgm_read( font + 1 );
194 if ( e == 0 )
195 break;
196 font += u8x8_pgm_read( font + 2 );
197 }
198
199 return (font - font_arg) + 2;
200}
201
202/*========================================================================*/
203/* u8g2 interface, font access */
204
205uint8_t u8g2_GetFontBBXWidth(u8g2_t *u8g2)
206{
207 return u8g2->font_info.max_char_width; /* new font info structure */
208}
209
210uint8_t u8g2_GetFontBBXHeight(u8g2_t *u8g2)
211{
212 return u8g2->font_info.max_char_height; /* new font info structure */
213}
214
215int8_t u8g2_GetFontBBXOffX(u8g2_t *u8g2) U8G2_NOINLINE;
216int8_t u8g2_GetFontBBXOffX(u8g2_t *u8g2)
217{
218 return u8g2->font_info.x_offset; /* new font info structure */
219}
220
221int8_t u8g2_GetFontBBXOffY(u8g2_t *u8g2) U8G2_NOINLINE;
222int8_t u8g2_GetFontBBXOffY(u8g2_t *u8g2)
223{
224 return u8g2->font_info.y_offset; /* new font info structure */
225}
226
227uint8_t u8g2_GetFontCapitalAHeight(u8g2_t *u8g2) U8G2_NOINLINE;
228uint8_t u8g2_GetFontCapitalAHeight(u8g2_t *u8g2)
229{
230 return u8g2->font_info.ascent_A; /* new font info structure */
231}
232
233/*========================================================================*/
234/* glyph handling */
235
236/* optimized */
237uint8_t u8g2_font_decode_get_unsigned_bits(u8g2_font_decode_t *f, uint8_t cnt)
238{
239 uint8_t val;
240 uint8_t bit_pos = f->decode_bit_pos;
241 uint8_t bit_pos_plus_cnt;
242
243 //val = *(f->decode_ptr);
244 val = u8x8_pgm_read( f->decode_ptr );
245
246 val >>= bit_pos;
247 bit_pos_plus_cnt = bit_pos;
248 bit_pos_plus_cnt += cnt;
249 if ( bit_pos_plus_cnt >= 8 )
250 {
251 uint8_t s = 8;
252 s -= bit_pos;
253 f->decode_ptr++;
254 //val |= *(f->decode_ptr) << (8-bit_pos);
255 val |= u8x8_pgm_read( f->decode_ptr ) << (s);
256 //bit_pos -= 8;
257 bit_pos_plus_cnt -= 8;
258 }
259 val &= (1U<<cnt)-1;
260 //bit_pos += cnt;
261
262 f->decode_bit_pos = bit_pos_plus_cnt;
263 return val;
264}
265
266
267/*
268 2 bit --> cnt = 2
269 -2,-1,0. 1
270
271 3 bit --> cnt = 3
272 -2,-1,0. 1
273 -4,-3,-2,-1,0,1,2,3
274
275 if ( x < 0 )
276 r = bits(x-1)+1;
277 else
278 r = bits(x)+1;
279
280*/
281/* optimized */
282int8_t u8g2_font_decode_get_signed_bits(u8g2_font_decode_t *f, uint8_t cnt)
283{
284 int8_t v, d;
285 v = (int8_t)u8g2_font_decode_get_unsigned_bits(f, cnt);
286 d = 1;
287 cnt--;
288 d <<= cnt;
289 v -= d;
290 return v;
291 //return (int8_t)u8g2_font_decode_get_unsigned_bits(f, cnt) - ((1<<cnt)>>1);
292}
293
294
295#ifdef U8G2_WITH_FONT_ROTATION
296u8g2_uint_t u8g2_add_vector_y(u8g2_uint_t dy, int8_t x, int8_t y, uint8_t dir)
297{
298 switch(dir)
299 {
300 case 0:
301 dy += y;
302 break;
303 case 1:
304 dy += x;
305 break;
306 case 2:
307 dy -= y;
308 break;
309 default:
310 dy -= x;
311 break;
312 }
313 return dy;
314}
315
316u8g2_uint_t u8g2_add_vector_x(u8g2_uint_t dx, int8_t x, int8_t y, uint8_t dir)
317{
318 switch(dir)
319 {
320 case 0:
321 dx += x;
322 break;
323 case 1:
324 dx -= y;
325 break;
326 case 2:
327 dx -= x;
328 break;
329 default:
330 dx += y;
331 break;
332 }
333 return dx;
334}
335
336/*
337// does not make sense, 50 bytes more required on avr
338void u8g2_add_vector(u8g2_uint_t *xp, u8g2_uint_t *yp, int8_t x, int8_t y, uint8_t dir)
339{
340 u8g2_uint_t x_ = *xp;
341 u8g2_uint_t y_ = *yp;
342 switch(dir)
343 {
344 case 0:
345 y_ += y;
346 x_ += x;
347 break;
348 case 1:
349 y_ += x;
350 x_ -= y;
351 break;
352 case 2:
353 y_ -= y;
354 x_ -= x;
355 break;
356 default:
357 y_ -= x;
358 x_ += y;
359 break;
360 }
361 *xp = x_;
362 *yp = y_;
363}
364*/
365#endif
366
367
368
369/*
370 Description:
371 Draw a run-length area of the glyph. "len" can have any size and the line
372 length has to be wrapped at the glyph border.
373 Args:
374 len: Length of the line
375 is_foreground foreground/background?
376 u8g2->font_decode.target_x X position
377 u8g2->font_decode.target_y Y position
378 u8g2->font_decode.is_transparent Transparent mode
379 Return:
380 -
381 Calls:
382 u8g2_Draw90Line()
383 Called by:
384 u8g2_font_decode_glyph()
385*/
386/* optimized */
387void u8g2_font_decode_len(u8g2_t *u8g2, uint8_t len, uint8_t is_foreground)
388{
389 uint8_t cnt; /* total number of remaining pixels, which have to be drawn */
390 uint8_t rem; /* remaining pixel to the right edge of the glyph */
391 uint8_t current; /* number of pixels, which need to be drawn for the draw procedure */
392 /* current is either equal to cnt or equal to rem */
393
394 /* local coordinates of the glyph */
395 uint8_t lx,ly;
396
397 /* target position on the screen */
398 u8g2_uint_t x, y;
399
400 u8g2_font_decode_t *decode = &(u8g2->font_decode);
401
402 cnt = len;
403
404 /* get the local position */
405 lx = decode->x;
406 ly = decode->y;
407
408 for(;;)
409 {
410 /* calculate the number of pixel to the right edge of the glyph */
411 rem = decode->glyph_width;
412 rem -= lx;
413
414 /* calculate how many pixel to draw. This is either to the right edge */
415 /* or lesser, if not enough pixel are left */
416 current = rem;
417 if ( cnt < rem )
418 current = cnt;
419
420
421 /* now draw the line, but apply the rotation around the glyph target position */
422 //u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground);
423
424 /* get target position */
425 x = decode->target_x;
426 y = decode->target_y;
427
428 /* apply rotation */
429#ifdef U8G2_WITH_FONT_ROTATION
430
431 x = u8g2_add_vector_x(x, lx, ly, decode->dir);
432 y = u8g2_add_vector_y(y, lx, ly, decode->dir);
433
434 //u8g2_add_vector(&x, &y, lx, ly, decode->dir);
435
436#else
437 x += lx;
438 y += ly;
439#endif
440
441 /* draw foreground and background (if required) */
442 if ( is_foreground )
443 {
444 u8g2->draw_color = decode->fg_color; /* draw_color will be restored later */
445 u8g2_DrawHVLine(u8g2,
446 x,
447 y,
448 current,
449#ifdef U8G2_WITH_FONT_ROTATION
450 /* dir */ decode->dir
451#else
452 0
453#endif
454 );
455 }
456 else if ( decode->is_transparent == 0 )
457 {
458 u8g2->draw_color = decode->bg_color; /* draw_color will be restored later */
459 u8g2_DrawHVLine(u8g2,
460 x,
461 y,
462 current,
463#ifdef U8G2_WITH_FONT_ROTATION
464 /* dir */ decode->dir
465#else
466 0
467#endif
468 );
469 }
470
471 /* check, whether the end of the run length code has been reached */
472 if ( cnt < rem )
473 break;
474 cnt -= rem;
475 lx = 0;
476 ly++;
477 }
478 lx += cnt;
479
480 decode->x = lx;
481 decode->y = ly;
482}
483
484
485void u8g2_font_2x_decode_len(u8g2_t *u8g2, uint8_t len, uint8_t is_foreground)
486{
487 uint8_t cnt; /* total number of remaining pixels, which have to be drawn */
488 uint8_t rem; /* remaining pixel to the right edge of the glyph */
489 uint8_t current; /* number of pixels, which need to be drawn for the draw procedure */
490 /* current is either equal to cnt or equal to rem */
491
492 /* local coordinates of the glyph */
493 uint8_t lx,ly;
494
495 /* target position on the screen */
496 u8g2_uint_t x, y;
497
498 u8g2_font_decode_t *decode = &(u8g2->font_decode);
499
500 cnt = len;
501
502 /* get the local position */
503 lx = decode->x;
504 ly = decode->y;
505
506 for(;;)
507 {
508 /* calculate the number of pixel to the right edge of the glyph */
509 rem = decode->glyph_width;
510 rem -= lx;
511
512 /* calculate how many pixel to draw. This is either to the right edge */
513 /* or lesser, if not enough pixel are left */
514 current = rem;
515 if ( cnt < rem )
516 current = cnt;
517
518
519 /* now draw the line, but apply the rotation around the glyph target position */
520 //u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground);
521
522 /* get target position */
523 x = decode->target_x;
524 y = decode->target_y;
525
526 x += lx*2;
527 y += ly*2;
528
529 /* draw foreground and background (if required) */
530 if ( is_foreground )
531 {
532 u8g2->draw_color = decode->fg_color; /* draw_color will be restored later */
533 u8g2_DrawHVLine(u8g2,
534 x,
535 y,
536 current*2,
537 0
538 );
539 u8g2_DrawHVLine(u8g2,
540 x,
541 y+1,
542 current*2,
543 0
544 );
545 }
546 else if ( decode->is_transparent == 0 )
547 {
548 u8g2->draw_color = decode->bg_color; /* draw_color will be restored later */
549 u8g2_DrawHVLine(u8g2,
550 x,
551 y,
552 current*2,
553 0
554 );
555 u8g2_DrawHVLine(u8g2,
556 x,
557 y+1,
558 current*2,
559 0
560 );
561 }
562
563 /* check, whether the end of the run length code has been reached */
564 if ( cnt < rem )
565 break;
566 cnt -= rem;
567 lx = 0;
568 ly++;
569 }
570 lx += cnt;
571
572 decode->x = lx;
573 decode->y = ly;
574
575}
576
577
578static void u8g2_font_setup_decode(u8g2_t *u8g2, const uint8_t *glyph_data)
579{
580 u8g2_font_decode_t *decode = &(u8g2->font_decode);
581 decode->decode_ptr = glyph_data;
582 decode->decode_bit_pos = 0;
583
584 /* 8 Nov 2015, this is already done in the glyph data search procedure */
585 /*
586 decode->decode_ptr += 1;
587 decode->decode_ptr += 1;
588 */
589
590 decode->glyph_width = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_char_width);
591 decode->glyph_height = u8g2_font_decode_get_unsigned_bits(decode,u8g2->font_info.bits_per_char_height);
592
593 decode->fg_color = u8g2->draw_color;
594 decode->bg_color = (decode->fg_color == 0 ? 1 : 0);
595}
596
597
598/*
599 Description:
600 Decode and draw a glyph.
601 Args:
602 glyph_data: Pointer to the compressed glyph data of the font
603 u8g2->font_decode.target_x X position
604 u8g2->font_decode.target_y Y position
605 u8g2->font_decode.is_transparent Transparent mode
606 Return:
607 Width (delta x advance) of the glyph.
608 Calls:
609 u8g2_font_decode_len()
610*/
611/* optimized */
612int8_t u8g2_font_decode_glyph(u8g2_t *u8g2, const uint8_t *glyph_data)
613{
614 uint8_t a, b;
615 int8_t x, y;
616 int8_t d;
617 int8_t h;
618 u8g2_font_decode_t *decode = &(u8g2->font_decode);
619
620 u8g2_font_setup_decode(u8g2, glyph_data); /* set values in u8g2->font_decode data structure */
621 h = u8g2->font_decode.glyph_height;
622
623 x = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_x);
624 y = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_y);
625 d = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_delta_x);
626
627 if ( decode->glyph_width > 0 )
628 {
629#ifdef U8G2_WITH_FONT_ROTATION
630 decode->target_x = u8g2_add_vector_x(decode->target_x, x, -(h+y), decode->dir);
631 decode->target_y = u8g2_add_vector_y(decode->target_y, x, -(h+y), decode->dir);
632
633 //u8g2_add_vector(&(decode->target_x), &(decode->target_y), x, -(h+y), decode->dir);
634
635#else
636 decode->target_x += x;
637 decode->target_y -= h+y;
638#endif
639 //u8g2_add_vector(&(decode->target_x), &(decode->target_y), x, -(h+y), decode->dir);
640
641#ifdef U8G2_WITH_INTERSECTION
642 {
643 u8g2_uint_t x0, x1, y0, y1;
644 x0 = decode->target_x;
645 y0 = decode->target_y;
646 x1 = x0;
647 y1 = y0;
648
649#ifdef U8G2_WITH_FONT_ROTATION
650 switch(decode->dir)
651 {
652 case 0:
653 x1 += decode->glyph_width;
654 y1 += h;
655 break;
656 case 1:
657 x0 -= h;
658 x0++; /* shift down, because of assymetric boundaries for the interseciton test */
659 x1++;
660 y1 += decode->glyph_width;
661 break;
662 case 2:
663 x0 -= decode->glyph_width;
664 x0++; /* shift down, because of assymetric boundaries for the interseciton test */
665 x1++;
666 y0 -= h;
667 y0++; /* shift down, because of assymetric boundaries for the interseciton test */
668 y1++;
669 break;
670 case 3:
671 x1 += h;
672 y0 -= decode->glyph_width;
673 y0++; /* shift down, because of assymetric boundaries for the interseciton test */
674 y1++;
675 break;
676 }
677#else /* U8G2_WITH_FONT_ROTATION */
678 x1 += decode->glyph_width;
679 y1 += h;
680#endif
681
682 if ( u8g2_IsIntersection(u8g2, x0, y0, x1, y1) == 0 )
683 return d;
684 }
685#endif /* U8G2_WITH_INTERSECTION */
686
687 /* reset local x/y position */
688 decode->x = 0;
689 decode->y = 0;
690
691 /* decode glyph */
692 for(;;)
693 {
694 a = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_0);
695 b = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_1);
696 do
697 {
698 u8g2_font_decode_len(u8g2, a, 0);
699 u8g2_font_decode_len(u8g2, b, 1);
700 } while( u8g2_font_decode_get_unsigned_bits(decode, 1) != 0 );
701
702 if ( decode->y >= h )
703 break;
704 }
705
706 /* restore the u8g2 draw color, because this is modified by the decode algo */
707 u8g2->draw_color = decode->fg_color;
708 }
709 return d;
710}
711
712
713int8_t u8g2_font_2x_decode_glyph(u8g2_t *u8g2, const uint8_t *glyph_data)
714{
715 uint8_t a, b;
716 int8_t x, y;
717 int8_t d;
718 int8_t h;
719 u8g2_font_decode_t *decode = &(u8g2->font_decode);
720
721 u8g2_font_setup_decode(u8g2, glyph_data); /* set values in u8g2->font_decode data structure */
722 h = u8g2->font_decode.glyph_height;
723
724 x = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_x);
725 y = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_char_y);
726 d = u8g2_font_decode_get_signed_bits(decode, u8g2->font_info.bits_per_delta_x);
727
728 if ( decode->glyph_width > 0 )
729 {
730 decode->target_x += x;
731 decode->target_y -= 2*h+y;
732
733#ifdef U8G2_WITH_INTERSECTION
734 {
735 u8g2_uint_t x0, x1, y0, y1;
736 x0 = decode->target_x;
737 y0 = decode->target_y;
738 x1 = x0;
739 y1 = y0;
740
741 x1 += 2*decode->glyph_width;
742 y1 += 2*h;
743
744 if ( u8g2_IsIntersection(u8g2, x0, y0, x1, y1) == 0 )
745 return 2*d;
746 }
747#endif /* U8G2_WITH_INTERSECTION */
748
749 /* reset local x/y position */
750 decode->x = 0;
751 decode->y = 0;
752
753 /* decode glyph */
754 for(;;)
755 {
756 a = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_0);
757 b = u8g2_font_decode_get_unsigned_bits(decode, u8g2->font_info.bits_per_1);
758 do
759 {
760 u8g2_font_2x_decode_len(u8g2, a, 0);
761 u8g2_font_2x_decode_len(u8g2, b, 1);
762 } while( u8g2_font_decode_get_unsigned_bits(decode, 1) != 0 );
763
764 if ( decode->y >= h )
765 break;
766 }
767
768 /* restore the u8g2 draw color, because this is modified by the decode algo */
769 u8g2->draw_color = decode->fg_color;
770 }
771 return d*2;
772}
773
774/*
775 Description:
776 Find the starting point of the glyph data.
777 Args:
778 encoding: Encoding (ASCII or Unicode) of the glyph
779 Return:
780 Address of the glyph data or NULL, if the encoding is not avialable in the font.
781*/
782const uint8_t *u8g2_font_get_glyph_data(u8g2_t *u8g2, uint16_t encoding)
783{
784 const uint8_t *font = u8g2->font;
785 font += U8G2_FONT_DATA_STRUCT_SIZE;
786
787
788 if ( encoding <= 255 )
789 {
790 if ( encoding >= 'a' )
791 {
792 font += u8g2->font_info.start_pos_lower_a;
793 }
794 else if ( encoding >= 'A' )
795 {
796 font += u8g2->font_info.start_pos_upper_A;
797 }
798
799 for(;;)
800 {
801 if ( u8x8_pgm_read( font + 1 ) == 0 )
802 break;
803 if ( u8x8_pgm_read( font ) == encoding )
804 {
805 return font+2; /* skip encoding and glyph size */
806 }
807 font += u8x8_pgm_read( font + 1 );
808 }
809 }
810#ifdef U8G2_WITH_UNICODE
811 else
812 {
813 uint16_t e;
814 const uint8_t *unicode_lookup_table;
815
816// removed, there is now the new index table
817//#ifdef __unix__
818// if ( u8g2->last_font_data != NULL && encoding >= u8g2->last_unicode )
819// {
820// font = u8g2->last_font_data;
821// }
822// else
823//#endif
824
825 font += u8g2->font_info.start_pos_unicode;
826 unicode_lookup_table = font;
827
828 /* issue 596: search for the glyph start in the unicode lookup table */
829 do
830 {
831 font += u8g2_font_get_word(unicode_lookup_table, 0);
832 e = u8g2_font_get_word(unicode_lookup_table, 2);
833 unicode_lookup_table+=4;
834 } while( e < encoding );
835
836
837 for(;;)
838 {
839 e = u8x8_pgm_read( font );
840 e <<= 8;
841 e |= u8x8_pgm_read( font + 1 );
842
843// removed, there is now the new index table
844//#ifdef __unix__
845// if ( encoding < e )
846// break;
847//#endif
848
849 if ( e == 0 )
850 break;
851
852 if ( e == encoding )
853 {
854// removed, there is now the new index table
855//#ifdef __unix__
856// u8g2->last_font_data = font;
857// u8g2->last_unicode = encoding;
858//#endif
859 return font+3; /* skip encoding and glyph size */
860 }
861 font += u8x8_pgm_read( font + 2 );
862 }
863 }
864#endif
865
866 return NULL;
867}
868
869static u8g2_uint_t u8g2_font_draw_glyph(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding)
870{
871 u8g2_uint_t dx = 0;
872 u8g2->font_decode.target_x = x;
873 u8g2->font_decode.target_y = y;
874 //u8g2->font_decode.is_transparent = is_transparent; this is already set
875 //u8g2->font_decode.dir = dir;
876 const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, encoding);
877 if ( glyph_data != NULL )
878 {
879 dx = u8g2_font_decode_glyph(u8g2, glyph_data);
880 }
881 return dx;
882}
883
884static u8g2_uint_t u8g2_font_2x_draw_glyph(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding)
885{
886 u8g2_uint_t dx = 0;
887 u8g2->font_decode.target_x = x;
888 u8g2->font_decode.target_y = y;
889 const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, encoding);
890 if ( glyph_data != NULL )
891 {
892 dx = u8g2_font_2x_decode_glyph(u8g2, glyph_data);
893 }
894 return dx;
895}
896
897
898
899uint8_t u8g2_IsGlyph(u8g2_t *u8g2, uint16_t requested_encoding)
900{
901 /* updated to new code */
902 if ( u8g2_font_get_glyph_data(u8g2, requested_encoding) != NULL )
903 return 1;
904 return 0;
905}
906
907/* side effect: updates u8g2->font_decode and u8g2->glyph_x_offset */
908int8_t u8g2_GetGlyphWidth(u8g2_t *u8g2, uint16_t requested_encoding)
909{
910 const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, requested_encoding);
911 if ( glyph_data == NULL )
912 return 0;
913
914 u8g2_font_setup_decode(u8g2, glyph_data);
915 u8g2->glyph_x_offset = u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_char_x);
916 u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_char_y);
917
918 /* glyph width is here: u8g2->font_decode.glyph_width */
919
920 return u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_delta_x);
921}
922
923
924/*
925 set one of:
926 U8G2_FONT_MODE_TRANSPARENT
927 U8G2_FONT_MODE_SOLID
928 U8G2_FONT_MODE_NONE
929 This has been changed for the new font procedures
930*/
931void u8g2_SetFontMode(u8g2_t *u8g2, uint8_t is_transparent)
932{
933 u8g2->font_decode.is_transparent = is_transparent; // new font procedures
934}
935
936u8g2_uint_t u8g2_DrawGlyph(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding)
937{
938#ifdef U8G2_WITH_FONT_ROTATION
939 switch(u8g2->font_decode.dir)
940 {
941 case 0:
942 y += u8g2->font_calc_vref(u8g2);
943 break;
944 case 1:
945 x -= u8g2->font_calc_vref(u8g2);
946 break;
947 case 2:
948 y -= u8g2->font_calc_vref(u8g2);
949 break;
950 case 3:
951 x += u8g2->font_calc_vref(u8g2);
952 break;
953 }
954#else
955 y += u8g2->font_calc_vref(u8g2);
956#endif
957 return u8g2_font_draw_glyph(u8g2, x, y, encoding);
958}
959
960u8g2_uint_t u8g2_DrawGlyphX2(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding)
961{
962 y += 2*u8g2->font_calc_vref(u8g2);
963 return u8g2_font_2x_draw_glyph(u8g2, x, y, encoding);
964}
965
966static u8g2_uint_t u8g2_draw_string(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str) U8G2_NOINLINE;
967static u8g2_uint_t u8g2_draw_string(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str)
968{
969 uint16_t e;
970 u8g2_uint_t delta, sum;
971 u8x8_utf8_init(u8g2_GetU8x8(u8g2));
972 sum = 0;
973 for(;;)
974 {
975 e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str);
976 if ( e == 0x0ffff )
977 break;
978 str++;
979 if ( e != 0x0fffe )
980 {
981 delta = u8g2_DrawGlyph(u8g2, x, y, e);
982
983#ifdef U8G2_WITH_FONT_ROTATION
984 switch(u8g2->font_decode.dir)
985 {
986 case 0:
987 x += delta;
988 break;
989 case 1:
990 y += delta;
991 break;
992 case 2:
993 x -= delta;
994 break;
995 case 3:
996 y -= delta;
997 break;
998 }
999
1000 /*
1001 // requires 10 bytes more on avr
1002 x = u8g2_add_vector_x(x, delta, 0, u8g2->font_decode.dir);
1003 y = u8g2_add_vector_y(y, delta, 0, u8g2->font_decode.dir);
1004 */
1005
1006#else
1007 x += delta;
1008#endif
1009
1010 sum += delta;
1011 }
1012 }
1013 return sum;
1014}
1015
1016static u8g2_uint_t u8g2_draw_string_2x(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str) U8G2_NOINLINE;
1017static u8g2_uint_t u8g2_draw_string_2x(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str)
1018{
1019 uint16_t e;
1020 u8g2_uint_t delta, sum;
1021 u8x8_utf8_init(u8g2_GetU8x8(u8g2));
1022 sum = 0;
1023 for(;;)
1024 {
1025 e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str);
1026 if ( e == 0x0ffff )
1027 break;
1028 str++;
1029 if ( e != 0x0fffe )
1030 {
1031 delta = u8g2_DrawGlyphX2(u8g2, x, y, e);
1032 x += delta;
1033 sum += delta;
1034 }
1035 }
1036 return sum;
1037}
1038
1039u8g2_uint_t u8g2_DrawStr(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str)
1040{
1041 u8g2->u8x8.next_cb = u8x8_ascii_next;
1042 return u8g2_draw_string(u8g2, x, y, str);
1043}
1044
1045u8g2_uint_t u8g2_DrawStrX2(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str)
1046{
1047 u8g2->u8x8.next_cb = u8x8_ascii_next;
1048 return u8g2_draw_string_2x(u8g2, x, y, str);
1049}
1050
1051/*
1052source: https://en.wikipedia.org/wiki/UTF-8
1053Bits from to bytes Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6
1054 7 U+0000 U+007F 1 0xxxxxxx
105511 U+0080 U+07FF 2 110xxxxx 10xxxxxx
105616 U+0800 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
105721 U+10000 U+1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
105826 U+200000 U+3FFFFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
105931 U+4000000 U+7FFFFFFF 6 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1060*/
1061u8g2_uint_t u8g2_DrawUTF8(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str)
1062{
1063 u8g2->u8x8.next_cb = u8x8_utf8_next;
1064 return u8g2_draw_string(u8g2, x, y, str);
1065}
1066
1067u8g2_uint_t u8g2_DrawUTF8X2(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str)
1068{
1069 u8g2->u8x8.next_cb = u8x8_utf8_next;
1070 return u8g2_draw_string_2x(u8g2, x, y, str);
1071}
1072
1073
1074u8g2_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)
1075{
1076 u8g2->u8x8.next_cb = u8x8_utf8_next;
1077 uint16_t e_prev = 0x0ffff;
1078 uint16_t e;
1079 u8g2_uint_t delta, sum, k;
1080 u8x8_utf8_init(u8g2_GetU8x8(u8g2));
1081 sum = 0;
1082 for(;;)
1083 {
1084 e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str);
1085 if ( e == 0x0ffff )
1086 break;
1087 str++;
1088 if ( e != 0x0fffe )
1089 {
1090 delta = u8g2_GetGlyphWidth(u8g2, e);
1091
1092 if ( to_left )
1093 {
1094 k = u8g2_GetKerning(u8g2, kerning, e, e_prev);
1095 delta -= k;
1096 x -= delta;
1097 }
1098 else
1099 {
1100 k = u8g2_GetKerning(u8g2, kerning, e_prev, e);
1101 delta -= k;
1102 }
1103 e_prev = e;
1104
1105 u8g2_DrawGlyph(u8g2, x, y, e);
1106 if ( to_left )
1107 {
1108 }
1109 else
1110 {
1111 x += delta;
1112 x -= k;
1113 }
1114
1115 sum += delta;
1116 }
1117 }
1118 return sum;
1119}
1120
1121u8g2_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)
1122{
1123 u8g2->u8x8.next_cb = u8x8_utf8_next;
1124 uint16_t e_prev = 0x0ffff;
1125 uint16_t e;
1126 u8g2_uint_t delta, sum, k;
1127 u8x8_utf8_init(u8g2_GetU8x8(u8g2));
1128 sum = 0;
1129 for(;;)
1130 {
1131 e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str);
1132 if ( e == 0x0ffff )
1133 break;
1134 str++;
1135 if ( e != 0x0fffe )
1136 {
1137 delta = u8g2_GetGlyphWidth(u8g2, e);
1138
1139 if ( to_left )
1140 {
1141 k = u8g2_GetKerningByTable(u8g2, kerning_table, e, e_prev);
1142 delta -= k;
1143 x -= delta;
1144 }
1145 else
1146 {
1147 k = u8g2_GetKerningByTable(u8g2, kerning_table, e_prev, e);
1148 delta -= k;
1149 }
1150 e_prev = e;
1151
1152 if ( to_left )
1153 {
1154 }
1155 else
1156 {
1157 x += delta;
1158 }
1159 u8g2_DrawGlyph(u8g2, x, y, e);
1160 if ( to_left )
1161 {
1162 }
1163 else
1164 {
1165 //x += delta;
1166 //x -= k;
1167 }
1168
1169 sum += delta;
1170 }
1171 }
1172 return sum;
1173}
1174
1175
1176
1177/*===============================================*/
1178
1179/* set ascent/descent for reference point calculation */
1180
1181void u8g2_UpdateRefHeight(u8g2_t *u8g2)
1182{
1183 if ( u8g2->font == NULL )
1184 return;
1185 u8g2->font_ref_ascent = u8g2->font_info.ascent_A;
1186 u8g2->font_ref_descent = u8g2->font_info.descent_g;
1187 if ( u8g2->font_height_mode == U8G2_FONT_HEIGHT_MODE_TEXT )
1188 {
1189 }
1190 else if ( u8g2->font_height_mode == U8G2_FONT_HEIGHT_MODE_XTEXT )
1191 {
1192 if ( u8g2->font_ref_ascent < u8g2->font_info.ascent_para )
1193 u8g2->font_ref_ascent = u8g2->font_info.ascent_para;
1194 if ( u8g2->font_ref_descent > u8g2->font_info.descent_para )
1195 u8g2->font_ref_descent = u8g2->font_info.descent_para;
1196 }
1197 else
1198 {
1199 if ( u8g2->font_ref_ascent < u8g2->font_info.max_char_height+u8g2->font_info.y_offset )
1200 u8g2->font_ref_ascent = u8g2->font_info.max_char_height+u8g2->font_info.y_offset;
1201 if ( u8g2->font_ref_descent > u8g2->font_info.y_offset )
1202 u8g2->font_ref_descent = u8g2->font_info.y_offset;
1203 }
1204}
1205
1206void u8g2_SetFontRefHeightText(u8g2_t *u8g2)
1207{
1208 u8g2->font_height_mode = U8G2_FONT_HEIGHT_MODE_TEXT;
1209 u8g2_UpdateRefHeight(u8g2);
1210}
1211
1212void u8g2_SetFontRefHeightExtendedText(u8g2_t *u8g2)
1213{
1214 u8g2->font_height_mode = U8G2_FONT_HEIGHT_MODE_XTEXT;
1215 u8g2_UpdateRefHeight(u8g2);
1216}
1217
1218void u8g2_SetFontRefHeightAll(u8g2_t *u8g2)
1219{
1220 u8g2->font_height_mode = U8G2_FONT_HEIGHT_MODE_ALL;
1221 u8g2_UpdateRefHeight(u8g2);
1222}
1223
1224/*===============================================*/
1225/* callback procedures to correct the y position */
1226
1227u8g2_uint_t u8g2_font_calc_vref_font(U8X8_UNUSED u8g2_t *u8g2)
1228{
1229 return 0;
1230}
1231
1232void u8g2_SetFontPosBaseline(u8g2_t *u8g2)
1233{
1234 u8g2->font_calc_vref = u8g2_font_calc_vref_font;
1235}
1236
1237
1238u8g2_uint_t u8g2_font_calc_vref_bottom(u8g2_t *u8g2)
1239{
1240 return (u8g2_uint_t)(u8g2->font_ref_descent);
1241}
1242
1243void u8g2_SetFontPosBottom(u8g2_t *u8g2)
1244{
1245 u8g2->font_calc_vref = u8g2_font_calc_vref_bottom;
1246}
1247
1248u8g2_uint_t u8g2_font_calc_vref_top(u8g2_t *u8g2)
1249{
1250 u8g2_uint_t tmp;
1251 /* reference pos is one pixel above the upper edge of the reference glyph */
1252 tmp = (u8g2_uint_t)(u8g2->font_ref_ascent);
1253 tmp++;
1254 return tmp;
1255}
1256
1257void u8g2_SetFontPosTop(u8g2_t *u8g2)
1258{
1259 u8g2->font_calc_vref = u8g2_font_calc_vref_top;
1260}
1261
1262u8g2_uint_t u8g2_font_calc_vref_center(u8g2_t *u8g2)
1263{
1264 int8_t tmp;
1265 tmp = u8g2->font_ref_ascent;
1266 tmp -= u8g2->font_ref_descent;
1267 tmp /= 2;
1268 tmp += u8g2->font_ref_descent;
1269 return tmp;
1270}
1271
1272void u8g2_SetFontPosCenter(u8g2_t *u8g2)
1273{
1274 u8g2->font_calc_vref = u8g2_font_calc_vref_center;
1275}
1276
1277/*===============================================*/
1278
1279void u8g2_SetFont(u8g2_t *u8g2, const uint8_t *font)
1280{
1281 if ( u8g2->font != font )
1282 {
1283//#ifdef __unix__
1284// u8g2->last_font_data = NULL;
1285// u8g2->last_unicode = 0x0ffff;
1286//#endif
1287 u8g2->font = font;
1288 u8g2_read_font_info(&(u8g2->font_info), font);
1289 u8g2_UpdateRefHeight(u8g2);
1290 /* u8g2_SetFontPosBaseline(u8g2); */ /* removed with issue 195 */
1291 }
1292}
1293
1294/*===============================================*/
1295
1296static uint8_t u8g2_is_all_valid(u8g2_t *u8g2, const char *str) U8G2_NOINLINE;
1297static uint8_t u8g2_is_all_valid(u8g2_t *u8g2, const char *str)
1298{
1299 uint16_t e;
1300 u8x8_utf8_init(u8g2_GetU8x8(u8g2));
1301 for(;;)
1302 {
1303 e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str);
1304 if ( e == 0x0ffff )
1305 break;
1306 str++;
1307 if ( e != 0x0fffe )
1308 {
1309 if ( u8g2_font_get_glyph_data(u8g2, e) == NULL )
1310 return 0;
1311 }
1312 }
1313 return 1;
1314}
1315
1316uint8_t u8g2_IsAllValidUTF8(u8g2_t *u8g2, const char *str)
1317{
1318 u8g2->u8x8.next_cb = u8x8_utf8_next;
1319 return u8g2_is_all_valid(u8g2, str);
1320}
1321
1322
1323/* string calculation is stilll not 100% perfect as it addes the initial string offset to the overall size */
1324static u8g2_uint_t u8g2_string_width(u8g2_t *u8g2, const char *str) U8G2_NOINLINE;
1325static u8g2_uint_t u8g2_string_width(u8g2_t *u8g2, const char *str)
1326{
1327 uint16_t e;
1328 u8g2_uint_t w, dx;
1329#ifdef U8G2_BALANCED_STR_WIDTH_CALCULATION
1330 int8_t initial_x_offset = -64;
1331#endif
1332
1333 u8g2->font_decode.glyph_width = 0;
1334 u8x8_utf8_init(u8g2_GetU8x8(u8g2));
1335
1336 /* reset the total width to zero, this will be expanded during calculation */
1337 w = 0;
1338 dx = 0;
1339
1340 // printf("str=<%s>\n", str);
1341
1342 for(;;)
1343 {
1344 e = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str);
1345 if ( e == 0x0ffff )
1346 break;
1347 str++;
1348 if ( e != 0x0fffe )
1349 {
1350 dx = u8g2_GetGlyphWidth(u8g2, e); /* delta x value of the glyph, side effect: updates u8g2->glyph_x_offset */
1351#ifdef U8G2_BALANCED_STR_WIDTH_CALCULATION
1352 if ( initial_x_offset == -64 )
1353 initial_x_offset = u8g2->glyph_x_offset;
1354#endif
1355 //printf("'%c' x=%d dx=%d w=%d io=%d ", e, u8g2->glyph_x_offset, dx, u8g2->font_decode.glyph_width, initial_x_offset);
1356 w += dx;
1357 }
1358 }
1359 //printf("\n");
1360
1361 /* adjust the last glyph, check for issue #16: do not adjust if width is 0 */
1362 if ( u8g2->font_decode.glyph_width != 0 )
1363 {
1364 //printf("string width adjust dx=%d glyph_width=%d x-offset=%d\n", dx, u8g2->font_decode.glyph_width, u8g2->glyph_x_offset);
1365 w -= dx;
1366 w += u8g2->font_decode.glyph_width; /* the real pixel width of the glyph, sideeffect of GetGlyphWidth */
1367 /* issue #46: we have to add the x offset also */
1368 w += u8g2->glyph_x_offset; /* this value is set as a side effect of u8g2_GetGlyphWidth() */
1369#ifdef U8G2_BALANCED_STR_WIDTH_CALCULATION
1370 /* https://github.com/olikraus/u8g2/issues/1561 */
1371 if ( initial_x_offset > 0 )
1372 w+=initial_x_offset;
1373#endif
1374 }
1375 // printf("w=%d \n", w);
1376
1377 return w;
1378}
1379
1380int8_t u8g2_GetXOffsetGlyph(u8g2_t *u8g2, uint16_t encoding)
1381{
1382 u8g2_GetGlyphWidth(u8g2, encoding); /* delta x value of the glyph, side effect: updates u8g2->glyph_x_offset */
1383 return u8g2->glyph_x_offset;
1384}
1385
1386int8_t u8g2_GetXOffsetUTF8(u8g2_t *u8g2, const char *utf8)
1387{
1388 uint16_t e;
1389 u8x8_utf8_init(u8g2_GetU8x8(u8g2));
1390 for(;;) // extract encoding from UTF8 byte stream
1391 {
1392 e = u8x8_utf8_next(u8g2_GetU8x8(u8g2), (uint8_t)*utf8);
1393 if ( e == 0x0ffff )
1394 return 0;
1395 if ( e < 0x0fffe ) // 0x0fffe means: just continue
1396 break;
1397 utf8++;
1398 }
1399 return u8g2_GetXOffsetGlyph(u8g2, e);
1400}
1401
1402static void u8g2_GetGlyphHorizontalProperties(u8g2_t *u8g2, uint16_t requested_encoding, uint8_t *w, int8_t *ox, int8_t *dx)
1403{
1404 const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, requested_encoding);
1405 if ( glyph_data == NULL )
1406 return;
1407
1408 u8g2_font_setup_decode(u8g2, glyph_data);
1409 *w = u8g2->font_decode.glyph_width;
1410 *ox = u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_char_x);
1411 u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_char_y);
1412 *dx = u8g2_font_decode_get_signed_bits(&(u8g2->font_decode), u8g2->font_info.bits_per_delta_x);
1413}
1414
1415/* u8g compatible GetStrX function */
1416int8_t u8g2_GetStrX(u8g2_t *u8g2, const char *s)
1417{
1418 uint8_t w;
1419 int8_t dx;
1420 int8_t ox = 0;
1421 u8g2_GetGlyphHorizontalProperties(u8g2, *s, &w, &ox, &dx);
1422 return ox;
1423}
1424
1425
1426/*
1427Warning: This function needs to be fixed. I think it was taken over from u8glib, but not fixed as of now
1428The main difference for this procedure compared to the normal get width, should be, that the initial
1429offset is removed
1430
1431Idea: for the user interface it probably would be better to add the xoffset of the first char to the end, so that the overall word looks better.
1432Maybe then the procedure should be called differently, maybe balanced width instead of exact width
1433
1434u8g2_calculate_exact_string_width is now OBSOLETE, instead the above str width calculation has been updated:
1435https://github.com/olikraus/u8g2/issues/1561
1436*/
1437#ifdef OBSOLETE
1438static u8g2_uint_t u8g2_calculate_exact_string_width(u8g2_t *u8g2, const char *str)
1439{
1440 const char *s = str;
1441 uint16_t enc;
1442 u8g2_uint_t w;
1443 uint8_t cnt;
1444 uint8_t gw;
1445 int8_t ox, dx;
1446
1447 /* reset the total minimal width to zero, this will be expanded during calculation */
1448 w = 0;
1449
1450
1451 /* check for empty string, width is already 0 */
1452 cnt = 0;
1453
1454 for(;;)
1455 {
1456 enc = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*s);
1457 if ( enc == 0x0ffff )
1458 break;
1459 s++;
1460 if ( enc != 0x0fffe )
1461 {
1462 if ( cnt == 0 )
1463 {
1464 /* get glyph properties of the first char */
1465 u8g2_GetGlyphHorizontalProperties(u8g2, enc, &gw, &ox, &dx);
1466 }
1467 cnt++;
1468 if ( cnt > 2 )
1469 break;
1470 }
1471 }
1472
1473 if ( cnt == 0 )
1474 return 0;
1475
1476 if ( cnt == 1 )
1477 return gw;
1478
1479 /* strlen(s) == 1: width = width(s[0]) */
1480 /* strlen(s) == 2: width = - offx(s[0]) + deltax(s[0]) + offx(s[1]) + width(s[1]) */
1481 /* strlen(s) == 3: width = - offx(s[0]) + deltax(s[0]) + deltax(s[1]) + offx(s[2]) + width(s[2]) */
1482
1483 /* assume that the string has size 2 or more, than start with negative offset-x */
1484 /* for string with size 1, this will be nullified after the loop */
1485 w = -ox;
1486 for(;;)
1487 {
1488 enc = u8g2->u8x8.next_cb(u8g2_GetU8x8(u8g2), (uint8_t)*str);
1489 if ( enc== 0x0ffff )
1490 break;
1491 str++;
1492 if ( enc != 0x0fffe )
1493 {
1494 u8g2_GetGlyphHorizontalProperties(u8g2, enc, &gw, &ox, &dx);
1495 /* if there are still more characters, add the delta to the next glyph */
1496 w += dx;
1497 }
1498 }
1499
1500 /* finally calculate the width of the last char */
1501 /* here is another exception, if the last char is a blank, use the dx value instead */
1502 if ( gw != 0 )
1503 {
1504 w -= dx; /* remove the last dx */
1505 /* if g was not updated in the for loop (strlen() == 1), then the initial offset x gets removed */
1506 w += gw;
1507 w += ox;
1508 }
1509 else
1510 {
1511 //w += dx;
1512 }
1513
1514
1515 return w;
1516
1517}
1518#endif
1519
1520
1521
1522
1523
1524u8g2_uint_t u8g2_GetStrWidth(u8g2_t *u8g2, const char *s)
1525{
1526 u8g2->u8x8.next_cb = u8x8_ascii_next;
1527 return u8g2_string_width(u8g2, s);
1528}
1529
1530/* OBSOLETE
1531u8g2_uint_t u8g2_GetExactStrWidth(u8g2_t *u8g2, const char *s)
1532{
1533 u8g2->u8x8.next_cb = u8x8_ascii_next;
1534 return u8g2_calculate_exact_string_width(u8g2, s);
1535}
1536*/
1537
1538/*
1539source: https://en.wikipedia.org/wiki/UTF-8
1540Bits from to bytes Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6
1541 7 U+0000 U+007F 1 0xxxxxxx
154211 U+0080 U+07FF 2 110xxxxx 10xxxxxx
154316 U+0800 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
154421 U+10000 U+1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
154526 U+200000 U+3FFFFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
154631 U+4000000 U+7FFFFFFF 6 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1547*/
1548u8g2_uint_t u8g2_GetUTF8Width(u8g2_t *u8g2, const char *str)
1549{
1550 u8g2->u8x8.next_cb = u8x8_utf8_next;
1551 return u8g2_string_width(u8g2, str);
1552}
1553
1554
1555
1556void u8g2_SetFontDirection(u8g2_t *u8g2, uint8_t dir)
1557{
1558#ifdef U8G2_WITH_FONT_ROTATION
1559 u8g2->font_decode.dir = dir;
1560#endif
1561}
1562
1563/*=======================================*/
1564/*
1565 Draw a string, which is produced by hbshape2u8g2 (libharfbuzz toolchain)
1566
1567 The data argument should look like this:
1568 static const unsigned char teststring[] U8X8_PROGMEM = {
1569 0x09, 0x28, 0x00, 0x00, // u8g2_DrawGlyph(&u8g2, 0, 0, 2344);
1570 0x09, 0x2e, 0x10, 0x00, // u8g2_DrawGlyph(&u8g2, 16, 0, 2350);
1571 0x09, 0x38, 0x10, 0x00, // u8g2_DrawGlyph(&u8g2, 32, 0, 2360);
1572 0x09, 0x4d, 0x00, 0x00, // u8g2_DrawGlyph(&u8g2, 32, 0, 2381);
1573 0x09, 0x24, 0x10, 0x00, // u8g2_DrawGlyph(&u8g2, 48, 0, 2340);
1574 0x09, 0x47, 0x00, 0x00, // u8g2_DrawGlyph(&u8g2, 48, 0, 2375);
1575 0x00, 0x00 // end of binary
1576 };
1577
1578 The data row contains four bytes, which are:
1579 <encoding high byte> <encoding low byte> <delta-x> <delta-y>
1580 The last row is marked with encoding=0
1581
1582 The algorithm is
1583 Input: x,y
1584 with all rows (until encoding is 0)
1585 x += <delta-x>
1586 y += <delta-y>
1587 draw glyph with <encoding> at x, y
1588
1589 A call to this function will require transparent mode:
1590 u8g2_SetFontMode(&u8g2, 1);
1591
1592 Limitation:
1593 Glyph delta must be lower than 128, this bascially means, that the glyph size is limited to
1594 hight/width of 128 pixel
1595
1596 Further details:
1597 https://github.com/olikraus/u8g2/issues/2656
1598
1599*/
1600void u8g2_DrawHB(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const unsigned char *data)
1601{
1602 uint16_t encoding = 0;
1603 for (;;)
1604 {
1605 encoding = u8x8_pgm_read(data);
1606 data++;
1607 encoding <<= 8;
1608 encoding |= u8x8_pgm_read(data);
1609 data++;
1610 if (encoding == 0)
1611 break;
1612 x += (int8_t)u8x8_pgm_read(data);
1613 data++;
1614 y += (int8_t)u8x8_pgm_read(data);
1615 data++;
1616 u8g2_DrawGlyph(u8g2, x, y, encoding);
1617 }
1618}
1619