]> granicus.if.org Git - icu/commitdiff
ICU-10670 Fix character-based Arabic shaping for Urdu & some other characters
authorMarkus Scherer <markus.icu@gmail.com>
Wed, 26 Feb 2014 00:02:24 +0000 (00:02 +0000)
committerMarkus Scherer <markus.icu@gmail.com>
Wed, 26 Feb 2014 00:02:24 +0000 (00:02 +0000)
X-SVN-Rev: 35233

icu4c/source/common/ushape.cpp
icu4c/source/test/cintltst/cbiditst.c

index 924a43a98f2cfeba48aed552f01f45d1649a991b..1799b63e6d8d6b76aa75dbd9fc1529a8071b1332 100644 (file)
@@ -1,7 +1,7 @@
 /*
  ******************************************************************************
  *
- *   Copyright (C) 2000-2013, International Business Machines
+ *   Copyright (C) 2000-2014, International Business Machines
  *   Corporation and others.  All Rights Reserved.
  *
  ******************************************************************************
@@ -212,10 +212,20 @@ static const UChar araLink[178]=
   0,                            /*0x0674*/
   1            + 32,            /*0x0675*/
   1, 1,                         /*0x0676-0x0677*/
-  1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x0678-0x067D*/
+  1 + 2,                        /*0x0678*/
+  1 + 2 + 8        + 256 * 0x16,/*0x0679*/
+  1 + 2 + 8        + 256 * 0x0E,/*0x067A*/
+  1 + 2 + 8        + 256 * 0x02,/*0x067B*/
+  1+2, 1+2,                     /*0x67C-0x067D*/
   1+2+8+256 * 0x06, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x067E-0x0683*/
   1+2, 1+2, 1+2+8+256 * 0x2A, 1+2,           /*0x0684-0x0687*/
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*0x0688-0x0691*/
+  1     + 8        + 256 * 0x38,/*0x0688*/
+  1, 1, 1,                      /*0x0689-0x068B*/
+  1     + 8        + 256 * 0x34,/*0x068C*/
+  1     + 8        + 256 * 0x32,/*0x068D*/
+  1     + 8        + 256 * 0x36,/*0x068E*/
+  1, 1,                         /*0x068F-0x0690*/
+  1     + 8        + 256 * 0x3C,/*0x0691*/
   1, 1, 1, 1, 1, 1, 1+8+256 * 0x3A, 1,       /*0x0692-0x0699*/
   1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x069A-0x06A3*/
   1+2, 1+2, 1+2, 1+2,           /*0x069A-0x06A3*/
@@ -223,15 +233,29 @@ static const UChar araLink[178]=
   1+2, 1+2, 1+2, 1+2,           /*0x06A4-0x06AD*/
   1+2, 1+2+8+256 * 0x42, 1+2, 1+2, 1+2, 1+2, /*0x06AE-0x06B7*/
   1+2, 1+2, 1+2, 1+2,           /*0x06AE-0x06B7*/
-  1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x06B8-0x06BF*/
-  1+2, 1+2,                     /*0x06B8-0x06BF*/
-  1,                            /*0x06C0*/
-  1+2,                          /*0x06C1*/
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*0x06C2-0x06CB*/
-  1+2+8+256 * 0xAC,             /*0x06CC*/
+  1+2, 1+2,                     /*0x06B8-0x06B9*/
+  1     + 8        + 256 * 0x4E,/*0x06BA*/
+  1 + 2 + 8        + 256 * 0x50,/*0x06BB*/
+  1+2, 1+2,                     /*0x06BC-0x06BD*/
+  1 + 2 + 8        + 256 * 0x5A,/*0x06BE*/
+  1+2,                          /*0x06BF*/
+  1     + 8        + 256 * 0x54,/*0x06C0*/
+  1 + 2 + 8        + 256 * 0x56,/*0x06C1*/
+  1, 1, 1,                      /*0x06C2-0x06C4*/
+  1     + 8        + 256 * 0x90,/*0x06C5*/
+  1     + 8        + 256 * 0x89,/*0x06C6*/
+  1     + 8        + 256 * 0x87,/*0x06C7*/
+  1     + 8        + 256 * 0x8B,/*0x06C8*/
+  1     + 8        + 256 * 0x92,/*0x06C9*/
+  1,                            /*0x06CA*/
+  1     + 8        + 256 * 0x8E,/*0x06CB*/
+  1 + 2 + 8        + 256 * 0xAC,/*0x06CC*/
   1,                            /*0x06CD*/
