一、先说明几个基本概念
1.字体基本属性
uint16_t fontHeight; ///< 字体的高度,单位像素
uint16_t baselineHeight; ///< 基线高度
uint8_t pixelsAboveTop; ///< 文本上方的像素数
uint8_t pixelsBelowBottom; ///< 基线以下的像素数
uint8_t bPerPixel : 7; ///< 每个像素的位数(使用了位域)
uint8_t bAlignRow : 1; ///< 字形存储时是否每行按字节对齐(使用了位域)
uint8_t maxPixelsLeft; ///< 字形向左延伸的最大像素数
uint8_t maxPixelsRight; ///< 字形向右延伸的最大像素数
2.fallbackCharacter:无法找到所需字符的字形时使用的备用字符(回退字符)
3.ellipsisCharacter:省略号字符
4.glyph:每个字的基本信息
5.KerningNode:字距调整
6.glyphData:每个字的像素
7.FontContextualFormsTable:上下文形式的信息,像阿拉伯语,字符形状会根据它前后的字符而改变
8.GSUB表:字形替换表指针(不知道干嘛用的)
二、字体相关的基类
定义了字体的基本属性
#ifndef TOUCHGFX_FONT_HPP
#define TOUCHGFX_FONT_HPP
#include <touchgfx/Unicode.hpp>
#include <touchgfx/hal/Types.hpp>
namespace touchgfx
{
/* Glyph 标志定义。这些标志用于在 GlyphNode 结构中存储额外的精度和编码信息 */
enum GlyphFlags
{
GLYPH_DATA_KERNINGTABLEPOS_BIT8_10 = 0x07, ///< Kerning 表位置的 8th, 9th 和 10th 位存储在 flags 中
GLYPH_DATA_WIDTH_BIT8 = 0x08, ///< Glyph 宽度的 9th 位存储在 flags 中
GLYPH_DATA_HEIGHT_BIT8 = 0x10, ///< Glyph 高度的 9th 位存储在 flags 中
GLYPH_DATA_TOP_BIT8 = 0x20, ///< Glyph 顶部偏移的 9th 位存储在 flags 中
GLYPH_DATA_TOP_BIT9 = 0x40, ///< Glyph 顶部偏移的符号位存储在 flags 中
GLYPH_DATA_ADVANCE_BIT8 = 0x80 ///< Glyph 前进宽度的 9th 位存储在 flags 中
};
#pragma pack(2)
/**
* 提供有关 glyph 信息的结构体。LCD 渲染时使用。
* Glyph 是字体中的一个字符表示,包含渲染该字符所需的所有数据。
*/
struct GlyphNode
{
uint32_t dataOffset; ///< 指向此 glyph 数据的索引
Unicode::UnicodeChar unicode; ///< 此 glyph 的 Unicode 编码
uint8_t _width; ///< glyph 数据的实际宽度
uint8_t _height; ///< glyph 数据的实际高度
uint8_t _top; ///< glyph 从基线开始的垂直偏移
int8_t left; ///< glyph 从左侧开始的水平偏移
uint8_t _advance; ///< glyph 的宽度(包括左右的空间)
uint8_t _kerningTablePos; ///< 此 glyph 的 kerning 信息在 kerning 表中的存储位置
uint8_t kerningTableSize; ///< 此 glyph 在 kerning 表中跟随 kerningTablePos 的条目数量
uint8_t flags; ///< 附加的 glyph 标志(字体编码和宽度/高度/顶部/前进的额外精度)
/**
* 获取 "kerningTablePos" 值,其中 8-10th 位存储在 flags 中。
* 通过将存储在 flags 中的高位与 _kerningTablePos 合并,得到正确的 kerningTablePos 值。
*
* @return 正确的 "kerningTablePos" 值。
*/
FORCE_INLINE_FUNCTION uint16_t kerningTablePos() const
{
return ((flags & GLYPH_DATA_KERNINGTABLEPOS_BIT8_10) << 8) | _kerningTablePos;
}
/**
* 获取 "width" 值,其中 9th 位存储在 flags 中。
* 通过将存储在 flags 中的高位与 _width 合并,得到正确的 width 值。
*
* @return 正确的 "width" 值。
*/
FORCE_INLINE_FUNCTION int16_t width() const
{
return ((flags & GLYPH_DATA_WIDTH_BIT8) << 5) | _width;
}
/**
* 获取 "height" 值,其中 9th 位存储在 flags 中。
* 通过将存储在 flags 中的高位与 _height 合并,得到正确的 height 值。
*
* @return 正确的 "height" 值。
*/
FORCE_INLINE_FUNCTION int16_t height() const
{
return ((flags & GLYPH_DATA_HEIGHT_BIT8) << 4) | _height;
}
/**
* 获取 "top" 值,其中 9th 位和符号位存储在 flags 中。
* 通过将存储在 flags 中的高位与 _top 合并,并根据符号位调整值,得到正确的 top 值。
*
* @return 正确的 "top" 值。
*/
FORCE_INLINE_FUNCTION int16_t top() const
{
int16_t num = ((flags & GLYPH_DATA_TOP_BIT8) << 3) | _top;
return (flags & GLYPH_DATA_TOP_BIT9) ? num - 512 : num;
}
/**
* 设置 "top" 的新值。用于调整 glyph 的垂直位置 -
* 当定位某些 Thai glyphs 和某些 Arabic glyphs 时使用。
*
* @param newTop 新的顶部偏移量。
*/
FORCE_INLINE_FUNCTION void setTop(int16_t newTop)
{
_top = newTop & 0xFF; // 存储低 8 位
flags &= ~(GLYPH_DATA_TOP_BIT8 | GLYPH_DATA_TOP_BIT9); // 清除旧的高位和符号位
flags |= (newTop & 0x300) >> 3; // 设置新的高位(9th 和可能的符号位)
}
/**
* 获取 "advance" 值,其中 9th 位存储在 flags 中。
* 通过将存储在 flags 中的高位与 _advance 合并,得到正确的 advance 值。
*
* @return 正确的 "advance" 值。
*/
FORCE_INLINE_FUNCTION uint16_t advance() const
{
return ((flags & GLYPH_DATA_ADVANCE_BIT8) << 1) | _advance;
}
};
#pragma pack()
#pragma pack(2)
/**
* 提供有关给定字符对之间的 kerning 信息的结构体。LCD 渲染时使用,用于计算文本宽度等。
*/
struct KerningNode
{
Unicode::UnicodeChar unicodePrevChar; ///< Kerning 对中前一个字符的 Unicode 编码
int8_t distance; ///< Kerning 距离,即两个字符之间的额外空间量
};
#pragma pack()
/**
* 定义了一个别名,表示字体ID。
* FontId是一个16位的无符号整数,通常用于在系统中唯一标识一个字体。
*/
typedef uint16_t FontId;
/**
* 结构体,提供了有关字体中可用的上下文形式的信息。
* 在某些字体中,特别是像阿拉伯语这样的复杂脚本中,字符的形状可能会根据它前后的字符而改变。
* 这种变化称为上下文形式。此结构体为这些上下文形式提供了表格。
*/
struct FontContextualFormsTable
{
/**
* 定义了指向包含5个Unicode字符的数组的指针的类型。
* 这主要用于创建指向特定上下文形式表的指针。
*/
typedef const Unicode::UnicodeChar (*arrayOf5UnicodesPtr)[5];
/**
* 定义了指向包含4个Unicode字符的数组的指针的类型。
* 与上面的类似,但用于不同大小的上下文形式表。
*/
typedef const Unicode::UnicodeChar (*arrayOf4UnicodesPtr)[4];
// 下面的成员都是指向上下文形式表的指针。
const Unicode::UnicodeChar (*contextualForms4Long)[5]; ///< 指向用于4个字形序列的上下文形式表的指针。
const Unicode::UnicodeChar (*contextualForms3Long)[5]; ///< 指向用于3个字形序列的上下文形式表的指针。
const Unicode::UnicodeChar (*contextualForms2Long)[5]; ///< 指向用于2个字形序列的上下文形式表的指针。
const Unicode::UnicodeChar (*contextualForms0621_063a)[4]; ///< 指向特定于0x0621到0x063A字形范围的上下文形式表的指针。
const Unicode::UnicodeChar (*contextualForms0641_064a)[4]; ///< 指向特定于0x0641到0x064A字形范围的上下文形式表的指针。
const Unicode::UnicodeChar (*contextualForms06XX)[5]; ///< 指向剩余0x06XX字形范围的上下文形式表的指针。
// 下面的成员提供了上述上下文形式表的长度。
uint16_t contextualForms4LongSize; ///< 4个字形序列的上下文形式表的长度。
uint16_t contextualForms3LongSize; ///< 3个字形序列的上下文形式表的长度。
uint16_t contextualForms2LongSize; ///< 2个字形序列的上下文形式表的长度。
uint16_t contextualForms06XXSize; ///< 剩余0x06XX字形范围的上下文形式表的长度。
};
/**
* 字体基类。这个类是抽象的,并要求实现getGlyph方法。
* 它提供了一些实用功能,如获取字符串宽度和字体高度。
*/
class Font
{
public:
/* 析构函数 */
virtual ~Font()
{
}
/**
* 获取与指定Unicode字符关联的字形数据。
* 请注意,在泰语和阿拉伯语字母的情况下,其中变音符号可以相对于前一个或多个字符放置,
* 请使用TextProvider::getNextLigature()代替,因为它将创建一个临时的GlyphNode,该节点将根据X / Y位置进行调整。
*
* @param unicode 要查找的字符。
* @param pixelData 指向字形像素数据的指针,如果找到字形,则由此方法设置。
* @param bitsPerPixel 引用,用于放置每像素的位数。
*
* @return 指向字形节点的指针,如果未找到字形,则为null。
*/
virtual const GlyphNode* getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const = 0;
/**
* 重载的getGlyph方法,它不接受像素数据和每像素位数的引用,而是直接返回与指定Unicode字符关联的字形数据。
* 如果字符为0,则立即返回null。否则,它调用上面的getGlyph方法并忽略返回的像素数据和每像素位数。
*
* @param unicode 要查找的字符。
*
* @return 指向字形节点的指针,如果未找到字形,则为null。
*/
virtual const GlyphNode* getGlyph(Unicode::UnicodeChar unicode) const
{
if (unicode == 0)
{
return 0;
}
const uint8_t* dummyPixelDataPointer = 0;
uint8_t bitsPerPixelDummy = 0;
const GlyphNode* glyph = getGlyph(unicode, dummyPixelDataPointer, bitsPerPixelDummy);
return glyph;
}
/* 获取给定字体的回退字符。当某些字符没有可用的字形时,将使用回退字符。
* 如果返回0(零),则表示没有默认字符 */
virtual Unicode::UnicodeChar getFallbackChar() const
{
return fallbackCharacter;
}
/* 获取给定字体的省略号字符。这是在截断长行时使用的字符 */
virtual Unicode::UnicodeChar getEllipsisChar() const
{
return ellipsisCharacter;
}
/**
* 获取指定字符串的像素宽度。如果字符串包含多行,将找到最宽行的宽度。
* 请注意,如果文本包含通配符,则必须给出正确数量的参数。
*
* 推荐使用带有TextDirection参数的getStringWidth()实现,以确保正确计算宽度。
* 字距调整可能会导致不同的结果,具体取决于TextDirection。此方法假定TextDirection为TEXT_DIRECTION_LTR。
*
* @param text 一个以null结尾的Unicode字符串,如果文本包含通配符,则插入参数。
* @param ... 提供在通配符占位符处插入的附加信息的可变参数。
*
* @return 指定字符串中最长行的像素宽度。
*/
virtual uint16_t getStringWidth(const Unicode::UnicodeChar* text, ...) const;
/**
* 获取指定字符串的像素宽度。如果字符串包含多行,将找到最宽行的宽度。
* 请注意,如果文本包含通配符,则必须给出正确数量的参数。
*
* 应为提供的文本正确设置TextDirection。例如,字符串"10 20 30"的计算方式将根据TextDirection的不同而有所不同。
* 如果TextDirection是TEXT_DIRECTION_LTR,则宽度计算为"10 20 30"(所有字符之间都有字距调整),
* 但对于TEXT_DIRECTION_RTL,它计算为"10"+" "+"20"+" "+"30"(仅在子字符串中的字符之间有字距调整,而子字符串之间没有)。
* 对于大多数字体,两种计算方式可能没有区别,但有些字体可能会产生略微不同的结果。
*
* @param textDirection 文本方向。
* @param text 一个以null结尾的Unicode字符串,如果文本包含通配符,则插入参数。
* @param ... 提供在通配符占位符处插入的附加信息的可变参数。
*
* @return 指定字符串中最长行的像素宽度。
*/
virtual uint16_t getStringWidth(TextDirection textDirection, const Unicode::UnicodeChar* text, ...) const;
/* 获取指定字符的像素宽度 */
virtual uint16_t getCharWidth(const Unicode::UnicodeChar c) const;
/**
* 获取给定文本顶部的空白像素数。
*
* @param text 一个以null结尾的Unicode字符串。
* @param ... 提供在通配符占位符处插入的附加信息的可变参数。
*
* @return 文本上方的空白像素数。
*/
virtual int16_t getSpacingAbove(const Unicode::UnicodeChar* text, ...) const;
TOUCHGFX_DEPRECATED("Please use getHeight() instead.", virtual uint16_t getMaxTextHeight(const Unicode::UnicodeChar* text, ...) const);
TOUCHGFX_DEPRECATED("Please use getBaseline() instead.", virtual uint16_t getFontHeight() const);
/**
* 返回此字体基线从行顶部开始的像素位置。
*
* @return 基线位置。
*
* @note 仅使用此高度分配文本区域是不够的。为此,请使用getHeight()。
*/
FORCE_INLINE_FUNCTION virtual uint16_t getBaseline() const
{
return baselineHeight;
}
TOUCHGFX_DEPRECATED("Please use getHeight() instead.", virtual uint16_t getMinimumTextHeight() const);
/**
* 返回字体的高度。字体可能会超出顶部getPixelsAboveTop()或底部getPixelsBelowBottom()的范围。
*
* @return 字体高度。
*/
FORCE_INLINE_FUNCTION virtual uint16_t getHeight() const
{
return fontHeight;
}
/**
* 获取正常文本高度之上的像素数。对于大多数字体,此值为0;对于某些'wedding'字体,该数字可能为正。
*
* @return 正常文本之上的像素数。
*/
FORCE_INLINE_FUNCTION uint16_t getPixelsAboveTop() const
{
return pixelsAboveTop;
}
/**
* 获取字体下方像素行的数量。
*
* @return 字体下方的像素数。
*/
FORCE_INLINE_FUNCTION uint16_t getPixelsBelowBottom() const
{
return pixelsBelowBottom;
}
/**
* 获取此字体的每像素位数。
*
* @return 此字体中每像素使用的位数。
*/
FORCE_INLINE_FUNCTION virtual uint8_t getBitsPerPixel() const
{
return bPerPixel;
}
/**
* 字体中的字形是否保存为每行字形字节对齐?
*
* @return 如果每行字形存储为字节对齐,则为true;否则为false。
*/
FORCE_INLINE_FUNCTION virtual uint8_t getByteAlignRow() const
{
return bAlignRow;
}
/**
* 获取字体中任何字形的最大左侧像素数。这是所有字形的"left"的最大值。该值被否定,因此如果"g"的left为-6,则maxPixelsLeft为6。此值由字体转换器计算。
*
* @return 最大左侧像素数。
*/
FORCE_INLINE_FUNCTION uint8_t getMaxPixelsLeft() const
{
return maxPixelsLeft;
}
/**
* 获取字体中任何字形的最大右侧像素数。这是所有字形的"width+left-advance"的最大值。这是字形超出其正常区域右侧的像素数。此值由字体转换器计算。
*
* @return 最大右侧像素数。
*/
FORCE_INLINE_FUNCTION uint8_t getMaxPixelsRight() const
{
return maxPixelsRight;
}
/**
* 获取两个字符之间的字距调整距离。
*
* @param prevChar 上一个字符的 Unicode 值。
* @param glyph 当前字符的 glyph 对象。
*
* @return prevChar 和 glyph 字符之间的字距调整距离。在这个基类中,该方法默认返回0。
*/
virtual int8_t getKerning(Unicode::UnicodeChar prevChar, const GlyphNode* glyph) const
{
(void)prevChar; // Unused variable
(void)glyph; // Unused variable
return 0;
}
/**
* 计算给定文本中的行数。
*
* @param text 要计算的文本。
* @param ... 提供额外信息的可变参数。
*
* @return 文本中的行数。这是一个虚函数,需要在子类中实现具体的行数计算逻辑。
*/
virtual uint16_t getNumberOfLines(const Unicode::UnicodeChar* text, ...) const;
/**
* 获取 GSUB 表。当前仅用于 Devanagari 字体。
*
* @return GSUB 表的指针,如果字体没有 GSUB 表,则返回 null
*/
virtual const uint16_t* getGSUBTable() const
{
return 0;
}
/**
* 获取用于阿拉伯语字体的上下文形式表。
*
* @return FontContextualFormsTable 的指针,如果字体没有该表,则返回 null
*/
virtual const FontContextualFormsTable* getContextualFormsTable() const
{
return 0;
}
/**
* 如果此字体是基于矢量的,则返回true。默认值为false。
*
* @return 如果此字体是基于矢量的,则返回true。
*/
virtual bool isVectorBasedFont() const
{
return false;
}
/**
* 返回缩放因子。
*
* @return 缩放因子。
*
* 注意:这个方法的默认实现返回0,这可能意味着派生类需要覆盖它来提供实际的缩放因子。
*/
virtual float getScaleFactor() const
{
return 0;
}
/**
* 查询'character'是否是不可见的,即零宽度。
*
* @param character 要查询的字符。
*
* @return 如果字符是不可见的且零宽度,则返回true;否则返回false。
* 这个方法检查字符是否是Unicode字符0xFEFF(字节顺序标记)或0x200B(零宽度空格)。
*/
FORCE_INLINE_FUNCTION static bool isInvisibleZeroWidth(Unicode::UnicodeChar character)
{
return character == 0xFEFF || character == 0x200B;
}
protected:
/**
* 获取指定字符串的像素宽度。如果字符串包含多行,将找到最宽行的宽度。请注意,如果文本包含通配符,则必须给出正确数量的参数。
*
* @param textDirection 文本方向。
* @param text 一个带有插入参数的空终止Unicode字符串(如果文本包含通配符)。
* @param pArg 提供在通配符占位符处插入的附加信息的可变参数。
*
* @return 指定字符串中最长行的像素宽度。
*
* @note 字符串被假定为纯从左到右的。
*/
uint16_t getStringWidthLTR(TextDirection textDirection, const Unicode::UnicodeChar* text, va_list pArg) const;
/**
* 获取指定字符串的像素宽度(从右到左处理)。如果字符串包含多行,将找到最宽行的宽度。请注意,如果文本包含通配符,则必须给出正确数量的参数。
*
* 该字符串被处理为从右到左的字符串,并细分为更小的文本字符串,以正确处理从左到右和从右到左字符串的混合。
*
* @param textDirection 文本方向。
* @param text 一个带有插入参数的空终止Unicode字符串(如果文本包含通配符)。
* @param pArg 提供在通配符占位符处插入的附加信息的可变参数。
*
* @return 字符串从右到左处理的宽度。
*/
uint16_t getStringWidthRTL(TextDirection textDirection, const Unicode::UnicodeChar* text, va_list pArg) const;
/* 构造函数。
*
* @param height 字体的高度,以像素为单位。
* @param baseline 基线的高度。基线是字符在不考虑任何上升或下降部分时的对齐线。
* @param pixAboveTop 文本上方最大的像素数。这通常是字符升部的高度。
* @param pixBelowBottom 基线以下的像素数。这通常是字符降部的高度。
* @param bitsPerPixel 每个像素的位数,决定了像素的数据大小和颜色深度。
* @param byteAlignRow 字形存储时,每行是否按字节对齐。
* @param maxLeft 字形在字体中向左延伸的最大像素数。
* @param maxRight 字形在字体中向右延伸的最大像素数。
* @param fallbackChar 在无法找到所需字符的字形时使用的备用字符。
* @param ellipsisChar 用于截断长文本的省略号字符。
*/
Font(uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, uint8_t bitsPerPixel, uint8_t byteAlignRow, uint8_t maxLeft, uint8_t maxRight, const Unicode::UnicodeChar fallbackChar, const Unicode::UnicodeChar ellipsisChar)
: fontHeight(height),
baselineHeight(baseline),
pixelsAboveTop(pixAboveTop),
pixelsBelowBottom(pixBelowBottom),
bPerPixel(bitsPerPixel),
bAlignRow(byteAlignRow),
maxPixelsLeft(maxLeft),
maxPixelsRight(maxRight),
fallbackCharacter(fallbackChar),
ellipsisCharacter(ellipsisChar)
{
}
uint16_t fontHeight; ///< 字体的高度,单位像素
uint16_t baselineHeight; ///< 基线高度
uint8_t pixelsAboveTop; ///< 文本上方的像素数
uint8_t pixelsBelowBottom; ///< 基线以下的像素数
uint8_t bPerPixel : 7; ///< 每个像素的位数(使用了位域)
uint8_t bAlignRow : 1; ///< 字形存储时是否每行按字节对齐(使用了位域)
uint8_t maxPixelsLeft; ///< 字形向左延伸的最大像素数
uint8_t maxPixelsRight; ///< 字形向右延伸的最大像素数
Unicode::UnicodeChar fallbackCharacter; ///< 无法找到所需字符的字形时使用的备用字符
Unicode::UnicodeChar ellipsisCharacter; ///< 省略号字符
private:
Font();
};
}
#endif
#ifndef TOUCHGFX_CONSTFONT_HPP
#define TOUCHGFX_CONSTFONT_HPP
#include <touchgfx/Font.hpp>
#include <touchgfx/Unicode.hpp>
#include <touchgfx/hal/Types.hpp>
namespace touchgfx
{
/**
* ConstFont类是一个Font类的实现,它的内容在编译时定义,并且通常放置在只读存储器中。
* @note 这是一个纯虚类。需要为getPixelData()和getKerning()创建应用程序特定的实现。 */
class ConstFont : public Font
{
public:
/**
* 初始化ConstFont类的一个新实例。
*
* @param glyphs 此字体已知的字形数组。
* @param numGlyphs 字形列表中的字形数量。
* @param height 字体的高度。
* @param baseline 基线的像素位置。
* @param pixAboveTop 文本顶部以上的最大像素数。
* @param pixBelowBottom 在此字体中,可以绘制在基线以下的最大像素数。
* @param bitsPerPixel 此字体中每像素的位数。
* @param byteAlignRow 字形保存时,每行都按字节对齐。
* @param maxLeft 字符向左延伸的最大值。
* @param maxRight 字符向右延伸的最大值。
* @param fallbackChar 当没有可用的字形时,用于排版的回退字符。
* @param ellipsisChar 用于截断长文本的省略号字符。
*/
ConstFont(const GlyphNode *glyphs, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, uint8_t bitsPerPixel, uint8_t byteAlignRow, uint8_t maxLeft, uint8_t maxRight, const Unicode::UnicodeChar fallbackChar, const Unicode::UnicodeChar ellipsisChar);
using Font::getGlyph;
/**
* 获取与指定unicode关联的字形的像素数据。
*
* @param unicode 要查找的字符。
* @param pixelData 返回指向此字形像素数据的指针的引用。
* @param bitsPerPixel 返回此字形的每像素位数。
*
* @return 指向字形节点的指针,如果未找到字形,则为null。
*/
virtual const GlyphNode* getGlyph(Unicode::UnicodeChar unicode, const uint8_t*& pixelData, uint8_t& bitsPerPixel) const;
/**
* 获取与此字形关联的像素数据。
*
* @param glyph 要获取像素数据的字形。
*
* @return 指向此字形像素数据的指针。这是一个纯虚函数,需要子类提供具体实现。
*/
virtual const uint8_t* getPixelData(const GlyphNode* glyph) const = 0;
/**
* 获取指定字符与字形之间的字距调整值。
*
* @param prevChar 前一个字符。
* @param glyph 要查找的字形。
*
* @return 字距调整值。这是一个纯虚函数,需要子类提供具体实现。
*/
virtual int8_t getKerning(Unicode::UnicodeChar prevChar, const GlyphNode* glyph) const = 0;
/**
* 查找与指定unicode关联的字形数据。
*
* @param unicode 要查找的字符。
*
* @return 指向字形节点的指针,如果未找到字形,则为null。
*/
const GlyphNode* find(Unicode::UnicodeChar unicode) const;
protected:
const GlyphNode *glyphList; //字形列表
uint16_t listSize; //字形列表的大小
private:
ConstFont() : Font(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), glyphList(0), listSize(0)
{
}
};
}
#endif
#ifndef TOUCHGFX_GENERATEDFONT_HPP
#define TOUCHGFX_GENERATEDFONT_HPP
#include <touchgfx/ConstFont.hpp>
namespace touchgfx
{
class GeneratedFont : public ConstFont
{
public:
//构造函数
//参数包括字形节点、字形数量、字体高度、基线、顶部像素、底部像素、每像素位数、行字节对齐、最大左边距、最大右边距、字形数据、字距调整列表、备选字符、省略字符、GSUB表和上下文形式表等
GeneratedFont(const GlyphNode *glyphs, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, uint8_t bitsPerPixel, uint8_t byteAlignRow, uint8_t maxLeft, uint8_t maxRight, const uint8_t *const *glyphDataInternalFlash, const KerningNode *kerningList, const Unicode::UnicodeChar fallbackChar, const Unicode::UnicodeChar ellipsisChar, const uint16_t *const gsubData, const FontContextualFormsTable *formsTable);
using ConstFont::getGlyph;
//获取指定字形的像素数据
virtual const uint8_t *getPixelData(const GlyphNode *glyph) const;
//根据前一个字符和当前字形获取字距调整值
virtual int8_t getKerning(Unicode::UnicodeChar prevChar, const GlyphNode *glyph) const;
//获取GSUB表(字形替换表)
virtual const uint16_t *getGSUBTable() const
{
return gsubTable;
}
//获取上下文形式表(可能用于特殊字形的渲染,如阿拉伯语等)
virtual const FontContextualFormsTable *getContextualFormsTable() const
{
return arabicTable;
}
protected:
GeneratedFont()
: ConstFont(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), glyphData(0), kerningData(0), gsubTable(0), arabicTable(0)
{
}
//字形像素的指针
const void *glyphData;
// 字距调整数据的指针
const KerningNode *kerningData;
// GSUB表的指针
const uint16_t *gsubTable;
// 上下文形式表的指针(可能用于特殊字形的渲染)
const FontContextualFormsTable *arabicTable;
};
}
#endif
三、静态字体
通过静态编译生成,并烧录到内存映射型闪存
#include <fonts/GeneratedFont.hpp>
/* 字形 */
FONT_TABLE_LOCATION_FLASH_PRAGMA
KEEP extern const touchgfx::GlyphNode glyphs_verdana_20_4bpp[] FONT_TABLE_LOCATION_FLASH_ATTRIBUTE = {
{ 0, 0x003F, 9, 14, 14, 1, 11, 0, 0, 0x00 }
};
FONT_TABLE_LOCATION_FLASH_PRAGMA
KEEP extern const touchgfx::GlyphNode glyphs_verdana_20_4bpp[] FONT_TABLE_LOCATION_FLASH_ATTRIBUTE;
/* 字形像素 */
FONT_GLYPH_LOCATION_FLASH_PRAGMA
KEEP extern const uint8_t unicodes_verdana_20_4bpp_0[] FONT_GLYPH_LOCATION_FLASH_ATTRIBUTE;
FONT_SEARCHTABLE_LOCATION_FLASH_PRAGMA
KEEP extern const uint8_t *const unicodes_verdana_20_4bpp[] FONT_SEARCHTABLE_LOCATION_FLASH_ATTRIBUTE = {
unicodes_verdana_20_4bpp_0
};
/* 字距调整 */
FONT_KERNING_LOCATION_FLASH_PRAGMA
KEEP extern const touchgfx::KerningNode kerning_verdana_20_4bpp[] FONT_KERNING_LOCATION_FLASH_ATTRIBUTE;
touchgfx::GeneratedFont& getFont_verdana_20_4bpp();
/* 获取字体verdana_20_4bpp */
touchgfx::GeneratedFont& getFont_verdana_20_4bpp()
{
/* 实例化: */
static touchgfx::GeneratedFont verdana_20_4bpp(glyphs_verdana_20_4bpp, 1, 20, 20, 0, 0, 4, 1, 0, 0, unicodes_verdana_20_4bpp, kerning_verdana_20_4bpp, 63, 0, 0, 0);
return verdana_20_4bpp;
}
#include <touchgfx/TypedText.hpp>
#include <fonts/GeneratedFont.hpp>
#include <texts/TypedTextDatabase.hpp>
extern touchgfx::GeneratedFont& getFont_verdana_20_4bpp();
extern touchgfx::GeneratedFont& getFont_verdana_40_4bpp();
extern touchgfx::GeneratedFont& getFont_verdana_10_4bpp();
/* 字体表 */
const touchgfx::Font *touchgfx_fonts[] = {
&(getFont_verdana_20_4bpp()), //字体1
&(getFont_verdana_40_4bpp()), //字体2
&(getFont_verdana_10_4bpp()) //字体3
};
/* 获取字体表指针 */
const touchgfx::Font **getFonts()
{
return touchgfx_fonts;
}
后面会通过registerTypedTextDatabase注册为TypedText类的静态成员变量
touchgfx::TypedText::registerTypedTextDatabase(currentLanguageTypedText, TypedTextDatabase::getFonts(), TypedTextDatabase::getInstanceSize());
四、二进制字体
二进制字体和静态字体相比的主要优势:
面对多语言场景, 如可以为要销往中国的设备提供中文字体,并为要销往日本的设备提供日文字体。 应用在运行时将这些文件加载并提供给TouchGFX,举例来说,应用可以从外部存储器(如SD卡)加载字体,也可以从互联网下载字体。
#ifndef TOUCHGFX_GENERATEDFONT_HPP
#define TOUCHGFX_GENERATEDFONT_HPP
#include <touchgfx/ConstFont.hpp>
namespace touchgfx
{
class GeneratedFont : public ConstFont
{
public:
//构造函数
//参数包括字形节点、字形数量、字体高度、基线、顶部像素、底部像素、每像素位数、行字节对齐、最大左边距、最大右边距、字形数据、字距调整列表、备选字符、省略字符、GSUB表和上下文形式表等
GeneratedFont(const GlyphNode *glyphs, uint16_t numGlyphs, uint16_t height, uint16_t baseline, uint8_t pixAboveTop, uint8_t pixBelowBottom, uint8_t bitsPerPixel, uint8_t byteAlignRow, uint8_t maxLeft, uint8_t maxRight, const uint8_t *const *glyphDataInternalFlash, const KerningNode *kerningList, const Unicode::UnicodeChar fallbackChar, const Unicode::UnicodeChar ellipsisChar, const uint16_t *const gsubData, const FontContextualFormsTable *formsTable);
using ConstFont::getGlyph;
//获取指定字形的像素数据
virtual const uint8_t *getPixelData(const GlyphNode *glyph) const;
//根据前一个字符和当前字形获取字距调整值
virtual int8_t getKerning(Unicode::UnicodeChar prevChar, const GlyphNode *glyph) const;
//获取GSUB表(字形替换表)
virtual const uint16_t *getGSUBTable() const
{
return gsubTable;
}
//获取上下文形式表(可能用于特殊字形的渲染,如阿拉伯语等)
virtual const FontContextualFormsTable *getContextualFormsTable() const
{
return arabicTable;
}
protected:
GeneratedFont()
: ConstFont(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), glyphData(0), kerningData(0), gsubTable(0), arabicTable(0)
{
}
//字形像素的指针
const void *glyphData;
// 字距调整数据的指针
const KerningNode *kerningData;
// GSUB表的指针
const uint16_t *gsubTable;
// 上下文形式表的指针(可能用于特殊字形的渲染)
const FontContextualFormsTable *arabicTable;
};
// 定义一个结构体,用于存储二进制字体的基本信息和偏移量
struct BinaryFontData
{
uint32_t fontIndex; // 字体在TypedTextDatabase中的索引
uint32_t sizeOfFontData; // 二进制字体的总大小
uint32_t offsetToTable; // GlyphNode数组(字体表)的偏移量
uint32_t offsetToKerning; // KerningNode数组(字距调整信息)的偏移量
uint32_t offsetToGlyphs; // 字体像素数据的偏移量
uint32_t offsetToGSUB; // GSUB表(用于字形替换)的偏移量
uint32_t offsetToArabicTable; // 阿拉伯文字体上下文形式表的偏移量
uint16_t numberOfGlyphs; // 字体表和像素数据中的字形数量
uint16_t fontHeight; // 字体高度
uint16_t baseline; // 基线距离
uint8_t pixAboveTop; // 字体上方最大像素数
uint8_t pixBelowBottom; // 字体下方最大像素数
uint8_t bitsPerPixel; // 每像素位数
uint8_t byteAlignRow; // 行对齐方式(A4/A2/A1)
uint8_t maxLeft; // 字形向左延伸的最大值
uint8_t maxRight; // 字形向右延伸的最大值
Unicode::UnicodeChar fallbackChar; // 字体的回退字符
Unicode::UnicodeChar ellipsisChar; // 字体的省略字符
};
// 定义一个BinaryFont类,继承自GeneratedFont类
class BinaryFont : public GeneratedFont
{
public:
// 构造函数,使用BinaryFontData结构体初始化字体
BinaryFont(const struct touchgfx::BinaryFontData* data)
: GeneratedFont((const GlyphNode*)((const uint8_t*)data + data->offsetToTable),
data->numberOfGlyphs,
data->fontHeight,
data->baseline,
data->pixAboveTop,
data->pixBelowBottom,
data->bitsPerPixel,
data->byteAlignRow,
data->maxLeft,
data->maxRight,
0,
(const KerningNode*)((const uint8_t*)data + data->offsetToKerning),
data->fallbackChar,
data->ellipsisChar,
(data->offsetToGSUB == 0) ? 0 : (const uint16_t*)((const uint8_t*)data + data->offsetToGSUB),
0),
glyphData((const uint8_t*)data + data->offsetToGlyphs)
{
// 如果存在阿拉伯文字体上下文形式表,则进行初始化
if (data->offsetToArabicTable > 0)
{
setupContextualTable(data);
}
}
BinaryFont() : GeneratedFont()
{
}
// 获取指定字形的像素数据
virtual const uint8_t *getPixelData(const GlyphNode *glyph) const
{
const uint8_t *data = (const uint8_t *)glyphData;
return &(data[glyph->dataOffset]);
}
protected:
const uint8_t *glyphData; // 存储字体像素数据的指针
FontContextualFormsTable contextualForms; // 存储阿拉伯文字体上下文形式表的对象
private:
// 定义指向Unicode字符数组的指针类型
typedef const Unicode::UnicodeChar (*array5ptr)[5];
typedef const Unicode::UnicodeChar (*array4ptr)[4];
// 初始化阿拉伯文字体上下文形式表
void setupContextualTable(const struct touchgfx::BinaryFontData *data)
{
const uint16_t *const base = (const uint16_t *)(((const uint8_t *)data) + data->offsetToArabicTable);
// 表中的首元素是数组偏移量(以16位字为单位)
contextualForms.contextualForms4Long = (array5ptr)(base + base[0]);
contextualForms.contextualForms3Long = (array5ptr)(base + base[1]);
contextualForms.contextualForms2Long = (array5ptr)(base + base[2]);
contextualForms.contextualForms0621_063a = (array4ptr)(base + base[3]);
contextualForms.contextualForms0641_064a = (array4ptr)(base + base[4]);
contextualForms.contextualForms06XX = (array5ptr)(base + base[5]);
contextualForms.contextualForms4LongSize = base[6];
contextualForms.contextualForms3LongSize = base[7];
contextualForms.contextualForms2LongSize = base[8];
contextualForms.contextualForms06XXSize = base[9];
arabicTable = &contextualForms;
}
};
}
#endif
#include <touchgfx/TypedText.hpp>
#include <fonts/GeneratedFont.hpp>
#include <texts/TypedTextDatabase.hpp>
extern touchgfx::GeneratedFont& getFont_verdana_20_4bpp();
extern touchgfx::GeneratedFont& getFont_verdana_40_4bpp();
extern touchgfx::GeneratedFont& getFont_verdana_10_4bpp();
/* 字体表 */
const touchgfx::Font *touchgfx_fonts[] = {
&(getFont_verdana_20_4bpp()), //字体1
&(getFont_verdana_40_4bpp()), //字体2
&(getFont_verdana_10_4bpp()) //字体3
};
/* 获取字体表指针 */
const touchgfx::Font **getFonts()
{
return touchgfx_fonts;
}
/* 设置字体 */
const touchgfx::Font *setFont(touchgfx::FontId fontId, const touchgfx::Font* font)
{
const touchgfx::Font *old = touchgfx_fonts[fontId];
touchgfx_fonts[fontId] = font;
return old;
}
/* 复位字体 */
void resetFont(touchgfx::FontId fontId)
{
switch (fontId)
{
case 0:
touchgfx_fonts[0] = &(getFont_verdana_20_4bpp());
break;
case 1:
touchgfx_fonts[1] = &(getFont_verdana_40_4bpp());
break;
case 2:
touchgfx_fonts[2] = &(getFont_verdana_10_4bpp());
break;
}
}
}
可以看出,使用二进制字体其实就是在二进制字体实例化之后,使用setFont函数将原先静态字体替换掉。
创建TextArea
配置字体转换器以生成二进制字体
安装二进制字体
FrontendApplication.hpp
#include <gui/common/FrontendApplication.hpp>
#include <BitmapDatabase.hpp>
#include <stdio.h>
#include <fonts/GeneratedFont.hpp>
#include <texts/TypedTextDatabase.hpp>
#include <fonts/ApplicationFontProvider.hpp>
LOCATION_PRAGMA_NOLOAD("TouchGFX_Cache")
uint16_t Cache[1024 * 604] LOCATION_ATTRIBUTE_NOLOAD("TouchGFX_Cache");
LOCATION_PRAGMA_NOLOAD("TouchGFX_Fontdata")
uint8_t fontdata[10000] LOCATION_ATTRIBUTE_NOLOAD("TouchGFX_Fontdata");
BinaryFont bf;
FrontendApplication::FrontendApplication(Model& m, FrontendHeap& heap)
: FrontendApplicationBase(m, heap)
{
#ifdef SIMULATOR
const uint32_t cacheSize = 0x300000; //3 MB, as example
uint16_t* const cacheStartAddr = (uint16_t*)malloc(cacheSize);
Bitmap::setCache(cacheStartAddr, cacheSize, 4);
FILE* font = fopen("generated/fonts/bin/Font_verdana_20_4bpp.bin", "rb");
if (font)
{
//read data from the file
fread(fontdata, 1, 10000, font);
fclose(font);
//initialize BinaryFont object in bf using placement new
new (&bf) BinaryFont((const struct touchgfx::BinaryFontData*)fontdata);
//replace application font 'DEFAULT' with the binary font
TypedTextDatabase::setFont(Typography::DEFAULT, &bf); //verdana_20_4bpp
}
#else
Bitmap::setCache(Cache, sizeof(Cache));
#endif
}
运行模拟器
从上面的例子中可以看出,此方法的缺点是需要将整个二进制字体加载到RAM(或存储器映射闪存),在字体较大时会面临困难。