Files
TX/source/Fonts/fontLibrary.c

279 lines
7.2 KiB
C

/*
* fontLibrary.c
*
* Created on: Feb 9, 2022
* Author: Brian.Bailey
*/
#include <stdint.h>
#include <string.h>
#include "fontLibrary.h"
#include "translate.h"
#include "lcd.h"
#include "System/system.h"
//UTF8 Decode
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
#define UTF8_ACCEPT 0
#define UTF8_REJECT 1
static const uint8_t utf8d[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
};
uint32_t FL_Decode(uint32_t* state, uint32_t* codep, uint32_t byte) //removed inline to make compiler happy
{
uint32_t type = utf8d[byte];
*codep = (*state != UTF8_ACCEPT) ?
(byte & 0x3fu) | (*codep << 6) :
(0xff >> type) & (byte);
*state = utf8d[256 + *state*16 + type];
return *state;
}
/**
* Get information about first codepoint in a UTF8-encoded string
*
* \param str UTF8-encoded string
* \param codepoint Font to draw string in
* \param charCount number of characters in the codepoint
* \return UTF8_ACCEPT if valid, UTF8_REJECT otherwise
*/
uint32_t FL_GetCodepointInfo(const char * str, uint32_t * codepoint, uint32_t * charCount)
{
uint32_t state = 0;
uint32_t count = 0; //character count
for(; *str; ++str)
{
count++;
if(!FL_Decode(&state, codepoint, *str))
{
//found the codepoint
*charCount = count;
return state;
}
}
}
uint32_t FL_GetFontHeight(const BFC_FONT * font)
{
return font->FontHeight;
}
//
void FL_DrawTranslatedString(const char *str, int16_t x, int16_t y, const BFC_FONT *pFont, LCD_DRAWMODE_t drawMode, FL_ALIGN align)
{
if(SYS_GetLanguage() < LANG_CHINESE) //Use normal fonts if language NOT Chinese or Korean
{
FL_DrawString(Translate(str), x, y, pFont, drawMode, align);
}
else //Chinese or Korean - Use simsun font
{
//if translate returns different pointer, the translation was not found.
char * strTranslated = 0;
strTranslated = (char *)Translate(str);
if(strTranslated == str)
{
//Translation string not found. Use English (So we can see the problem!)
FL_DrawString(Translate(str), x, y, pFont, drawMode, align);
}
else
{
//Translation successful
FL_DrawString(Translate(str), x, y, fontSimsun, drawMode, align);
}
}
//FL_DrawString(Translate(str), x, y, pFont, drawMode, align);
}
//Draw a null terminated UTF8 encoded string
void FL_DrawString(const char *str, int16_t x, int16_t y, const BFC_FONT *pFont, LCD_DRAWMODE_t drawMode, FL_ALIGN align)
{
switch(align)
{
case FL_ALIGN_LEFT:
break;
case FL_ALIGN_CENTER:
x -= (FL_GetStringLengthInPixels(str, pFont)) >> 1;
break;
case FL_ALIGN_RIGHT:
x -= FL_GetStringLengthInPixels(str, pFont);
break;
default:
break;
}
uint32_t error = 0;
uint32_t index = 0;
while(str[index] != '\0' && !error)
{
uint32_t codepoint; //UTF8 code
uint32_t charCount; //number of chars in the current codepoint
if(FL_GetCodepointInfo(&str[index], &codepoint, &charCount))
{
codepoint = 0x000A; //not valid UTF8 codepoint so return a distinctive char
charCount = 1; //assume 1 byte consumed. It might be wrong but we won't skip any bytes
}
index += charCount; //Advance index by number of chars consumed from string
x += FL_DrawChar(codepoint, x, y, pFont, drawMode); //advance x coordinate by glyph width
}
}
/* Draw a character to the framebuffer
* Encode: Unicode
* Data length: 8 bits
* Invert bits: No
* 1 bpp
* Data format: Big Endian, Row based, Row preferred, Packed
*/
uint32_t FL_DrawChar(uint16_t codepoint, int x0, int y0, const BFC_FONT *pFont, LCD_DRAWMODE_t drawMode)
{
// 1. find the character information first
const BFC_CHARINFO *pCharInfo = FL_GetCharInfo(pFont, (unsigned short)codepoint); //cast for this function
if( pCharInfo != 0 )
{
int height = pFont->FontHeight;
int width = pCharInfo->Width;
int data_size = pCharInfo->DataSize; // # bytes of the data array
const unsigned char *pData = pCharInfo->p.pData8; // pointer to data array
int x, y; //pixel coordinates within the glyph
unsigned char data;
uint32_t packedDataSize = 8; //8-bit data ONLY
uint32_t bitPosition = packedDataSize-1; //bit position in the byte
uint32_t byteIndex = 0;
unsigned char bitMask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
// 2. draw all the pixels in this character
for(y=0; y<height; y++)
{
for(x=0; x<width; x++)
{
data = pData[byteIndex];
if(data & bitMask[bitPosition])
{
LCD_DrawPixel(x0+x, y0+y, drawMode);
}
if(bitPosition == 0)
{
bitPosition = packedDataSize-1;
byteIndex++;
}
else
{
bitPosition--;
}
}
}
return width;
}
return 0;
}
uint32_t FL_GetStringLengthInPixels(const char * str, const BFC_FONT *pFont)
{
uint32_t widthInPixels = 0;
uint32_t error = 0;
uint32_t index = 0;
while(str[index] != '\0' && !error)
{
uint32_t codepoint; //UTF8 code
uint32_t charCount; //number of chars in the current codepoint
if(FL_GetCodepointInfo(&str[index], &codepoint, &charCount))
{
while(1); //not valid UTF8 codepoint
}
index += charCount; //Advance index by number of chars consumed from string
widthInPixels += FL_GetCharInfo(pFont, str[index])->Width;
}
return widthInPixels;
}
const BFC_CHARINFO* FL_GetCharInfo(const BFC_FONT *pFont, unsigned short ch)
{
const BFC_CHARINFO *pCharInfo = 0;
const BFC_FONT_PROP *pProp = pFont->p.pProp;
unsigned short first_char, last_char;
if(pFont == 0 || pFont->p.pProp == 0)
return 0;
while(pProp != 0)
{
first_char = pProp->FirstChar;
last_char = pProp->LastChar;
pCharInfo = pProp->pFirstCharInfo;
if( ch >= first_char && ch <= last_char )
{
// the character "ch" is inside this range,
// return this char info, and not search anymore.
pCharInfo = pCharInfo + (ch - first_char);
return pCharInfo;
}
else
{
// the character "ch" is not in this range
// so search it in the next range
pProp = pProp->pNextProp;
}
}
// if the character "ch" is not rendered in this font,
// we use the first character in this font as the default one.
if( pCharInfo == 0 )
{
pProp = pFont->p.pProp;
pCharInfo = pProp->pFirstCharInfo;
}
return pCharInfo;
}