-  1+2, 1+2, 1+2, 1+2,           /*0x06CE-0x06D1*/
-  1, 1                          /*0x06D2-0x06D3*/
+  1+2, 1+2,                     /*0x06CE-0x06CF*/
+  1 + 2 + 8        + 256 * 0x94,/*0x06D0*/
+  1+2,                          /*0x06D1*/
+  1     + 8        + 256 * 0x5E,/*0x06D2*/
+  1     + 8        + 256 * 0x60 /*0x06D3*/
 };
 
 static const uint8_t presALink[] = {
@@ -273,16 +297,16 @@ static const uint8_t presBLink[]=
 static const UChar convertFBto06[] =
 {
 /***********0******1******2******3******4******5******6******7******8******9******A******B******C******D******E******F***/
-/*FB5*/   0x671, 0x671,     0,     0,     0,     0, 0x67E, 0x67E, 0x67E, 0x67E,     0,     0,     0,     0,     0,     0,
-/*FB6*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+/*FB5*/   0x671, 0x671, 0x67B, 0x67B, 0x67B, 0x67B, 0x67E, 0x67E, 0x67E, 0x67E,     0,     0,     0,     0, 0x67A, 0x67A,
+/*FB6*/   0x67A, 0x67A,     0,     0,     0,     0, 0x679, 0x679, 0x679, 0x679,     0,     0,     0,     0,     0,     0,
 /*FB7*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0, 0x686, 0x686, 0x686, 0x686,     0,     0,
-/*FB8*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0, 0x698, 0x698,     0,     0, 0x6A9, 0x6A9,
-/*FB9*/   0x6A9, 0x6A9, 0x6AF, 0x6AF, 0x6AF, 0x6AF,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-/*FBA*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-/*FBB*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+/*FB8*/       0,     0, 0x68D, 0x68D, 0x68C, 0x68C, 0x68E, 0x68E, 0x688, 0x688, 0x698, 0x698, 0x691, 0x691, 0x6A9, 0x6A9,
+/*FB9*/   0x6A9, 0x6A9, 0x6AF, 0x6AF, 0x6AF, 0x6AF,     0,     0,     0,     0,     0,     0,     0,     0, 0x6BA, 0x6BA,
+/*FBA*/   0x6BB, 0x6BB, 0x6BB, 0x6BB, 0x6C0, 0x6C0, 0x6C1, 0x6C1, 0x6C1, 0x6C1, 0x6BE, 0x6BE, 0x6BE, 0x6BE, 0x6d2, 0x6D2,
+/*FBB*/   0x6D3, 0x6D3,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
 /*FBC*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-/*FBD*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-/*FBE*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+/*FBD*/       0,     0,     0,     0,     0,     0,     0, 0x6C7, 0x6C7, 0x6C6, 0x6C6, 0x6C8, 0x6C8,     0, 0x6CB, 0x6CB,
+/*FBE*/   0x6C5, 0x6C5, 0x6C9, 0x6C9, 0x6D0, 0x6D0, 0x6D0, 0x6D0,     0,     0,     0,     0,     0,     0,     0,     0,
 /*FBF*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0, 0x6CC, 0x6CC, 0x6CC, 0x6CC
 };
 
index 30bca7af37524299a27560c0ddf74bcf3304e887..692bbcb8954fa659b2f0082b34e449104cbdc84b 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT:
- * Copyright (c) 1997-2013, International Business Machines Corporation and
+ * Copyright (c) 1997-2014, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 /*   file name:  cbiditst.c
@@ -70,6 +70,10 @@ static void doArabicShapingTestForBug8703(void);
 
 static void doArabicShapingTestForBug9024(void);
 
+static void _testPresentationForms(const UChar *in);
+
+static void doArabicShapingTestForNewCharacters(void);
+
 static void testReorder(void);
 
 static void testReorderArabicMathSymbols(void);
@@ -140,6 +144,7 @@ addComplexTest(TestNode** root) {
     addTest(root, doArabicShapingTestForBug8703, "complex/arabic-shaping/bug-8703");
     addTest(root, testReorderArabicMathSymbols, "complex/bidi/bug-9024");
     addTest(root, doArabicShapingTestForBug9024, "complex/arabic-shaping/bug-9024");
+    addTest(root, doArabicShapingTestForNewCharacters, "complex/arabic-shaping/shaping2");
 }
 
 static void
@@ -3313,6 +3318,244 @@ doArabicShapingTestForBug9024(void) {
 
 }
 
+static void _testPresentationForms(const UChar* in) {
+  enum Forms { GENERIC, ISOLATED, FINAL, INITIAL, MEDIAL };
+  /* This character is used to check whether the in-character is rewritten correctly
+     and whether the surrounding characters are shaped correctly as well. */
+  UChar otherChar[] = {0x0628, 0xfe8f, 0xfe90, 0xfe91, 0xfe92};
+  UChar src[3];
+  UChar dst[3];
+  UErrorCode errorCode;
+  int32_t length;
+
+  /* Testing isolated shaping */
+  src[0] = in[GENERIC];
+  errorCode=U_ZERO_ERROR;
+  length=u_shapeArabic(src, 1,
+                       dst, 1,
+                       U_SHAPE_LETTERS_SHAPE,
+                       &errorCode);
+  if(U_FAILURE(errorCode) || length!=1 || dst[0] != in[ISOLATED]) {
+      log_err("failure in u_shapeArabic(_testAllForms: shaping isolated): %x\n", in[GENERIC]);
+  }
+  errorCode=U_ZERO_ERROR;
+  length=u_shapeArabic(dst, 1,
+                       src, 1,
+                       U_SHAPE_LETTERS_UNSHAPE,
+                       &errorCode);
+  if(U_FAILURE(errorCode) || length!=1 || src[0] != in[GENERIC]) {
+      log_err("failure in u_shapeArabic(_testAllForms: unshaping isolated): %x\n", in[GENERIC]);
+  }
+
+  /* Testing final shaping */
+  src[0] = otherChar[GENERIC];
+  src[1] = in[GENERIC];
+  if (in[FINAL] != 0) {
+  errorCode=U_ZERO_ERROR;
+  length=u_shapeArabic(src, 2,
+                       dst, 2,
+                       U_SHAPE_LETTERS_SHAPE,
+                       &errorCode);
+  if(U_FAILURE(errorCode) || length!=2 || dst[0] != otherChar[INITIAL] || dst[1] != in[FINAL]) {
+      log_err("failure in u_shapeArabic(_testAllForms: shaping final): %x\n", in[GENERIC]);
+  }
+  errorCode=U_ZERO_ERROR;
+  length=u_shapeArabic(dst, 2,
+                       src, 2,
+                       U_SHAPE_LETTERS_UNSHAPE,
+                       &errorCode);
+  if(U_FAILURE(errorCode) || length!=2 || src[0] != otherChar[GENERIC] || src[1] != in[GENERIC]) {
+      log_err("failure in u_shapeArabic(_testAllForms: unshaping final): %x\n", in[GENERIC]);
+  }
+  } else {
+    errorCode=U_ZERO_ERROR;
+    length=u_shapeArabic(src, 2,
+                         dst, 2,
+                         U_SHAPE_LETTERS_SHAPE,
+                         &errorCode);
+    if(U_FAILURE(errorCode) || length!=2 || dst[0] != otherChar[ISOLATED] || dst[1] != in[ISOLATED]) {
+      log_err("failure in u_shapeArabic(_testAllForms: shaping final): %x\n", in[GENERIC]);
+    }
+    errorCode=U_ZERO_ERROR;
+    length=u_shapeArabic(dst, 2,
+                         src, 2,
+                         U_SHAPE_LETTERS_UNSHAPE,
+                         &errorCode);
+    if(U_FAILURE(errorCode) || length!=2 || src[0] != otherChar[GENERIC] || src[1] != in[GENERIC]) {
+      log_err("failure in u_shapeArabic(_testAllForms: unshaping final): %x\n", in[GENERIC]);
+    }
+  }
+
+  /* Testing initial shaping */
+  src[0] = in[GENERIC];
+  src[1] = otherChar[GENERIC];
+  if (in[INITIAL] != 0) {
+    /* Testing characters that have an initial form */
+    errorCode=U_ZERO_ERROR;
+    length=u_shapeArabic(src, 2,
+                         dst, 2,
+                         U_SHAPE_LETTERS_SHAPE,
+                         &errorCode);
+    if(U_FAILURE(errorCode) || length!=2 || dst[0] != in[INITIAL] || dst[1] != otherChar[FINAL]) {
+      log_err("failure in u_shapeArabic(_testAllForms: shaping initial): %x\n", in[GENERIC]);
+    }
+    errorCode=U_ZERO_ERROR;
+    length=u_shapeArabic(dst, 2,
+                         src, 2,
+                         U_SHAPE_LETTERS_UNSHAPE,
+                         &errorCode);
+    if(U_FAILURE(errorCode) || length!=2 || src[0] != in[GENERIC] || src[1] != otherChar[GENERIC]) {
+      log_err("failure in u_shapeArabic(_testAllForms: unshaping initial): %x\n", in[GENERIC]);
+    }
+  } else {
+    /* Testing characters that do not have an initial form */
+    errorCode=U_ZERO_ERROR;
+    length=u_shapeArabic(src, 2,
+                         dst, 2,
+                         U_SHAPE_LETTERS_SHAPE,
+                         &errorCode);
+    if(U_FAILURE(errorCode) || length!=2 || dst[0] != in[ISOLATED] || dst[1] != otherChar[ISOLATED]) {
+      log_err("failure in u_shapeArabic(_testTwoForms: shaping initial): %x\n", in[GENERIC]);
+    }
+    errorCode=U_ZERO_ERROR;
+    length=u_shapeArabic(dst, 2,
+                         src, 2,
+                         U_SHAPE_LETTERS_UNSHAPE,
+                         &errorCode);
+    if(U_FAILURE(errorCode) || length!=2 || src[0] != in[GENERIC] || src[1] != otherChar[GENERIC]) {
+      log_err("failure in u_shapeArabic(_testTwoForms: unshaping initial): %x\n", in[GENERIC]);
+    }
+  }
+
+  /* Testing medial shaping */
+  src[0] = otherChar[0];
+  src[1] = in[GENERIC];
+  src[2] = otherChar[0];
+  errorCode=U_ZERO_ERROR;
+  if (in[MEDIAL] != 0) {
+    /* Testing characters that have an medial form */
+    length=u_shapeArabic(src, 3,
+                         dst, 3,
+                         U_SHAPE_LETTERS_SHAPE,
+                         &errorCode);
+    if(U_FAILURE(errorCode) || length!=3 || dst[0] != otherChar[INITIAL] || dst[1] != in[MEDIAL] || dst[2] != otherChar[FINAL]) {
+      log_err("failure in u_shapeArabic(_testAllForms: shaping medial): %x\n", in[GENERIC]);
+    }
+    errorCode=U_ZERO_ERROR;
+    length=u_shapeArabic(dst, 3,
+                         src, 3,
+                         U_SHAPE_LETTERS_UNSHAPE,
+                         &errorCode);
+    if(U_FAILURE(errorCode) || length!=3 || src[0] != otherChar[GENERIC] || src[1] != in[GENERIC] || src[2] != otherChar[GENERIC]) {
+      log_err("failure in u_shapeArabic(_testAllForms: unshaping medial): %x\n", in[GENERIC]);
+    }
+  } else {
+    /* Testing characters that do not have an medial form */
+    errorCode=U_ZERO_ERROR;
+    length=u_shapeArabic(src, 3,
+                         dst, 3,
+                         U_SHAPE_LETTERS_SHAPE,
+                         &errorCode);
+    if(U_FAILURE(errorCode) || length!=3 || dst[0] != otherChar[INITIAL] || dst[1] != in[FINAL] || dst[2] != otherChar[ISOLATED]) {
+      log_err("failure in u_shapeArabic(_testTwoForms: shaping medial): %x\n", in[GENERIC]);
+    }
+    errorCode=U_ZERO_ERROR;
+    length=u_shapeArabic(dst, 3,
+                         src, 3,
+                         U_SHAPE_LETTERS_UNSHAPE,
+                         &errorCode);
+    if(U_FAILURE(errorCode) || length!=3 || src[0] != otherChar[GENERIC] || src[1] != in[GENERIC] || src[2] != otherChar[GENERIC]) {
+      log_err("failure in u_shapeArabic(_testTwoForms: unshaping medial): %x\n", in[GENERIC]);
+    }
+  }
+}
+
+static void
+doArabicShapingTestForNewCharacters(void) {
+  static const UChar letterForms[][5]={
+    { 0x0679, 0xFB66, 0xFB67, 0xFB68, 0xFB69 },  /* TTEH */
+    { 0x067A, 0xFB5E, 0xFB5F, 0xFB60, 0xFB61 },  /* TTEHEH */
+    { 0x067B, 0xFB52, 0xFB53, 0xFB54, 0xFB55 },  /* BEEH */
+    { 0x0688, 0xFB88, 0xFB89, 0, 0 },            /* DDAL */
+    { 0x068C, 0xFB84, 0xFB85, 0, 0 },            /* DAHAL */
+    { 0x068D, 0xFB82, 0xFB83, 0, 0 },            /* DDAHAL */
+    { 0x068E, 0xFB86, 0xFB87, 0, 0 },            /* DUL */
+    { 0x0691, 0xFB8C, 0xFB8D, 0, 0 },            /* RREH */
+    { 0x06BA, 0xFB9E, 0xFB9F, 0, 0 },            /* NOON GHUNNA */
+    { 0x06BB, 0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3 },  /* RNOON */
+    { 0x06BE, 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD },  /* HEH DOACHASHMEE */
+    { 0x06C0, 0xFBA4, 0xFBA5, 0, 0 },            /* HEH WITH YEH ABOVE */
+    { 0x06C1, 0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9 },  /* HEH GOAL */
+    { 0x06C5, 0xFBE0, 0xFBE1, 0, 0 },            /* KIRGIHIZ OE */
+    { 0x06C6, 0xFBD9, 0xFBDA, 0, 0 },            /* OE */
+    { 0x06C7, 0xFBD7, 0xFBD8, 0, 0 },            /* U */
+    { 0x06C8, 0xFBDB, 0xFBDC, 0, 0 },            /* YU */
+    { 0x06C9, 0xFBE2, 0xFBE3, 0, 0 },            /* KIRGIZ YU */
+    { 0x06CB, 0xFBDE, 0xFBDF, 0, 0},             /* VE */
+    { 0x06D0, 0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7 },  /* E */
+    { 0x06D2, 0xFBAE, 0xFBAF, 0, 0 },            /* YEH BARREE */
+    { 0x06D3, 0xFBB0, 0xFBB1, 0, 0 },            /* YEH BARREE WITH HAMZA ABOVE */
+    { 0x0622, 0xFE81, 0xFE82, 0, 0, },           /* ALEF WITH MADDA ABOVE */
+    { 0x0623, 0xFE83, 0xFE84, 0, 0, },           /* ALEF WITH HAMZA ABOVE */
+    { 0x0624, 0xFE85, 0xFE86, 0, 0, },           /* WAW WITH HAMZA ABOVE */
+    { 0x0625, 0xFE87, 0xFE88, 0, 0, },           /* ALEF WITH HAMZA BELOW */
+    { 0x0626, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, }, /* YEH WITH HAMZA ABOVE */
+    { 0x0627, 0xFE8D, 0xFE8E, 0, 0, },           /* ALEF */
+    { 0x0628, 0xFE8F, 0xFE90, 0xFE91, 0xFE92, }, /* BEH */
+    { 0x0629, 0xFE93, 0xFE94, 0, 0, },           /* TEH MARBUTA */
+    { 0x062A, 0xFE95, 0xFE96, 0xFE97, 0xFE98, }, /* TEH */
+    { 0x062B, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, }, /* THEH */
+    { 0x062C, 0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0, }, /* JEEM */
+    { 0x062D, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, }, /* HAH */
+    { 0x062E, 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8, }, /* KHAH */
+    { 0x062F, 0xFEA9, 0xFEAA, 0, 0, },           /* DAL */
+    { 0x0630, 0xFEAB, 0xFEAC, 0, 0, },           /* THAL */
+    { 0x0631, 0xFEAD, 0xFEAE, 0, 0, },           /* REH */
+    { 0x0632, 0xFEAF, 0xFEB0, 0, 0, },           /* ZAIN */
+    { 0x0633, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, }, /* SEEN */
+    { 0x0634, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8, }, /* SHEEN */
+    { 0x0635, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, }, /* SAD */
+    { 0x0636, 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0, }, /* DAD */
+    { 0x0637, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, }, /* TAH */
+    { 0x0638, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8, }, /* ZAH */
+    { 0x0639, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, }, /* AIN */
+    { 0x063A, 0xFECD, 0xFECE, 0xFECF, 0xFED0, }, /* GHAIN */
+    { 0x0641, 0xFED1, 0xFED2, 0xFED3, 0xFED4, }, /* FEH */
+    { 0x0642, 0xFED5, 0xFED6, 0xFED7, 0xFED8, }, /* QAF */
+    { 0x0643, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, }, /* KAF */
+    { 0x0644, 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0, }, /* LAM */
+    { 0x0645, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, }, /* MEEM */
+    { 0x0646, 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8, }, /* NOON */
+    { 0x0647, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, }, /* HEH */
+    { 0x0648, 0xFEED, 0xFEEE, 0, 0, },           /* WAW */
+    { 0x0649, 0xFEEF, 0xFEF0, 0, 0, },           /* ALEF MAKSURA */
+    { 0x064A, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, }, /* YEH */
+    { 0x064E, 0xFE76, 0, 0, 0xFE77, },           /* FATHA */
+    { 0x064F, 0xFE78, 0, 0, 0xFE79, },           /* DAMMA */
+    { 0x0650, 0xFE7A, 0, 0, 0xFE7B, },           /* KASRA */
+    { 0x0651, 0xFE7C, 0, 0, 0xFE7D, },           /* SHADDA */
+    { 0x0652, 0xFE7E, 0, 0, 0xFE7F, },           /* SUKUN */
+    { 0x0679, 0xFB66, 0xFB67, 0xFB68, 0xFB69, }, /* TTEH */
+    { 0x067E, 0xFB56, 0xFB57, 0xFB58, 0xFB59, }, /* PEH */
+    { 0x0686, 0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D, }, /* TCHEH */
+    { 0x0688, 0xFB88, 0xFB89, 0, 0, },           /* DDAL */
+    { 0x0691, 0xFB8C, 0xFB8D, 0, 0, },           /* RREH */
+    { 0x0698, 0xFB8A, 0xFB8B, 0, 0, },           /* JEH */
+    { 0x06A9, 0xFB8E, 0xFB8F, 0xFB90, 0xFB91, }, /* KEHEH */
+    { 0x06AF, 0xFB92, 0xFB93, 0xFB94, 0xFB95, }, /* GAF */
+    { 0x06BA, 0xFB9E, 0xFB9F, 0, 0, },           /* NOON GHUNNA */
+    { 0x06BE, 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD, }, /* HEH DOACHASHMEE */
+    { 0x06C0, 0xFBA4, 0xFBA5, 0, 0, },           /* HEH WITH YEH ABOVE */
+    { 0x06C1, 0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9, }, /* HEH GOAL */
+    { 0x06CC, 0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF, }, /* FARSI YEH */
+    { 0x06D2, 0xFBAE, 0xFBAF, 0, 0, },           /* YEH BARREE */
+    { 0x06D3, 0xFBB0, 0xFBB1, 0, 0, }};          /* YEH BARREE WITH HAMZA ABOVE */
+
+  for (int i = 0; i < LENGTHOF(letterForms); ++i) {
+    _testPresentationForms(letterForms[i]);
+  }
+}
+
 /* helpers ------------------------------------------------------------------ */
 
 static void initCharFromDirProps(void) {