Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to use UTF-8 glyphs #414

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 91 additions & 21 deletions Adafruit_GFX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ POSSIBILITY OF SUCH DAMAGE.
#define pgm_read_pointer(addr) ((void *)pgm_read_word(addr))
#endif

inline GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
inline GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint16_t c) {
#ifdef __AVR__
return &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
#else
Expand Down Expand Up @@ -116,6 +116,7 @@ Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) {
textcolor = textbgcolor = 0xFFFF;
wrap = true;
_cp437 = false;
_utf8 = false;
gfxFont = NULL;
}

Expand Down Expand Up @@ -1105,15 +1106,15 @@ void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap,
@brief Draw a single character
@param x Bottom left corner x coordinate
@param y Bottom left corner y coordinate
@param c The 8-bit font-indexed character (likely ascii)
@param c The 16-bit font-indexed character (likely ascii)
@param color 16-bit 5-6-5 Color to draw chraracter with
@param bg 16-bit 5-6-5 Color to fill background with (if same as color,
no background)
@param size Font magnification level, 1 is 'original' size
*/
/**************************************************************************/
void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
uint16_t color, uint16_t bg, uint8_t size) {
void Adafruit_GFX::drawChar(int16_t x, int16_t y, uint16_t c, uint16_t color,
uint16_t bg, uint8_t size) {
drawChar(x, y, c, color, bg, size, size);
}

Expand All @@ -1123,17 +1124,16 @@ void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
@brief Draw a single character
@param x Bottom left corner x coordinate
@param y Bottom left corner y coordinate
@param c The 8-bit font-indexed character (likely ascii)
@param c The 16-bit font-indexed character (likely ascii)
@param color 16-bit 5-6-5 Color to draw chraracter with
@param bg 16-bit 5-6-5 Color to fill background with (if same as color,
no background)
@param size_x Font magnification level in X-axis, 1 is 'original' size
@param size_y Font magnification level in Y-axis, 1 is 'original' size
*/
/**************************************************************************/
void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
uint16_t color, uint16_t bg, uint8_t size_x,
uint8_t size_y) {
void Adafruit_GFX::drawChar(int16_t x, int16_t y, uint16_t c, uint16_t color,
uint16_t bg, uint8_t size_x, uint8_t size_y) {

if (!gfxFont) { // 'Classic' built-in font

Expand Down Expand Up @@ -1178,9 +1178,9 @@ void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
// newlines, returns, non-printable characters, etc. Calling
// drawChar() directly with 'bad' characters of font may cause mayhem!

c -= (uint8_t)pgm_read_byte(&gfxFont->first);
GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c);
uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont);
c -= pgm_read_word(&gfxFont->first);
GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
uint8_t *bitmap = (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);

uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
uint8_t w = pgm_read_byte(&glyph->width), h = pgm_read_byte(&glyph->height);
Expand Down Expand Up @@ -1233,15 +1233,76 @@ void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,

} // End classic vs custom font
}

/**************************************************************************/
/*!
@brief Serial UTF-8 decoder
@param c 8 bit value from encoded stream
@returns 0 if decoding is not complete yet, 16 bit code point
otherwise. Can cast to 8 bits for ASCII range (0-255)
*/
/**************************************************************************/

uint16_t Adafruit_GFX::decodeUTF8(uint8_t c) {
// 7 bit Unicode Code Point
if ((c & 0x80) == 0x00) {
decoderState = 0;
return (uint16_t)c;
}

if (decoderState == 0) {
// 11 bit Unicode Code Point
if ((c & 0xE0) == 0xC0) {
decoderBuffer = ((c & 0x1F) << 6); // Save first 5 bits
decoderState = 1;
return 0;
}

// 16 bit Unicode Code Point
if ((c & 0xF0) == 0xE0) {
decoderBuffer = ((c & 0x0F) << 12); // Save first 4 bits
decoderState = 2;
return 0;
}

// 21 bit Unicode Code Point not supported so fall-back to extended ASCII
if ((c & 0xF8) == 0xF0)
return (uint16_t)c;
} else {
if (decoderState == 2) {
decoderBuffer |=
((c & 0x3F) << 6); // Add next 6 bits of 16 bit code point
decoderState--;
return 0;
} else // decoderState must be == 1
{
decoderBuffer |= (c & 0x3F); // Add last 6 bits of code point
decoderState = 0;
return decoderBuffer;
}
}

decoderState = 0;

return (uint16_t)c; // fall-back to extended ASCII
}

