阿拉伯字母变形表

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文本编辑器都可以抑制字符串的双向显示功能,让程序员按照字符串固有的逻辑关系移动光标。这可是我反复试用了许多文本编辑工具找到的啊!!

 

posted on 2021-12-11 13:14  johnphan  阅读(4668)  评论(0编辑  收藏  举报

导航