shaping.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Copyright (C) 2003 Mooffie <mooffie@typo.co.il>
  2. //
  3. // This program is free software; you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation; either version 2 of the License, or
  6. // (at your option) any later version.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
  16. #include <config.h>
  17. #include "shaping.h"
  18. #include "bidi.h"
  19. #include "univalues.h"
  20. struct charinfo {
  21. unichar ccode;
  22. char cclass;
  23. unichar isolated;
  24. unichar final;
  25. unichar initial;
  26. unichar medial;
  27. };
  28. static charinfo infos[] = {
  29. { 0x0621, 'U', 0xFE80, 0x0000, 0x0000, 0x0000 },
  30. { 0x0622, 'R', 0xFE81, 0xFE82, 0x0000, 0x0000 },
  31. { 0x0623, 'R', 0xFE83, 0xFE84, 0x0000, 0x0000 },
  32. { 0x0624, 'R', 0xFE85, 0xFE86, 0x0000, 0x0000 },
  33. { 0x0625, 'R', 0xFE87, 0xFE88, 0x0000, 0x0000 },
  34. { 0x0626, 'D', 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C },
  35. { 0x0627, 'R', 0xFE8D, 0xFE8E, 0x0000, 0x0000 },
  36. { 0x0628, 'D', 0xFE8F, 0xFE90, 0xFE91, 0xFE92 },
  37. { 0x0629, 'R', 0xFE93, 0xFE94, 0x0000, 0x0000 },
  38. { 0x062A, 'D', 0xFE95, 0xFE96, 0xFE97, 0xFE98 },
  39. { 0x062B, 'D', 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C },
  40. { 0x062C, 'D', 0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0 },
  41. { 0x062D, 'D', 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4 },
  42. { 0x062E, 'D', 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8 },
  43. { 0x062F, 'R', 0xFEA9, 0xFEAA, 0x0000, 0x0000 },
  44. { 0x0630, 'R', 0xFEAB, 0xFEAC, 0x0000, 0x0000 },
  45. { 0x0631, 'R', 0xFEAD, 0xFEAE, 0x0000, 0x0000 },
  46. { 0x0632, 'R', 0xFEAF, 0xFEB0, 0x0000, 0x0000 },
  47. { 0x0633, 'D', 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4 },
  48. { 0x0634, 'D', 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8 },
  49. { 0x0635, 'D', 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC },
  50. { 0x0636, 'D', 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0 },
  51. { 0x0637, 'D', 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4 },
  52. { 0x0638, 'D', 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8 },
  53. { 0x0639, 'D', 0xFEC9, 0xFECA, 0xFECB, 0xFECC },
  54. { 0x063A, 'D', 0xFECD, 0xFECE, 0xFECF, 0xFED0 },
  55. { 0x063B, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  56. { 0x063C, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  57. { 0x063D, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  58. { 0x063E, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  59. { 0x063F, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  60. { 0x0640, 'D', 0x0640, 0x0640, 0x0640, 0x0640 },
  61. { 0x0641, 'D', 0xFED1, 0xFED2, 0xFED3, 0xFED4 },
  62. { 0x0642, 'D', 0xFED5, 0xFED6, 0xFED7, 0xFED8 },
  63. { 0x0643, 'D', 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC },
  64. { 0x0644, 'D', 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0 },
  65. { 0x0645, 'D', 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4 },
  66. { 0x0646, 'D', 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8 },
  67. { 0x0647, 'D', 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC },
  68. { 0x0648, 'R', 0xFEED, 0xFEEE, 0x0000, 0x0000 },
  69. { 0x0649, 'D', 0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9 },
  70. { 0x064A, 'D', 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4 },
  71. { 0x064B, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  72. { 0x064C, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  73. { 0x064D, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  74. { 0x064E, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  75. { 0x064F, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  76. { 0x0650, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  77. { 0x0651, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  78. { 0x0652, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  79. { 0x0653, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  80. { 0x0654, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  81. { 0x0655, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  82. { 0x0656, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  83. { 0x0657, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  84. { 0x0658, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  85. { 0x0659, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  86. { 0x065A, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  87. { 0x065B, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  88. { 0x065C, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  89. { 0x065D, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  90. { 0x065E, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  91. { 0x065F, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  92. { 0x0660, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  93. { 0x0661, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  94. { 0x0662, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  95. { 0x0663, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  96. { 0x0664, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  97. { 0x0665, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  98. { 0x0666, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  99. { 0x0667, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  100. { 0x0668, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  101. { 0x0669, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  102. { 0x066A, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  103. { 0x066B, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  104. { 0x066C, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  105. { 0x066D, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  106. { 0x066E, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  107. { 0x066F, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  108. { 0x0670, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  109. { 0x0671, 'R', 0xFB50, 0xFB51, 0x0000, 0x0000 },
  110. { 0x0672, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  111. { 0x0673, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  112. { 0x0674, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  113. { 0x0675, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  114. { 0x0676, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  115. { 0x0677, 'R', 0xFBDD, 0xFFFD, 0x0000, 0x0000 },
  116. { 0x0678, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  117. { 0x0679, 'D', 0xFB66, 0xFB67, 0xFB68, 0xFB69 },
  118. { 0x067A, 'D', 0xFB5E, 0xFB5F, 0xFB60, 0xFB61 },
  119. { 0x067B, 'D', 0xFB52, 0xFB53, 0xFB54, 0xFB55 },
  120. { 0x067C, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  121. { 0x067D, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  122. { 0x067E, 'D', 0xFB56, 0xFB57, 0xFB58, 0xFB59 },
  123. { 0x067F, 'D', 0xFB62, 0xFB63, 0xFB64, 0xFB65 },
  124. { 0x0680, 'D', 0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D },
  125. { 0x0681, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  126. { 0x0682, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  127. { 0x0683, 'D', 0xFB76, 0xFB77, 0xFB78, 0xFB79 },
  128. { 0x0684, 'D', 0xFB72, 0xFB73, 0xFB74, 0xFB75 },
  129. { 0x0685, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  130. { 0x0686, 'D', 0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D },
  131. { 0x0687, 'D', 0xFB7E, 0xFB7F, 0xFB80, 0xFB81 },
  132. { 0x0688, 'R', 0xFB88, 0xFB89, 0x0000, 0x0000 },
  133. { 0x0689, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  134. { 0x068A, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  135. { 0x068B, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  136. { 0x068C, 'R', 0xFB84, 0xFB85, 0x0000, 0x0000 },
  137. { 0x068D, 'R', 0xFB82, 0xFB83, 0x0000, 0x0000 },
  138. { 0x068E, 'R', 0xFB86, 0xFB87, 0x0000, 0x0000 },
  139. { 0x068F, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  140. { 0x0690, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  141. { 0x0691, 'R', 0xFB8C, 0xFB8D, 0x0000, 0x0000 },
  142. { 0x0692, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  143. { 0x0693, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  144. { 0x0694, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  145. { 0x0695, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  146. { 0x0696, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  147. { 0x0697, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  148. { 0x0698, 'R', 0xFB8A, 0xFB8B, 0x0000, 0x0000 },
  149. { 0x0699, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  150. { 0x069A, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  151. { 0x069B, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  152. { 0x069C, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  153. { 0x069D, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  154. { 0x069E, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  155. { 0x069F, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  156. { 0x06A0, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  157. { 0x06A1, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  158. { 0x06A2, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  159. { 0x06A3, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  160. { 0x06A4, 'D', 0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D },
  161. { 0x06A5, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  162. { 0x06A6, 'D', 0xFB6E, 0xFB6F, 0xFB70, 0xFB71 },
  163. { 0x06A7, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  164. { 0x06A8, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  165. { 0x06A9, 'D', 0xFB8E, 0xFB8F, 0xFB90, 0xFB91 },
  166. { 0x06AA, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  167. { 0x06AB, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  168. { 0x06AC, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  169. { 0x06AD, 'D', 0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6 },
  170. { 0x06AE, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  171. { 0x06AF, 'D', 0xFB92, 0xFB93, 0xFB94, 0xFB95 },
  172. { 0x06B0, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  173. { 0x06B1, 'D', 0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D },
  174. { 0x06B2, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  175. { 0x06B3, 'D', 0xFB96, 0xFB97, 0xFB98, 0xFB99 },
  176. { 0x06B4, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  177. { 0x06B5, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  178. { 0x06B6, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  179. { 0x06B7, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  180. { 0x06B8, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  181. { 0x06B9, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  182. { 0x06BA, 'D', 0xFB9E, 0xFB9F, 0xFFFD, 0xFFFD },
  183. { 0x06BB, 'D', 0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3 },
  184. { 0x06BC, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  185. { 0x06BD, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  186. { 0x06BE, 'D', 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD },
  187. { 0x06BF, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  188. { 0x06C0, 'R', 0xFBA4, 0xFBA5, 0x0000, 0x0000 },
  189. { 0x06C1, 'D', 0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9 },
  190. { 0x06C2, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  191. { 0x06C3, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  192. { 0x06C4, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  193. { 0x06C5, 'R', 0xFBE0, 0xFBE1, 0x0000, 0x0000 },
  194. { 0x06C6, 'R', 0xFBD9, 0xFBDA, 0x0000, 0x0000 },
  195. { 0x06C7, 'R', 0xFBD7, 0xFBD8, 0x0000, 0x0000 },
  196. { 0x06C8, 'R', 0xFBDB, 0xFBDC, 0x0000, 0x0000 },
  197. { 0x06C9, 'R', 0xFBE2, 0xFBE3, 0x0000, 0x0000 },
  198. { 0x06CA, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  199. { 0x06CB, 'R', 0xFBDE, 0xFBDF, 0x0000, 0x0000 },
  200. { 0x06CC, 'D', 0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF },
  201. { 0x06CD, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  202. { 0x06CE, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  203. { 0x06CF, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  204. { 0x06D0, 'D', 0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7 },
  205. { 0x06D1, 'X', 0x0000, 0x0000, 0x0000, 0x0000 },
  206. { 0x06D2, 'R', 0xFBAE, 0xFBAF, 0x0000, 0x0000 },
  207. { 0x06D3, 'R', 0xFBB0, 0xFBB1, 0x0000, 0x0000 }
  208. };
  209. #define TBLMIN 0x0621
  210. #define TBLMAX 0x06D3
  211. static inline bool is_d(unichar ch) {
  212. if (ch >= TBLMIN && ch <= TBLMAX) {
  213. return (infos[ch - TBLMIN].cclass == 'D');
  214. }
  215. return false;
  216. }
  217. static inline bool is_r(unichar ch) {
  218. if (ch >= TBLMIN && ch <= TBLMAX) {
  219. return (infos[ch - TBLMIN].cclass == 'R');
  220. }
  221. return false;
  222. }
  223. static inline bool is_rjc(unichar ch) {
  224. if (ch == UNI_ZWJ)
  225. return true;
  226. if (ch >= TBLMIN && ch <= TBLMAX) {
  227. return (infos[ch - TBLMIN].cclass == 'D');
  228. }
  229. return false;
  230. }
  231. static inline bool is_ljc(unichar ch) {
  232. if (ch == UNI_ZWJ)
  233. return true;
  234. if (ch >= TBLMIN && ch <= TBLMAX) {
  235. return (infos[ch - TBLMIN].cclass == 'D'
  236. || infos[ch - TBLMIN].cclass == 'R');
  237. }
  238. return false;
  239. }
  240. static inline charinfo *get_info(unichar ch) {
  241. if (ch >= TBLMIN && ch <= TBLMAX) {
  242. return &infos[ch - TBLMIN];
  243. }
  244. return NULL;
  245. }
  246. bool is_shaping_transparent(unichar ch) {
  247. return BiDi::is_nsm(ch);
  248. }
  249. // shape() - this is a temporary and a very inefficient implementation
  250. // of Arabic joining described in section 8.2 of the Unicode standard.
  251. //
  252. // :TODO: optimize.
  253. int shape(unichar *s, int len, attribute_t *attributes)
  254. {
  255. if (!len)
  256. return len;
  257. unichar a = 0, b = 0, c = 0;
  258. for (int i = len - 1; i >= 0; i--) {
  259. b = s[i];
  260. unichar &chref = s[i];
  261. c = 0;
  262. while (i > 0 && is_shaping_transparent(s[i-1]))
  263. i--;
  264. if (i > 0)
  265. c = s[i-1];
  266. if (is_r(b)) {
  267. if (is_rjc(a)) {
  268. chref = get_info(b)->final;
  269. }
  270. } else if (is_d(b)) {
  271. if (is_rjc(a) && is_ljc(c)) {
  272. chref = get_info(b)->medial;
  273. } else if (is_rjc(a) && !is_ljc(c)) {
  274. chref = get_info(b)->final;
  275. } else if (!is_rjc(a) && is_ljc(c)) {
  276. chref = get_info(b)->initial;
  277. }
  278. }
  279. a = b;
  280. }
  281. return ligate(s, len, attributes);
  282. }
  283. // ligate() - do LAM-ALEF ligatures. returns the new length of the string.
  284. int ligate(unichar *s, int len, attribute_t *attributes)
  285. {
  286. #define LAM_L 0xFEDF
  287. #define LAM_M 0xFEE0
  288. #define ALEF_MADDA_R 0xFE82
  289. #define ALEF_HAMZA_ABOVE_R 0xFE84
  290. #define ALEF_HAMZA_BELOW_R 0xFE88
  291. #define ALEF_R 0xFE8E
  292. #define LAMALEF_MADDA_I 0xFEF5
  293. #define LAMALEF_MADDA_R 0xFEF6
  294. #define LAMALEF_HAMZA_ABOVE_I 0xFEF7
  295. #define LAMALEF_HAMZA_ABOVE_R 0xFEF8
  296. #define LAMALEF_HAMZA_BELOW_I 0xFEF9
  297. #define LAMALEF_HAMZA_BELOW_R 0xFEFA
  298. #define LAMALEF_I 0xFEFB
  299. #define LAMALEF_R 0xFEFC
  300. int new_len = len;
  301. bool may_start = false;
  302. int lig_start = 0; // silence the compiler
  303. for (int i = len - 1; i >= 0; i--) {
  304. if (i > 0 && (s[i] == LAM_L || s[i] == LAM_M)) {
  305. lig_start = i;
  306. may_start = true;
  307. }
  308. else if (may_start) {
  309. if (s[i] == ALEF_MADDA_R ||
  310. s[i] == ALEF_HAMZA_ABOVE_R ||
  311. s[i] == ALEF_HAMZA_BELOW_R ||
  312. s[i] == ALEF_R)
  313. {
  314. int rlig = (s[lig_start] == LAM_M) ? 1 : 0;
  315. switch (s[i]) {
  316. case ALEF_MADDA_R:
  317. s[i] = LAMALEF_MADDA_I + rlig; break;
  318. case ALEF_HAMZA_ABOVE_R:
  319. s[i] = LAMALEF_HAMZA_ABOVE_I + rlig; break;
  320. case ALEF_HAMZA_BELOW_R:
  321. s[i] = LAMALEF_HAMZA_BELOW_I + rlig; break;
  322. case ALEF_R:
  323. s[i] = LAMALEF_I + rlig; break;
  324. }
  325. for (int j = lig_start; j < new_len - 1; j++)
  326. s[j] = s[j+1];
  327. if (attributes) {
  328. for (int j = lig_start; j < new_len - 1; j++)
  329. attributes[j] = attributes[j+1];
  330. }
  331. new_len--; // we deleted a LAM
  332. } else {
  333. if (!is_shaping_transparent(s[i]))
  334. may_start = false;
  335. }
  336. }
  337. }
  338. return new_len;
  339. }