/**************************************************************************/
/*!
@brief Print one byte/character of data, used to support print()
@param c The 8-bit ascii character to write
@param data The 8-bit UTF-8 or ascii character to write
*/
/**************************************************************************/
size_t Adafruit_GFX::write(uint8_t c) {
if (!gfxFont) { // 'Classic' built-in font
size_t Adafruit_GFX::write(uint8_t data) {
uint16_t c = (uint16_t)data;
if (_utf8)
c = decodeUTF8(data);
if (c == 0)
return 1;

if (!gfxFont) { // 'Classic' built-in font
if (c > 255)
return 1; // Stop 16 bit characters
if (c == '\n') { // Newline?
cursor_x = 0; // Reset x to zero,
cursor_y += textsize_y * 8; // advance y one line
Expand All @@ -1262,9 +1323,10 @@ size_t Adafruit_GFX::write(uint8_t c) {
cursor_y +=
(int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
} else if (c != '\r') {
uint8_t first = pgm_read_byte(&gfxFont->first);
if ((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) {
GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
uint16_t first = pgm_read_word(&gfxFont->first);
if ((c >= first) && (c <= pgm_read_word(&gfxFont->last))) {
GFXglyph *glyph =
&(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c - first]);
uint8_t w = pgm_read_byte(&glyph->width),
h = pgm_read_byte(&glyph->height);
if ((w > 0) && (h > 0)) { // Is there an associated bitmap?
Expand Down Expand Up @@ -1368,7 +1430,7 @@ void Adafruit_GFX::setFont(const GFXfont *f) {
@param maxy Pointer to maximum Y coord, passed in AND returned.
*/
/**************************************************************************/
void Adafruit_GFX::charBounds(unsigned char c, int16_t *x, int16_t *y,
void Adafruit_GFX::charBounds(uint16_t c, int16_t *x, int16_t *y,
int16_t *minx, int16_t *miny, int16_t *maxx,
int16_t *maxy) {

Expand All @@ -1378,8 +1440,8 @@ void Adafruit_GFX::charBounds(unsigned char c, int16_t *x, int16_t *y,
*x = 0; // Reset x to zero, advance y by one line
*y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
} else if (c != '\r') { // Not a carriage return; is normal char
uint8_t first = pgm_read_byte(&gfxFont->first),
last = pgm_read_byte(&gfxFont->last);
uint16_t first = pgm_read_word(&gfxFont->first),
last = pgm_read_word(&gfxFont->last);
if ((c >= first) && (c <= last)) { // Char present in this font?
GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
uint8_t gw = pgm_read_byte(&glyph->width),
Expand Down Expand Up @@ -1449,7 +1511,7 @@ void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
int16_t *x1, int16_t *y1, uint16_t *w,
uint16_t *h) {

uint8_t c; // Current character
uint16_t c; // Current character
int16_t minx = 0x7FFF, miny = 0x7FFF, maxx = -1, maxy = -1; // Bound rect
// Bound rect is intentionally initialized inverted, so 1st char sets it

Expand All @@ -1458,6 +1520,14 @@ void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
*w = *h = 0; // Initial size is zero

while ((c = *str++)) {
if (_utf8) {
c = decodeUTF8(c);
} else {
c = (uint16_t)c;
}
if (c == 0) {
continue;
}
// charBounds() modifies x/y to advance for each character,
// and min/max x/y are updated to incrementally build bounding rect.
charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
Expand Down
29 changes: 24 additions & 5 deletions Adafruit_GFX.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ class Adafruit_GFX : public Print {
const uint8_t mask[], int16_t w, int16_t h);
void drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, uint8_t *mask,
int16_t w, int16_t h);
void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
uint16_t bg, uint8_t size);
void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
uint16_t bg, uint8_t size_x, uint8_t size_y);
void drawChar(int16_t x, int16_t y, uint16_t c, uint16_t color, uint16_t bg,
uint8_t size);
void drawChar(int16_t x, int16_t y, uint16_t c, uint16_t color, uint16_t bg,
uint8_t size_x, uint8_t size_y);
void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1,
int16_t *y1, uint16_t *w, uint16_t *h);
void getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y,
Expand All @@ -121,6 +121,9 @@ class Adafruit_GFX : public Print {
void setTextSize(uint8_t sx, uint8_t sy);
void setFont(const GFXfont *f = NULL);

// Serial UTF-8 decoder
uint16_t decodeUTF8(uint8_t c);

/**********************************************************************/
/*!
@brief Set text cursor location
Expand Down Expand Up @@ -180,6 +183,18 @@ class Adafruit_GFX : public Print {
/**********************************************************************/
void cp437(bool x = true) { _cp437 = x; }

/**********************************************************************/
/*!
@brief Enable (or disable) UTF-8-compatible charset in custom made fonts
By default, the font.h files boundled to the library use ASCII
charset as UTF-8 fonts need more memory as many AVR chips can offer. Pass
'true' to this function if you are willing to use UTF-8 fonts that you
generated whith fontconvert and also your board has enough free memory.
@param x true = enable (new behavior), false = disable (old behavior)
*/
/**********************************************************************/
void utf8(boolean x = true) { _utf8 = x; }

using Print::write;
#if ARDUINO >= 100
virtual size_t write(uint8_t);
Expand Down Expand Up @@ -230,7 +245,7 @@ class Adafruit_GFX : public Print {
int16_t getCursorY(void) const { return cursor_y; };

protected:
void charBounds(unsigned char c, int16_t *x, int16_t *y, int16_t *minx,
void charBounds(uint16_t c, int16_t *x, int16_t *y, int16_t *minx,
int16_t *miny, int16_t *maxx, int16_t *maxy);
int16_t WIDTH; ///< This is the 'raw' display width - never changes
int16_t HEIGHT; ///< This is the 'raw' display height - never changes
Expand All @@ -245,7 +260,11 @@ class Adafruit_GFX : public Print {
uint8_t rotation; ///< Display rotation (0 thru 3)
bool wrap; ///< If set, 'wrap' text at right edge of display
bool _cp437; ///< If set, use correct CP437 charset (default is off)
bool _utf8; ///< If set, use correct UTF-8 charset (default is off)
GFXfont *gfxFont; ///< Pointer to special font

uint8_t decoderState = 0; ///< UTF-8 decoder state
uint16_t decoderBuffer; ///< Unicode code-point buffer
};

/// A simple drawn button UI element
Expand Down
Loading