使用Uniscribe 处理复杂文本(3)
文章转自王牌软件
站长推荐:NSetup一键部署软件
一键式完成美化安装包制作,自动增量升级,数据统计,数字签名。应对各种复杂场景,脚本模块化拆分,常规复杂的脚本代码,图形化设置。无需专业的研发经验,轻松完成项目部署。(www.nsetup.cn)
只回答业务咨询
站长推荐:NSetup一键部署软件
一键式完成美化安装包制作,自动增量升级,数据统计,数字签名。应对各种复杂场景,脚本模块化拆分,常规复杂的脚本代码,图形化设置。无需专业的研发经验,轻松完成项目部署。(www.nsetup.cn)
Uniscribe API 介绍
Uniscribe API 含有DC 的函数,除了ScriptTextOut 和ScriptStringOut 考虑DC 布局外(RTL 布局和LTR 布局下结果不一致),其余的函数一律不考虑DC 布局(RTL 布局和LTR 布局下结果一致)。
HRESULT WINAPI ScriptApplyDigitSubstitution(
const SCRIPT_DIGITSUBSTITUTE *psds,
SCRIPT_CONTROL *psc,
SCRIPT_STATE *pss
);
函数功能:应用数字替换
参数描述:
psds : 输入参数,该结构由函数ScriptRecordDigitSubstitution 获得
psc: 输出参数,脚本控制结构
pss: 输出参数,脚本状态结构
函数存在的目的?
我们知道(或许不知道),这个世界上并不是只有0123456789 可以表示数字的,还有像阿拉伯文的数字,在一定环境下我们希望数字能有特殊的显示效果。比如在阿拉伯国家(此时系统的缺省语言是阿拉伯语),我们在阿拉伯非数字字符后侧输入数字应该显示成阿拉伯本地的数字。
HESULT WINAPI ScriptApplyLogicalWidth(
const int *piDx,
int cChars,
int cGlyphs,
const WORD *pwLogClust,
const SCRIPT_VISATTR *psva,
const int *piAdvance,
const SCRIPT_ANALYSIS *psa,
ABC *pABC,
int *piJustify,
);
没用过。
HRESULT WINAPI ScriptBreak(
const WCHAR *pwcChars,
int cChars,
const SCRIPT_ANALYSIS *psa,
SCRIPT_LOGATTR *psla
);
函数功能: 返回当前文本的截断信息
参数描述:
pwcChars: 输入参数,需要获取信息的文本段
cChars: 输入参数,文本字符个数
psa: 输入参数,文本分析结果,由ScriptItemize 函数获得
psla: 输出参数,文本截断信息
函数存在目的?
我们在使用记事本时如果单词在本行无法显示完全,需要换到下一行,我们更希望能够将整个单词换到下一行,而不是部分。因此我们需要能够分析在何处换行的函数。
HRESULT WINAPI ScriptCacheGetHeight(
HDC hdc,
SCRIPT_CACHE *psc,
long *tmHeight
);
函数功能: 获取当前缓存中字体的建议高度
参数描述:
hdc: 输入参数,dc
psc: 输入参数,缓存,由ScriptShape 函数获得
tmHeight: 输出参数,建议高度
函数存在目的?
我们计算输出文本的大小,这个函数可以计算文本的高度。
HRESULT WINAPI ScriptCPtoX(
int iCP,
BOOL fTrailing,
int cChars,
int cGlyphs,
const WORD *pwLogClust,
const SCRIPT_VISATTR *psva,
const int *piAdvance,
const SCRIPT_ANALYSIS *psa,
int *piX
);
函数功能: 计算字符的位置
参数描述:
icp: 输入参数,字符索引值
fTrailing: 输入参数,位置偏向性
cChars: 输入参数,字符个数
cGlyphs: 输入参数,字形个数
pwLogClust: 输入参数,簇标记数组
psva: 输入参数,字形属性数组
piAdvance: 输入参数,字形宽度
psa: 输入参数,本段文本块(item)分析结果,由ScriptItemize 获得
piDx: 输出参数,字符的位置
函数存在目的?
我们必须知道当前光标的有效位置,使用这个函数可以计算出精确位置
函数如何实现?
这个函数是针对每一个Item 而言的(Item 详见ScriptItemSize 函数),每个Item 均是由若干个簇组成,位置的计算是根据簇,而不是单纯的根据字符宽度或字形宽度。
首先会判断该Item 是否是RTL 方向绘制的文本,假设是RTL;
接着计算icp + fTrailing在哪个簇内;
找到指定的簇之后,位置即为该簇的右侧(此处可能存在特殊情况,因为阿拉伯组合字符允许光标定位在组合字符中间部位,而泰文等其他大多数组合字符不允许在中间出现光标)。
例1:
فُضُلي
在Arial Unicode MS 字体下,
文本绘制方向:RTL
字符码值(按显示顺序,最前面是最后一个字符):
U+064a, U+ 0644, U+ 064f, U+ 0636, U+064f, U+ 0641
字形值: 6610 6592 1230 6560 1230 6579
字形宽度: 10 3 0 10 0 6
簇标记: 5 5 3 3 1 0
簇信息:
第一簇: 字符范围[5] 字形范围[0] 宽度10
第二簇: 字符范围[4] 字形范围[1] 宽度3
第三簇: 字符范围[2,3] 字形范围[2,3] 宽度10
第四簇: 字符范围[0,1] 字形范围[4,5] 宽度6
我们可以很确定第三簇和第四簇均是组合字符。
现在我们给定参数iCP = 1,fTrailing = FALSE,实际求取字符位置是索引值为1 的字符位置。
按上面所讲规则,索引在第四簇内,则光标位置应该在第四簇的右侧(前提是RTL 文本),所以光标的位置应该是29,但是因为阿拉伯文本的特殊性,允许组合字符中部出现光标,所以光标的位置实际是26。最后一簇含有两个字符,索引相对簇开始字符的偏移是1-0=1,占比是1/2 = 50%,所以距簇开始字符处的偏移为50% * 6 = 3, 因此实际位置是29 – 3 = 26。
例2:
ฆูีฟิฟ
字体选用:Tahoma
文本绘制方向:LTR
字符码值: U+0e06, U+0e39, U+0e35, U+0e1d, U+0e34, U+0e1d
字形值: 2109 2160 3232 2134 5444 2134
字形宽度: 9 0 0 8 0 8
簇标记: 0 0 0 3 3 5
簇信息:
第一簇: 字符范围[0,2], 字形范围[0,2], 宽度9
第二簇: 字符范围[3,4], 字形范围[3,4], 宽度8
第三簇: 字符范围[5], 字形范围[5], 宽度9
我们可以很确定第一簇和第二簇均是组合字符。
我们给定参数iCP = 1,fTrailing = FALSE,实际求取字符位置是索引值为1 的字符位置。
因为1 在第一簇的范围内,所以位置在第一簇的左侧(前提是LTR文本),即0
我们给定参数iCP = 1,fTrailing = TRUE,实际求取字符位置是索引值为2 的字符位置。
因为2 在第一簇的范围内,所以位置在第一簇的左侧,即0
我们给定参数iCP = 3,fTrailing = FALSE,实际求取字符位置是索引值为2 的字符位置。
因为3 在第二簇的范围内,所以位置在第二簇的左侧,即9.
如果实际求取字符索引值大于等于本Item 的字符个数,则光标位置在最后一个簇的右侧,即25。
HRESULT WINAPI ScriptFreeCache(
SCRIPT_CACHE *psc
);
函数功能:
释放Uniscribe 为每一个Item 分配的字体缓存空间
学习日记,兼职软件设计,软件修改,毕业设计。
本文出自 学习日记,转载时请注明出处及相应链接。
本文永久链接: https://www.softwareace.cn/?p=301