跳转到主要内容

字体缓存

本节描述如何使用字体缓存处理TouchGFX中的二进制字体。

请先阅读二进制字体的相关内容。

字体缓存

注意,使用二进制字体需要将整个字体加载到存储器。 在某些情况下,如果字体很大,如大字号中文字体,则这样做可能不可取。

字体缓存使应用能够从外部存储器只能加载显示字符串所需的字母。 这意味着整个字体无需保存到在可寻址闪存或RAM上,而是只需保存在更大的文件系统上。

在下图中,内编译字体Font2已被字体缓存替代。 当TouchGFX使用Font2绘制文本时, TouchGFX会找到指向字体表中CachedFont对象的指针。 此特殊字体将查找FontCache对象中的字母。

使用缓存字体

CachedFont设置了指向内联字体(上面的Font2)的指针。 当TouchGFX要求CachedFont提供特殊字母时,cachedFont将首先查找它替代的普通字体(Font2)。 该字体可能是空字体,但也可能是包含一些常用字母的“普通”字体。 如果字体不包含需要的字母,CachedFont将查找FontCache,以便确定是否已从文件系统加载了字母。

由于无需缓存正常字体中已有的字母,此原则限制了必须缓存的字母数量。

在应用代码中使用字体缓存

在应用程序安装CachedFont之前,必须先创建FontCache、存储缓冲区和文件系统阅读器对象:

Screen1View.cpp
uint8_t fontdata[5120]; //Memory buffer for the font cache, 5Kb
FontCache fontCache;
CachedFont cachedFont; //Cached Font object
FileDataReader reader; //Filesystem reader object

FontCache必须链接到缓冲区和阅读器:

Screen1View.cpp
//setup the font cache with buffer and size; and file reader object
fontCache.setMemory(fontdata, 5120);
fontCache.setReader(&reader);

现在,应用可以设置字体缓存,初始化CachedFont并将它传递给TouchGFX。

字体缓存需要用TextId来初始化CachedFont对象。 TextId用于查找CachedFont必须指向的字体。 这确保您替换的是显示屏上的文本使用的字体:

Screen1View.cpp
//initialize the cachedFont object to the font used by T_SINGLEUSEID1
TypedText text = TypedText(T_SINGLEUSEID1);
fontCache.initializeCachedFont(text, &cachedFont);

//replace the linked in font in TouchGFX with cachedFont
TypedTextDatabase::setFont(DEFAULT, &cachedFont);

以上代码可以放在应用中的任何位置。 如果缓存字体只用在特定视图中,此视图可能是插入代码的理想位置。

缓存字母

字体缓存仍然为空。 必须先从字体缓存读取字母,然后才能显示字母。 这是通过将统一码(字符串)阵列传递到字体缓存来完成的。 在本例中,我们只从T_SINGLEUSEID1传递文本。

Screen1View.cpp
//cache the glyphs used by the text T_SINGLEUSEID1
Unicode::UnicodeChar* str = const_cast<Unicode::UnicodeChar*>(text.getText());
bool b = fontCache.cacheString(text, str);

字体缓存将通过阅读器对象加载在str阵列中找到的字母。 读取的统一码将链接到TextId text参数使用的字体。

此应用负责配置要从正确的文件加载的阅读器对象。

缓存连字

对于在显示前将统一码序列转换为其他统一码的语言(如阿拉伯语和天城体),以上方法不适合。 它缓存原始统一码而不是转换后显示的统一码。 此方法将转换给定统一码并缓存需要的统一码(转换后):

Screen1View.cpp
//cache the glyphs used by the text T_SINGLEUSEID1 after conversion
Unicode::UnicodeChar* str = const_cast<Unicode::UnicodeChar*>(text.getText());
bool b = fontCache.cacheLigatures(cachedFont, text, str);

内存使用

字体缓存可以计算当前内存使用量:

Screen1View.cpp
touchgfx_printf("Memory usage %d\n", fontCache.getMemoryUsage());

缓存GSUB表

在渲染时,一些字体使用GSUB表。 这只是东方语言的几种字体,如天城体字体。 GSUB表使字体系统能够重新排列字符并用字符序列代替其他“组合”字符。

字体缓存可以从文件系统加载此GSUB表。 如未加载,则文本渲染系统无GSUB表可用,将无法正确显示字体。

在初始化缓存字体时,通过提供额外参数加载GSUB表:

Screen1View.cpp
//initialize the cachedFont and load the GSUB table
text = TypedText(T_SINGLEUSEID1);
fontCache.initializeCachedFont(text, &cachedFont, true);

实现字体文件阅读器

TouchGFX不包含以上示例代码中使用的FileDataReader类,它取决于使用的操作系统。

下面是普通“stdio”兼容文件系统的一个示例。

Screen1View.cpp
class FileDataReader : public FontDataReader
{
public:
virtual ~FileDataReader() { }
virtual void open()
{
fp = fopen("Font_verdana_20_4bpp.bin", "rb");
if (!fp)
{
touchgfx_printf("Unable to open font file!!!\n");
}
}
virtual void close()
{
fclose(fp);
}
virtual void setPosition(uint32_t position)
{
fseek(fp, position, SEEK_SET);
}
virtual void readData(void* out, uint32_t numberOfBytes)
{
fread(out, numberOfBytes, 1, fp);
}
private:
FILE* fp;
};

FileDataReader类从FontCache.hpp实现FontDataReader接口:

FontCache.hpp
class FontDataReader
{
public:
virtual ~FontDataReader() { }
virtual void open() = 0;
virtual void close() = 0;
virtual void setPosition(uint32_t position) = 0;
virtual void readData(void* out, uint32_t numberOfBytes) = 0;
};