TouchGFX之字体

一、先说明几个基本概念

        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(或存储器映射闪存),在字体较大时会面临困难。

相关推荐

  1. OracleORA-29275: 部分多字节字符

    2024-03-20 23:32:01       62 阅读
  2. Bootstrap5icons字体图标及简单布局案例

    2024-03-20 23:32:01       54 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-20 23:32:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-20 23:32:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-20 23:32:01       87 阅读
  4. Python语言-面向对象

    2024-03-20 23:32:01       96 阅读

热门阅读

  1. PHP魔术方法详解

    2024-03-20 23:32:01       43 阅读
  2. Python从入门到精通秘籍九

    2024-03-20 23:32:01       43 阅读
  3. 八股文三(Spring、Spring Cloud Alibaba)

    2024-03-20 23:32:01       37 阅读
  4. 使用 mypy 做 type check

    2024-03-20 23:32:01       43 阅读
  5. 数据结构的美之百家争鸣-redis-dict篇

    2024-03-20 23:32:01       39 阅读
  6. 蓝桥杯2017省赛:分巧克力|枚举到二分

    2024-03-20 23:32:01       43 阅读
  7. 小项目知识点

    2024-03-20 23:32:01       46 阅读
  8. AcWing 167.木棒

    2024-03-20 23:32:01       47 阅读
  9. 2024最新华为OD机试试题库全 -【游戏分组】- C卷

    2024-03-20 23:32:01       48 阅读
  10. MongoDB聚合运算符:$floor

    2024-03-20 23:32:01       45 阅读
  11. 安卓面试题多线程 61-65

    2024-03-20 23:32:01       35 阅读
  12. Typescript泛型

    2024-03-20 23:32:01       42 阅读
  13. 5.1.1.1、【AI技术新纪元:Spring AI解码】功能调用

    2024-03-20 23:32:01       37 阅读
  14. SpringBoot 如何快速过滤出一次请求的所有日志?

    2024-03-20 23:32:01       42 阅读