阿拉伯字母变形表
Arabic Alphabet Shape Table / 阿拉伯字母的变形程序
####阿拉伯语字母,除了用在阿拉伯语,还用在了波斯语等其它许多语言中,包括我国新疆维吾尔语。完全不懂阿拉伯语,为了在嵌入式设备上的程序,能处理阿拉伯语的变形问题,才收集一些资料学习。所有文字来自于网络上的资料加工编辑而成。
阿拉伯语的课本上,都是从阿拉伯语的语法、 词法甚至书法上,讲解阿拉伯语字母的变形问题,这种解释对于编写阿拉伯字母变形程序,基本上没有什么参考价值,或者说学习代价带太大了,不实用。不需要学懂阿拉伯语的这些语法规则,只要知道在计算机显示环境下,一个uincode的字符在何种上下文的条件下,变换成何种字符即可。
####学习的结论是,阿拉伯语优先考虑了书写视觉上要求,没有使用所见即所得的直观符号处理方式(看见的符号就是实际保存的符号),而是将阿拉伯字母渲染之后再显示。完整的渲染流程应该是:计算机在显示阿拉伯字母时,需要根据选择阿拉伯字母的书写风格和当前选择的字体,以及显示位置、书写空间的情况,将字母原型(不是字母原型似乎也能处理),经过Shape(字母位置变形)、Ligature(Combined)(字母连写变形 或称作结合变形)、Diacritics(字母标注变(元)音符号变形)、Kashida(为了凑满一整行字母延长变形)、Tatwell(插入字母链接符号)等等一系列的操作,才可以将一段阿拉伯字母渲染输出(Rendering),从右到左的排版,再与从左至右的字符混合排版后,显示出来。不能完全确定信息是:不同的地域语言,阿拉伯字母变形规则有可能有所不同。全部的变形规则中,最主要的变形是Shape和Ligature。如果用汉语来非常粗略的比喻阿拉伯语的连写变形规则,就好像一篇汉字文章在显示(书写的)的时候被要求,一定要把文字中的“不好”显示成“孬”,把“混凝土”显示成“砼”,把“不用”显示成“甭”...,。阿拉伯语是最难学习的语言之一。
####一般情况下,阿拉伯语的数据文件都是用Unicode编码保存,并且保存的是阿拉伯字母原型字符的Unicode编码(General Unicode),General Unicode字符的Unicode编码是在0x06**范围内,在显示的文件的时候,各种显示软件会根据当时的显示环境,按照阿拉伯语的书写规则,执行一套操作变形渲染之后,反向(从右到左)显示。变形之后的阿拉伯字符(Contextual forms)其Unicode编码大致是在0xFE**范围。权威的Unicode编码阿拉伯文本( Arabic Script )处理细节 ,参考这里: (see Section 9.2, Arabic of [Unicode]) ,& 这里 :Text Layout Requirements for the Arabic Script (w3c.github.io)
####变形之后显示输出来的 Arabic Letter 字符虽然也是Unicode字符(Contextual forms),但是它们一般不使用Unicode编码表示,而是用预先设定的字体的glyph id表示,并且再附加上字体信息、格式信息,因为显示出来的字母有可能是几个字符叠加渲染出来的,所以字体信息、格式信息也很重要。在0x20**范围的一些Unicode字符,是格式控制字符和标注元音用的叠加字符。阿拉伯语字母为了视觉效果的渲染变形,有着多对一,多对多复杂的映射关系,完整全套的变形的处理功能(包括双向排版处理),绝非是一个小程序就可以实现的。但是还是有一些小程序,实现了(现代标准阿拉伯语的)阿拉伯语字母 Shape(位置变形) & Ligature(连写变形) 这2个最主要视觉变形功能,可以用在简单的设备显示阿拉伯字母。例如:
https://github.com/Konash/arabic-support-unity/blob/master/Assets/ArabicSupport/Scripts/ArabicSupport.cs
https://github.com/mpcabd/python-arabic-reshaper
https://github.com/louy/Javascript-Arabic-Reshaper
https://github.com/Accorpa/Arabic-Converter-From-and-To-Arabic-Presentation-Forms-B/blob/master/ArabicConverter.m
https://github.com/TerryCavanagh/hx_arabic_shaper/tree/main/src/hx_arabic_shaper
https://github.com/hopewise/ArabicShaper/tree/master/src/arabic/shaper
一些Gui库中,也有阿拉伯语字母的处理代码,例如:以往旧版MTK,ucGUI(emWIN)。
####下图是一些Arabic Alphabet Shape阿拉伯字母各种视觉渲染变形例子,来自网络上的资料截图,注意阿拉伯字母是从右至左阅读的:
位置变形:首位变形,末尾变形的例子
连接变形的例子:
标注元音的例子:
为了视觉效果,复杂的多种形态变形例子:
为了视觉效果(凑满一整行)延长变形的例子:
插入了延长字符的例子:
####阿拉伯字母与其它字母混合显示时,除了字母变形问题之外,还有双向显示排版的问题。双向混合排版显示问题,也是一个非常复杂的问题。可以完全处理世界上各种语言(包括Arabic Letter)字母视觉渲染变形和双向排版问题的开源代码有:icu bidi :https://github.com/unicode-org/icu
专门针对阿拉伯语和希伯来语字符渲染处理的开源软件有:fribidi :https://github.com/fribidi/fribidi/
fribidi在MS Windows可用的 dll & lib : https://github.com/ShiftMediaProject/fribidi/releases
另外,还有微软的Uniscribe组件。Uniscribe是微软公司开发的Windows操作系统为正确演示Unicode文字而开发的组件。在Windows中显示的字符,如果需要变形,都是经过Unicscribe输出的。下图是直接使用 USP10.DLL 显示“连写”变形字符的例子。理论上是,显示需要变形渲染的字符,要显示“比所见即所得”的字符慢一些,需要经过USP10.DLL一整套处理。
除了看微软的文档之外,浏览翻找这里,有Uniscribe使用说明和实例下载
####字符变形之后, Shape & Ligature 变形导致字符Unicode编码变化的的例子:
//可用于测试位置变形和连写的字符串 //"\x0633\x0645\x064A\x0631" -> "\xFEB3\xFEE4\xFEF4\xFEAE" //"x0633\x0645\x064A\x0631" -> "\xFEB3\xFEE4\xFEF4\xFEAE" //"\u0632\u0632\u0644\u0622" -> \xFEAF(位置变形) \xFEAF(位置变形) \xFEF5(连写变形 one glyph ligature) //"\u064a\u0644\u0622" -> "\uFEF3\uFEF6" //"\u0632\u0644\u0622" -> "\uFEAF\uFEF5"
####不是所有的代码编辑器,都能完全正确显示阿拉伯字符的,即便是完全支持阿拉伯字符的编辑器,对于不懂阿语的人来说,也难以自容的编辑阿拉伯字符。下表中,用英文字符o将它们包围起来,防止阿拉伯语字母显示的时候,自动发生各种变形。这个变形表,仅仅显示出了阿拉伯字母位置变形情况。
参考:各种的程序代码编辑器,对阿拉伯字母的显示效果比较:Sublime Text 2 能逻辑上“正确的”显示阿拉伯语字母(虽然不正确,但程序员需要这样的错误)
####阿拉伯字母位置变形表
o o 中是空白表示不变化。原型字母的Unicode是0x06**,变形字母Unicode是0xfe**
原型----独立-----在后-----在前-----中间
oءo , oﺀo , o o , o o , o o , Arabic letter Hamza
oآo , oﺁo , oﺂo , o o , o o , Arabic letter Alef with Madda ab
oأo , oﺃo , oﺄo , o o , o o , Arabic letter Alef with Hamza ab
oؤo , oﺅo , oﺆo , o o , o o , Arabic letter Waw with Hamza abo
oإo , oﺇo , oﺈo , o o , o o , Arabic letter Alef with Hamza be
oئo , oﺉo , oﺊo , oﺋo , oﺌo , Arabic letter Yeh with Hamza abo
oاo , oﺍo , oﺎo , o o , o o , Arabic letter Alef
oبo , oﺏo , oﺐo , oﺑo , oﺒo , Arabic letter Beh
oةo , oﺓo , oﺔo , o o , o o , Arabic letter Teh Marbuta
oتo , oﺕo , oﺖo , oﺗo , oﺘo , Arabic letter Teh
oثo , oﺙo , oﺚo , oﺛo , oﺜo , Arabic letter Theh
oجo , oﺝo , oﺞo , oﺟo , oﺠo , Arabic letter Jeem
oحo , oﺡo , oﺢo , oﺣo , oﺤo , Arabic letter Hah
oخo , oﺥo , oﺦo , oﺧo , oﺨo , Arabic letter Khah
oدo , oﺩo , oﺪo , o o , o o , Arabic letter Dal
oذo , oﺫo , oﺬo , o o , o o , Arabic letter Thal
oرo , oﺭo , oﺮo , o o , o o , Arabic letter Reh
oزo , oﺯo , oﺰo , o o , o o , Arabic letter Zain
oسo , oﺱo , oﺲo , oﺳo , oﺴo , Arabic letter Seen
oشo , oﺵo , oﺶo , oﺷo , oﺸo , Arabic letter Sheen
oصo , oﺹo , oﺺo , oﺻo , oﺼo , Arabic letter Sad
oضo , oﺽo , oﺾo , oﺿo , oﻀo , Arabic letter Dad
oطo , oﻁo , oﻂo , oﻃo , oﻄo , Arabic letter Tah
oظo , oﻅo , oﻆo , oﻇo , oﻈo , Arabic letter Zah
oعo , oﻉo , oﻊo , oﻋo , oﻌo , Arabic letter Ain
oغo , oﻍo , oﻎo , oﻏo , oﻐo , Arabic letter Ghain
oفo , oﻑo , oﻒo , oﻓo , oﻔo , Arabic letter Feh
oقo , oﻕo , oﻖo , oﻗo , oﻘo , Arabic letter Qaf
oكo , oﻙo , oﻚo , oﻛo , oﻜo , Arabic letter Kaf
oلo , oﻝo , oﻞo , oﻟo , oﻠo , Arabic letter Lam
oمo , oﻡo , oﻢo , oﻣo , oﻤo , Arabic letter Meem
oنo , oﻥo , oﻦo , oﻧo , oﻨo , Arabic letter Noon
oهo , oﻩo , oﻪo , oﻫo , oﻬo , Arabic letter Heh
oوo , oﻭo , oﻮo , o o , o o , Arabic letter Waw
oىo , oﻯo , oﻰo , o o , o o , Arabic letter Alef Maksura
oيo , oﻱo , oﻲo , oﻳo , oﻴo , Arabic letter Yeh
oپo , oﭖo , oﭗo , oﭘo , oﭙo , Eastern arabic letter Peh
oچo , oﭺo , oﭻo , oﭼo , oﭽo , Eastern arabic letter Tcheh
oژo , oﮊo , oﮋo , o o , o o , Eastern arabic letter Jeh
oکo , oﮎo , oﮏo , oﮐo , oﮑo , Eastern arabic letter Keheh
oگo , oﮒo , oﮓo , oﮔo , oﮕo , Eastern arabic letter Gaf
oیo , oﯼo , oﯽo , o o , o o , Eastern arabic letter Farsi Yeh
可以将这些数据,导入到Excel表:
注意:空白表示不变(同“独立”),原型字母的Unicode是0x06**,变形字母Unicode是0xfe**
上面的数据来自于下面这个程序(C#)的源代码。 :
static public readonly char[,] _LetterShapeTable = new char [,]{ /* Base Isol. Final Initial Medial */ /* 原型, 独立, 后边(在左),前边(在右),内侧(中间)*/ { /* 0 0x0621 */ '\u0621', '\uFE80', '\u0000', '\u0000', '\u0000' /* Arabic letter Hamza */ }, { /* 1 0x0622 */ '\u0622', '\uFE81', '\uFE82', '\u0000', '\u0000' /* Arabic letter Alef with Madda above */ }, { /* 2 0x0623 */ '\u0623', '\uFE83', '\uFE84', '\u0000', '\u0000' /* Arabic letter Alef with Hamza above */ }, { /* 3 0x0624 */ '\u0624', '\uFE85', '\uFE86', '\u0000', '\u0000' /* Arabic letter Waw with Hamza above */ }, { /* 4 0x0625 */ '\u0625', '\uFE87', '\uFE88', '\u0000', '\u0000' /* Arabic letter Alef with Hamza below */ }, { /* 5 0x0626 */ '\u0626', '\uFE89', '\uFE8A', '\uFE8B', '\uFE8C' /* Arabic letter Yeh with Hamza above */ }, { /* 6 0x0627 */ '\u0627', '\uFE8D', '\uFE8E', '\u0000', '\u0000' /* Arabic letter Alef */ }, { /* 7 0x0628 */ '\u0628', '\uFE8F', '\uFE90', '\uFE91', '\uFE92' /* Arabic letter Beh */ }, { /* 8 0x0629 */ '\u0629', '\uFE93', '\uFE94', '\u0000', '\u0000' /* Arabic letter Teh Marbuta */ }, { /* 9 0x062A */ '\u062A', '\uFE95', '\uFE96', '\uFE97', '\uFE98' /* Arabic letter Teh */ }, { /* 10 0x062B */ '\u062B', '\uFE99', '\uFE9A', '\uFE9B', '\uFE9C' /* Arabic letter Theh */ }, { /* 11 0x062C */ '\u062C', '\uFE9D', '\uFE9E', '\uFE9F', '\uFEA0' /* Arabic letter Jeem */ }, { /* 12 0x062D */ '\u062D', '\uFEA1', '\uFEA2', '\uFEA3', '\uFEA4' /* Arabic letter Hah */ }, { /* 13 0x062E */ '\u062E', '\uFEA5', '\uFEA6', '\uFEA7', '\uFEA8' /* Arabic letter Khah */ }, { /* 14 0x062F */ '\u062F', '\uFEA9', '\uFEAA', '\u0000', '\u0000' /* Arabic letter Dal */ }, { /* 15 0x0630 */ '\u0630', '\uFEAB', '\uFEAC', '\u0000', '\u0000' /* Arabic letter Thal */ }, { /* 16 0x0631 */ '\u0631', '\uFEAD', '\uFEAE', '\u0000', '\u0000' /* Arabic letter Reh */ }, { /* 17 0x0632 */ '\u0632', '\uFEAF', '\uFEB0', '\u0000', '\u0000' /* Arabic letter Zain */ }, { /* 18 0x0633 */ '\u0633', '\uFEB1', '\uFEB2', '\uFEB3', '\uFEB4' /* Arabic letter Seen */ }, { /* 19 0x0634 */ '\u0634', '\uFEB5', '\uFEB6', '\uFEB7', '\uFEB8' /* Arabic letter Sheen */ }, { /* 20 0x0635 */ '\u0635', '\uFEB9', '\uFEBA', '\uFEBB', '\uFEBC' /* Arabic letter Sad */ }, { /* 21 0x0636 */ '\u0636', '\uFEBD', '\uFEBE', '\uFEBF', '\uFEC0' /* Arabic letter Dad */ }, { /* 22 0x0637 */ '\u0637', '\uFEC1', '\uFEC2', '\uFEC3', '\uFEC4' /* Arabic letter Tah */ }, { /* 23 0x0638 */ '\u0638', '\uFEC5', '\uFEC6', '\uFEC7', '\uFEC8' /* Arabic letter Zah */ }, { /* 24 0x0639 */ '\u0639', '\uFEC9', '\uFECA', '\uFECB', '\uFECC' /* Arabic letter Ain */ }, { /* 25 0x063A */ '\u063A', '\uFECD', '\uFECE', '\uFECF', '\uFED0' /* Arabic letter Ghain */ }, { /* 26 0x0641 */ '\u0641', '\uFED1', '\uFED2', '\uFED3', '\uFED4' /* Arabic letter Feh */ }, { /* 27 0x0642 */ '\u0642', '\uFED5', '\uFED6', '\uFED7', '\uFED8' /* Arabic letter Qaf */ }, { /* 28 0x0643 */ '\u0643', '\uFED9', '\uFEDA', '\uFEDB', '\uFEDC' /* Arabic letter Kaf */ }, { /* 29 0x0644 */ '\u0644', '\uFEDD', '\uFEDE', '\uFEDF', '\uFEE0' /* Arabic letter Lam */ }, { /* 30 0x0645 */ '\u0645', '\uFEE1', '\uFEE2', '\uFEE3', '\uFEE4' /* Arabic letter Meem */ }, { /* 31 0x0646 */ '\u0646', '\uFEE5', '\uFEE6', '\uFEE7', '\uFEE8' /* Arabic letter Noon */ }, { /* 32 0x0647 */ '\u0647', '\uFEE9', '\uFEEA', '\uFEEB', '\uFEEC' /* Arabic letter Heh */ }, { /* 33 0x0648 */ '\u0648', '\uFEED', '\uFEEE', '\u0000', '\u0000' /* Arabic letter Waw */ }, { /* 34 0x0649 */ '\u0649', '\uFEEF', '\uFEF0', '\u0000', '\u0000' /* Arabic letter Alef Maksura */ }, { /* 35 0x064A */ '\u064A', '\uFEF1', '\uFEF2', '\uFEF3', '\uFEF4' /* Arabic letter Yeh */ }, { /* 36 0x067E */ '\u067E', '\uFB56', '\uFB57', '\uFB58', '\uFB59' /* Eastern arabic letter Peh */ }, { /* 37 0x0686 */ '\u0686', '\uFB7A', '\uFB7B', '\uFB7C', '\uFB7D' /* Eastern arabic letter Tcheh */ }, { /* 38 0x0698 */ '\u0698', '\uFB8A', '\uFB8B', '\u0000', '\u0000' /* Eastern arabic letter Jeh */ }, { /* 39 0x06A9 */ '\u06A9', '\uFB8E', '\uFB8F', '\uFB90', '\uFB91' /* Eastern arabic letter Keheh */ }, { /* 40 0x06AF */ '\u06AF', '\uFB92', '\uFB93', '\uFB94', '\uFB95' /* Eastern arabic letter Gaf */ }, { /* 41 0x06CC */ '\u06CC', '\uFBFC', '\uFBFD', '\u0000', '\u0000' /* Eastern arabic letter Farsi Yeh */ }, };
####编写程序,在程序种观察阿拉伯字位置变形和连写变形情况,这个程序还可以输入一个不正确的变形,看看微软是如何处理的。
####问题:获得了变形之后的字符串Unicode,和变形前的字符串Unicode,在比较函数中,如何认为它们是“相等”的?因为它们的确有着某种等价关系。
####测试一下网络上收集的各种阿拉伯字母变形处理程序,验证能否正确的处理位置变形和连写变形,对比发现有的程序是无法处理连写规则的,右边正确的连写变形,左边是出错的例子:
####连写规则表
Ligatures
Character combinations of Lam and Alef are transformed into ligatures. The following table
shows how emWin transforms these combinations into ligatures, if the first letter is a Lam
(code 0x0644 ):
Second letter | Ligature (final) | Ligature (elsewhere)
0x622 , Alef with Madda above | 0xFEF6 | 0xFEF5
0x623 , Alef with Hamza above | 0xFEF8 | 0xFEF7
0x625 , Alef with Hamza below | 0xFEFA | 0xFEF9
0x627 , Alef | 0xFEFC | 0xFEFB
####附录1:
其它一些收集的资料截图
阿拉伯字母位置变形规则
-------------------------------------------------------------------------------------------------------------------------------------------
阿拉伯字母连写变形规则 :
####知乎网上的资料:维吾尔语使用的阿拉伯语字母的情况,从中可以看出地域不同的差异。
####附录2
Arabic Shaping 程序例子:(来自网络)
//include ......
#if 1 // only test for simple Arabic shaping
/*********************************************************************
*
*
*
**********************************************************************
*/
typedef struct {
U16 Isolated;
U16 Final;
U16 Initial;
U16 Medial;
} KEY_INFO;
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
static const KEY_INFO _aKeyInfo[] = {
/* Base Isol. Final Initial Medial */
{ /* 0 0x0621 */ 0xFE80, 0x0000, 0x0000, 0x0000 /* Arabic letter Hamza */ },
{ /* 1 0x0622 */ 0xFE81, 0xFE82, 0x0000, 0x0000 /* Arabic letter Alef with Madda above */ },
{ /* 2 0x0623 */ 0xFE83, 0xFE84, 0x0000, 0x0000 /* Arabic letter Alef with Hamza above */ },
{ /* 3 0x0624 */ 0xFE85, 0xFE86, 0x0000, 0x0000 /* Arabic letter Waw with Hamza above */ },
{ /* 4 0x0625 */ 0xFE87, 0xFE88, 0x0000, 0x0000 /* Arabic letter Alef with Hamza below */ },
{ /* 5 0x0626 */ 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C /* Arabic letter Yeh with Hamza above */ },
{ /* 6 0x0627 */ 0xFE8D, 0xFE8E, 0x0000, 0x0000 /* Arabic letter Alef */ },
{ /* 7 0x0628 */ 0xFE8F, 0xFE90, 0xFE91, 0xFE92 /* Arabic letter Beh */ },
{ /* 8 0x0629 */ 0xFE93, 0xFE94, 0x0000, 0x0000 /* Arabic letter Teh Marbuta */ },
{ /* 9 0x062A */ 0xFE95, 0xFE96, 0xFE97, 0xFE98 /* Arabic letter Teh */ },
{ /* 10 0x062B */ 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C /* Arabic letter Theh */ },
{ /* 11 0x062C */ 0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0 /* Arabic letter Jeem */ },
{ /* 12 0x062D */ 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4 /* Arabic letter Hah */ },
{ /* 13 0x062E */ 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8 /* Arabic letter Khah */ },
{ /* 14 0x062F */ 0xFEA9, 0xFEAA, 0x0000, 0x0000 /* Arabic letter Dal */ },
{ /* 15 0x0630 */ 0xFEAB, 0xFEAC, 0x0000, 0x0000 /* Arabic letter Thal */ },
{ /* 16 0x0631 */ 0xFEAD, 0xFEAE, 0x0000, 0x0000 /* Arabic letter Reh */ },
{ /* 17 0x0632 */ 0xFEAF, 0xFEB0, 0x0000, 0x0000 /* Arabic letter Zain */ },
{ /* 18 0x0633 */ 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4 /* Arabic letter Seen */ },
{ /* 19 0x0634 */ 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8 /* Arabic letter Sheen */ },
{ /* 20 0x0635 */ 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC /* Arabic letter Sad */ },
{ /* 21 0x0636 */ 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0 /* Arabic letter Dad */ },
{ /* 22 0x0637 */ 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4 /* Arabic letter Tah */ },
{ /* 23 0x0638 */ 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8 /* Arabic letter Zah */ },
{ /* 24 0x0639 */ 0xFEC9, 0xFECA, 0xFECB, 0xFECC /* Arabic letter Ain */ },
{ /* 25 0x063A */ 0xFECD, 0xFECE, 0xFECF, 0xFED0 /* Arabic letter Ghain */ },
{ /* 26 0x0641 */ 0xFED1, 0xFED2, 0xFED3, 0xFED4 /* Arabic letter Feh */ },
{ /* 27 0x0642 */ 0xFED5, 0xFED6, 0xFED7, 0xFED8 /* Arabic letter Qaf */ },
{ /* 28 0x0643 */ 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC /* Arabic letter Kaf */ },
{ /* 29 0x0644 */ 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0 /* Arabic letter Lam */ },
{ /* 30 0x0645 */ 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4 /* Arabic letter Meem */ },
{ /* 31 0x0646 */ 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8 /* Arabic letter Noon */ },
{ /* 32 0x0647 */ 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC /* Arabic letter Heh */ },
{ /* 33 0x0648 */ 0xFEED, 0xFEEE, 0x0000, 0x0000 /* Arabic letter Waw */ },
{ /* 34 0x0649 */ 0xFEEF, 0xFEF0, 0x0000, 0x0000 /* Arabic letter Alef Maksura */ },
{ /* 35 0x064A */ 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4 /* Arabic letter Yeh */ },
{ /* 36 0x067E */ 0xFB56, 0xFB57, 0xFB58, 0xFB59 /* Eastern arabic letter Peh */ },
{ /* 37 0x0686 */ 0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D /* Eastern arabic letter Tcheh */ },
{ /* 38 0x0698 */ 0xFB8A, 0xFB8B, 0x0000, 0x0000 /* Eastern arabic letter Jeh */ },
{ /* 39 0x06A9 */ 0xFB8E, 0xFB8F, 0xFB90, 0xFB91 /* Eastern arabic letter Keheh */ },
{ /* 40 0x06AF */ 0xFB92, 0xFB93, 0xFB94, 0xFB95 /* Eastern arabic letter Gaf */ },
{ /* 41 0x06CC */ 0xFBFC, 0xFBFD, 0x0000, 0x0000 /* Eastern arabic letter Farsi Yeh */ },
};
/*********************************************************************
*
* _GetTableIndex
*/
static int _GetTableIndex(U16 c) {
if (c < 0x621) {
return 0;
}
if (c > 0x6cc) {
return 0;
}
if ((c >= 0x621) && (c <= 0x63a)) {
return c - 0x621;
}
if ((c >= 0x641) && (c <= 0x64a)) {
return c - 0x641 + 26;
}
if (c == 0x67e) {
return 36;
}
if (c == 0x686) {
return 37;
}
if (c == 0x698) {
return 38;
}
if (c == 0x6a9) {
return 39;
}
if (c == 0x6af) {
return 40;
}
if (c == 0x6cc) {
return 41;
}
return 0;
}
/*********************************************************************
*
* _IsTransparent
*/
static int _IsTransparent(U16 c) {
if (c >= 0x064b) {
return 1;
}
if (c == 0x670) {
return 1;
}
return 0;
}
/*********************************************************************
*
* _GetLigature
*/
static int _GetLigature(U16 Char, U16 Next, int PrevAffectsJoining) {
if (((Next != 0x622) && (Next != 0x623) && (Next != 0x625) && (Next != 0x627)) || (Char != 0x644)) {
return 0;
}
if (PrevAffectsJoining) {
switch (Next) {
case 0x622:
return 0xfef6;
case 0x623:
return 0xfef8;
case 0x625:
return 0xfefa;
case 0x627:
return 0xfefc;
}
} else {
switch (Next) {
case 0x622:
return 0xfef5;
case 0x623:
return 0xfef7;
case 0x625:
return 0xfef9;
case 0x627:
return 0xfefb;
}
}
return 0;
}
/*********************************************************************
*
* _GetStringDistXArabic
*/
static int _GetStringDistXArabic(const char GUI_UNI_PTR *s, int MaxNumChars) {
U16 Glyph, Char, PrevChar = 0, NextChar;
int CharIsArabic, IgnoreNextCharacter = 0, xSizeArabic = 0;
unsigned int i = 0;
while (--MaxNumChars >= 0) {
if (!PrevChar) {
Char = *(i + (U16*)s);
//Char = GUI_UC__GetCharCodeInc(&s);
if (Char) {
NextChar = *(i + 1 + (U16*)s);
//NextChar = GUI_UC__GetCharCodeInc(&s);
}
} else {
Char = NextChar;
if (Char) {
NextChar = *(i + 1 + (U16*)s);
//NextChar = GUI_UC__GetCharCodeInc(&s);
}
}
if (IgnoreNextCharacter) {
IgnoreNextCharacter = 0;
} else {
if (Char != 0x20) {
CharIsArabic = GUI__IsArabicCharacter(Char);
}
if (CharIsArabic) {
Glyph = GUI__GetPresentationForm(Char, NextChar, PrevChar, &IgnoreNextCharacter);
xSizeArabic += GUI_GetCharDistX(Glyph);
} else {
break;
}
}
PrevChar = Char;
i++;
}
return xSizeArabic;
}
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* GUI__GetCursorCharacterArabic
*/
U16 GUI__GetCursorCharacterArabic(const char GUI_UNI_PTR * s, int Index, int MaxNumChars, int * pIsRTL) {
int Ligature = 0, PrevIndex, PrevAffectsJoining;
U16 Prev = 0, Char, Next = 0, Glyph;
if (Index) {
int NumChars = Index;
while (--NumChars) {
s += GUI_UC_GetCharSize(s);
}
Prev = GUI_UC__GetCharCodeInc(&s);
Char = GUI_UC__GetCharCodeInc(&s);
} else {
int NumChars = Index;
while (NumChars--) {
s += GUI_UC_GetCharSize(s);
}
Char = GUI_UC__GetCharCodeInc(&s);
}
if (Index < (MaxNumChars - 1)) {
Next = GUI_UC_GetCharCode(s);
}
PrevIndex = _GetTableIndex(Prev);
PrevAffectsJoining = (_GetTableIndex(Prev) || _IsTransparent(Prev)) && (_aKeyInfo[PrevIndex].Medial);
Ligature = _GetLigature(Prev, Char, PrevAffectsJoining);
if (Ligature) {
*pIsRTL = 1;
return Ligature;
}
Glyph = GUI__GetPresentationForm(Char, Next, Prev, 0);
if (Char != 0x20) {
*pIsRTL = GUI__IsArabicCharacter(Char) ? 1 : 0;
} else {
*pIsRTL = GUI__IsArabicCharacter(Prev) ? 1 : 0;
}
return Glyph;
}
/*********************************************************************
*
* GUI__IsArabicCharacter
*/
int GUI__IsArabicCharacter(U16 c) {
return ((c >= 0x600) && (c <= 0x6ff)) ? 1 : 0;
}
/*********************************************************************
*
* GUI__GetPresentationForm
*/
U16 GUI__GetPresentationForm(U16 Char, U16 Next, U16 Prev, int * pIgnoreNext) {
int CharIndex, PrevIndex, NextAffectsJoining, PrevAffectsJoining, Final, Initial, Medial, Ligature;
CharIndex = _GetTableIndex(Char);
if (!CharIndex) {
return Char;
}
PrevIndex = _GetTableIndex(Prev);
PrevAffectsJoining = (_GetTableIndex(Prev) || _IsTransparent(Prev)) && (_aKeyInfo[PrevIndex].Medial);
Ligature = _GetLigature(Char, Next, PrevAffectsJoining);
if (!Ligature) {
Ligature = _GetLigature(Prev, Char, PrevAffectsJoining);
}
if (Ligature) {
if (pIgnoreNext) {
*pIgnoreNext = 1;
}
return Ligature;
} else {
if (pIgnoreNext) {
*pIgnoreNext = 0;
}
}
NextAffectsJoining = (_GetTableIndex(Next) || _IsTransparent(Next)) && (_aKeyInfo[CharIndex].Medial);
if ((!PrevAffectsJoining) && (!NextAffectsJoining)) {
return _aKeyInfo[CharIndex].Isolated;
} else if ((!PrevAffectsJoining) && (NextAffectsJoining)) {
Initial = _aKeyInfo[CharIndex].Initial;
if (Initial) {
return Initial;
} else {
return _aKeyInfo[CharIndex].Isolated;
}
} else if ((PrevAffectsJoining) && (NextAffectsJoining)) {
Medial = _aKeyInfo[CharIndex].Medial;
if (Medial) {
return Medial;
} else {
return _aKeyInfo[CharIndex].Isolated;
}
} else if ((PrevAffectsJoining) && (!NextAffectsJoining)) {
Final = _aKeyInfo[CharIndex].Final;
if (Final) {
return Final;
} else {
return _aKeyInfo[CharIndex].Isolated;
}
}
return Char;
}
//ONLY for SHAPED algorithm verification
void GUI__ArabicShaped(const U16 * s, int MaxNumChars, U16* r)
{
//
static unsigned short int retText[21] = { 0 };//<<<<<<
//
int j = 0;
U16 Glyph, Char, PrevChar = 0, NextChar;
int CharIsArabic, xPosArabicStart, IgnoreNextCharacter = 0, xSizeArabic;
unsigned int i = 0;
while (--MaxNumChars >= 0)
{
if (!PrevChar)
{
Char = *(i + (U16*)s);
if (Char) {
NextChar = *(i + 1 + (U16*)s);
}
}
else
{
Char = NextChar;
if (Char) {
NextChar = *(i + 1 + (U16*)s);
}
}
if (IgnoreNextCharacter)
{
IgnoreNextCharacter = 0;
}
else
{
if (Char != 0x20)
{
CharIsArabic = GUI__IsArabicCharacter(Char);
}
if (CharIsArabic)
{
Glyph = GUI__GetPresentationForm(Char, NextChar, PrevChar, &IgnoreNextCharacter);
}
else
{
Glyph = Char;
}
retText[j++] = Glyph;
}
PrevChar = Char;
i++;
}
r = retText;
}
#else
//......
#endif
/*************************** End of file ****************************/
编辑程序的时候,如果程序中有阿拉伯语字符串,程序员是不需要所谓的变形和逆序显示的。
用这种功能的编辑器还真的不多。除了可以使用 jEdit 编辑器之外,还可以使用 Sublime Text 编辑器 ,这个2文本编辑器都可以抑制字符串的双向显示功能,让程序员按照字符串固有的逻辑关系移动光标。这可是我反复试用了许多文本编辑工具找到的啊!!