279 lines
7.2 KiB
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;
|
|
}
|
|
|
|
|
|
|
|
|