/src/ftk_text_layout_bidi.c

http://ftk.googlecode.com/ · C · 992 lines · 778 code · 110 blank · 104 comment · 158 complexity · f7ce9dd4369cf4159ea55b6ef4f8f06c MD5 · raw file

  1. /*
  2. * File: ftk_text_layout_bidi.c
  3. *
  4. * Author: Li XianJing <xianjimli@hotmail.com>
  5. * Brief: interface for text layout(bidi,line break,shape join).
  6. *
  7. * Copyright (c) 2009 - 2010 Li XianJing <xianjimli@hotmail.com>
  8. *
  9. * Licensed under the Academic Free License version 2.1
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24. */
  25. /*
  26. * History:
  27. * ================================================================
  28. * 2010-07-18 Li XianJing <xianjimli@hotmail.com> created
  29. *
  30. */
  31. /*
  32. * XXX: Part of the code in this file come from microwindow, the author has its copyright.
  33. */
  34. /*
  35. * Copyright (c) 2000, 2002, 2003, 2005 Greg Haerr <greg@censoft.com>
  36. * Portions Copyright (c) 2002 by Koninklijke Philips Electronics N.V.
  37. */
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include "ftk_text_layout.h"
  42. /**
  43. * UTF-8 to UTF-16 conversion. Surrogates are handeled properly, e.g.
  44. * a single 4-byte UTF-8 character is encoded into a surrogate pair.
  45. * On the other hand, if the UTF-8 string contains surrogate values, this
  46. * is considered an error and returned as such.
  47. *
  48. * The destination array must be able to hold as many Unicode-16 characters
  49. * as there are ASCII characters in the UTF-8 string. This in case all UTF-8
  50. * characters are ASCII characters. No more will be needed.
  51. *
  52. * This function will also accept Java's variant of UTF-8. This encodes
  53. * U+0000 as two characters rather than one, so the UTF-8 does not contain
  54. * any zeroes.
  55. *
  56. * @author Copyright (c) 2000 Morten Rolland, Screen Media
  57. *
  58. * @param utf8 Input string in UTF8 format.
  59. * @param cc Number of bytes to convert.
  60. * @param unicode16 Destination buffer.
  61. * @return Number of characters converted, or -1 if input is not
  62. * valid UTF8.
  63. */
  64. static int
  65. utf8_to_utf16(const unsigned char *utf8, int cc, unsigned short *unicode16)
  66. {
  67. int count = 0;
  68. unsigned char c0, c1;
  69. unsigned long scalar;
  70. while(--cc >= 0) {
  71. c0 = *utf8++;
  72. /*DPRINTF("Trying: %02x\n",c0);*/
  73. if ( c0 < 0x80 ) {
  74. /* Plain ASCII character, simple translation :-) */
  75. *unicode16++ = c0;
  76. count++;
  77. continue;
  78. }
  79. if ( (c0 & 0xc0) == 0x80 )
  80. /* Illegal; starts with 10xxxxxx */
  81. return -1;
  82. /* c0 must be 11xxxxxx if we get here => at least 2 bytes */
  83. scalar = c0;
  84. if(--cc < 0)
  85. return -1;
  86. c1 = *utf8++;
  87. /*DPRINTF("c1=%02x\n",c1);*/
  88. if ( (c1 & 0xc0) != 0x80 )
  89. /* Bad byte */
  90. return -1;
  91. scalar <<= 6;
  92. scalar |= (c1 & 0x3f);
  93. if ( !(c0 & 0x20) ) {
  94. /* Two bytes UTF-8 */
  95. if ( (scalar != 0) && (scalar < 0x80) )
  96. return -1; /* Overlong encoding */
  97. *unicode16++ = scalar & 0x7ff;
  98. count++;
  99. continue;
  100. }
  101. /* c0 must be 111xxxxx if we get here => at least 3 bytes */
  102. if(--cc < 0)
  103. return -1;
  104. c1 = *utf8++;
  105. /*DPRINTF("c1=%02x\n",c1);*/
  106. if ( (c1 & 0xc0) != 0x80 )
  107. /* Bad byte */
  108. return -1;
  109. scalar <<= 6;
  110. scalar |= (c1 & 0x3f);
  111. if ( !(c0 & 0x10) ) {
  112. /*DPRINTF("####\n");*/
  113. /* Three bytes UTF-8 */
  114. if ( scalar < 0x800 )
  115. return -1; /* Overlong encoding */
  116. if ( scalar >= 0xd800 && scalar < 0xe000 )
  117. return -1; /* UTF-16 high/low halfs */
  118. *unicode16++ = scalar & 0xffff;
  119. count++;
  120. continue;
  121. }
  122. /* c0 must be 1111xxxx if we get here => at least 4 bytes */
  123. c1 = *utf8++;
  124. if(--cc < 0)
  125. return -1;
  126. /*DPRINTF("c1=%02x\n",c1);*/
  127. if ( (c1 & 0xc0) != 0x80 )
  128. /* Bad byte */
  129. return -1;
  130. scalar <<= 6;
  131. scalar |= (c1 & 0x3f);
  132. if ( !(c0 & 0x08) ) {
  133. /* Four bytes UTF-8, needs encoding as surrogates */
  134. if ( scalar < 0x10000 )
  135. return -1; /* Overlong encoding */
  136. scalar -= 0x10000;
  137. *unicode16++ = ((scalar >> 10) & 0x3ff) + 0xd800;
  138. *unicode16++ = (scalar & 0x3ff) + 0xdc00;
  139. count += 2;
  140. continue;
  141. }
  142. return -1; /* No support for more than four byte UTF-8 */
  143. }
  144. return count;
  145. }
  146. /*
  147. * warning: the length of output string may exceed six x the length of the input
  148. */
  149. static int
  150. uc16_to_utf8(const unsigned short *us, int cc, unsigned char *s)
  151. {
  152. int i;
  153. unsigned char *t = s;
  154. unsigned short uc16;
  155. for (i = 0; i < cc; i++) {
  156. uc16 = us[i];
  157. if (uc16 <= 0x7F) {
  158. *t++ = (char) uc16;
  159. } else if (uc16 <= 0x7FF) {
  160. *t++ = 0xC0 | (unsigned char) ((uc16 >> 6) & 0x1F); /* upper 5 bits */
  161. *t++ = 0x80 | (unsigned char) (uc16 & 0x3F); /* lower 6 bits */
  162. } else {
  163. *t++ = 0xE0 | (unsigned char) ((uc16 >> 12) & 0x0F);/* upper 4 bits */
  164. *t++ = 0x80 | (unsigned char) ((uc16 >> 6) & 0x3F); /* next 6 bits */
  165. *t++ = 0x80 | (unsigned char) (uc16 & 0x3F); /* lowest 6 bits */
  166. }
  167. }
  168. *t = 0;
  169. return (t - s);
  170. }
  171. /*
  172. UTF8 utility:
  173. This map return the expected count of bytes based on the first char
  174. */
  175. const char utf8_len_map[256] = {
  176. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  177. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  178. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  179. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  180. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  181. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  182. 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  183. 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
  184. };
  185. #ifdef DEBUG_TEXT_SHAPING
  186. /*
  187. * Return the number of character (not byte) of UTF-8 string
  188. */
  189. int utf8_nchar ( const char *str )
  190. {
  191. int n = 0;
  192. int al = strlen ( str );
  193. while ( n < al )
  194. n += utf8_len_map[(unsigned char)str[n]];
  195. return (n < al) ? n : al;
  196. }
  197. #endif
  198. #define HAVE_SHAPEJOINING_SUPPORT 1
  199. #if HAVE_SHAPEJOINING_SUPPORT
  200. typedef struct char_shaped {
  201. unsigned short isolated;
  202. unsigned short initial;
  203. unsigned short medial;
  204. unsigned short final;
  205. } chr_shpjoin_t;
  206. /* This table start from a base of 0x0621, up to 0x06D3 */
  207. #define SHAPED_TABLE_START 0x0621
  208. #define SHAPED_TABLE_TOP 0x06D3
  209. static const chr_shpjoin_t shaped_table[] =
  210. {
  211. /* base s i m f */
  212. { /*0x0621*/ 0xFE80, 0x0000, 0x0000, 0x0000, }, /* HAMZA */
  213. { /*0x0622*/ 0xFE81, 0x0000, 0x0000, 0xFE82, }, /* ALEF_MADDA */
  214. { /*0x0623*/ 0xFE83, 0x0000, 0x0000, 0xFE84, }, /* ALEF_HAMZA_ABOVE */
  215. { /*0x0624*/ 0xFE85, 0x0000, 0x0000, 0xFE86, }, /* WAW_HAMZA */
  216. { /*0x0625*/ 0xFE87, 0x0000, 0x0000, 0xFE88, }, /* ALEF_HAMZA_BELOW */
  217. { /*0x0626*/ 0xFE89, 0xFE8B, 0xFE8C, 0xFE8A, }, /* YEH_HAMZA */
  218. { /*0x0627*/ 0xFE8D, 0x0000, 0x0000, 0xFE8E, }, /* ALEF */
  219. { /*0x0628*/ 0xFE8F, 0xFE91, 0xFE92, 0xFE90, }, /* BEH */
  220. { /*0x0629*/ 0xFE93, 0x0000, 0x0000, 0xFE94, }, /* TEH_MARBUTA */
  221. { /*0x062A*/ 0xFE95, 0xFE97, 0xFE98, 0xFE96, }, /* TEH */
  222. { /*0x062B*/ 0xFE99, 0xFE9B, 0xFE9C, 0xFE9A, }, /* THEH */
  223. { /*0x062C*/ 0xFE9D, 0xFE9F, 0xFEA0, 0xFE9E, }, /* JEEM */
  224. { /*0x062D*/ 0xFEA1, 0xFEA3, 0xFEA4, 0xFEA2, }, /* HAH */
  225. { /*0x062E*/ 0xFEA5, 0xFEA7, 0xFEA8, 0xFEA6, }, /* KHAH */
  226. { /*0x062F*/ 0xFEA9, 0x0000, 0x0000, 0xFEAA, }, /* DAL */
  227. { /*0x0630*/ 0xFEAB, 0x0000, 0x0000, 0xFEAC, }, /* THAL */
  228. { /*0x0631*/ 0xFEAD, 0x0000, 0x0000, 0xFEAE, }, /* REH */
  229. { /*0x0632*/ 0xFEAF, 0x0000, 0x0000, 0xFEB0, }, /* ZAIN */
  230. { /*0x0633*/ 0xFEB1, 0xFEB3, 0xFEB4, 0xFEB2, }, /* SEEN */
  231. { /*0x0634*/ 0xFEB5, 0xFEB7, 0xFEB8, 0xFEB6, }, /* SHEEN */
  232. { /*0x0635*/ 0xFEB9, 0xFEBB, 0xFEBC, 0xFEBA, }, /* SAD */
  233. { /*0x0636*/ 0xFEBD, 0xFEBF, 0xFEC0, 0xFEBE, }, /* DAD */
  234. { /*0x0637*/ 0xFEC1, 0xFEC3, 0xFEC4, 0xFEC2, }, /* TAH */
  235. { /*0x0638*/ 0xFEC5, 0xFEC7, 0xFEC8, 0xFEC6, }, /* ZAH */
  236. { /*0x0639*/ 0xFEC9, 0xFECB, 0xFECC, 0xFECA, }, /* AIN */
  237. { /*0x063A*/ 0xFECD, 0xFECF, 0xFED0, 0xFECE, }, /* GHAIN */
  238. { /*0x063B*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  239. { /*0x063C*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  240. { /*0x063D*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  241. { /*0x063E*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  242. { /*0x063F*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  243. { /*0x0640*/ 0x0640, 0x0640, 0x0640, 0x0640, }, /* TATWEEL */
  244. { /*0x0641*/ 0xFED1, 0xFED3, 0xFED4, 0xFED2, }, /* FEH */
  245. { /*0x0642*/ 0xFED5, 0xFED7, 0xFED8, 0xFED6, }, /* QAF */
  246. { /*0x0643*/ 0xFED9, 0xFEDB, 0xFEDC, 0xFEDA, }, /* KAF */
  247. { /*0x0644*/ 0xFEDD, 0xFEDF, 0xFEE0, 0xFEDE, }, /* LAM */
  248. { /*0x0645*/ 0xFEE1, 0xFEE3, 0xFEE4, 0xFEE2, }, /* MEEM */
  249. { /*0x0646*/ 0xFEE5, 0xFEE7, 0xFEE8, 0xFEE6, }, /* NOON */
  250. { /*0x0647*/ 0xFEE9, 0xFEEB, 0xFEEC, 0xFEEA, }, /* HEH */
  251. { /*0x0648*/ 0xFEED, 0x0000, 0x0000, 0xFEEE, }, /* WAW */
  252. { /*0x0649*/ 0xFEEF, 0xFBE8, 0xFBE9, 0xFEF0, }, /* ALEF_MAKSURA */
  253. { /*0x064A*/ 0xFEF1, 0xFEF3, 0xFEF4, 0xFEF2, }, /* YEH */
  254. { /*0x064B*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  255. { /*0x064C*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  256. { /*0x064D*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  257. { /*0x064E*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  258. { /*0x064F*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  259. { /*0x0650*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  260. { /*0x0651*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  261. { /*0x0652*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  262. { /*0x0653*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  263. { /*0x0654*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  264. { /*0x0655*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  265. { /*0x0656*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  266. { /*0x0657*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  267. { /*0x0658*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  268. { /*0x0659*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  269. { /*0x065A*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  270. { /*0x065B*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  271. { /*0x065C*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  272. { /*0x065D*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  273. { /*0x065E*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  274. { /*0x065F*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  275. { /*0x0660*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  276. { /*0x0661*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  277. { /*0x0662*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  278. { /*0x0663*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  279. { /*0x0664*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  280. { /*0x0665*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  281. { /*0x0666*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  282. { /*0x0667*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  283. { /*0x0668*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  284. { /*0x0669*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  285. { /*0x066A*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  286. { /*0x066B*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  287. { /*0x066C*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  288. { /*0x066D*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  289. { /*0x066E*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  290. { /*0x066F*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  291. { /*0x0670*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  292. { /*0x0671*/ 0xFB50, 0x0000, 0x0000, 0xFB51, },
  293. { /*0x0672*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  294. { /*0x0673*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  295. { /*0x0674*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  296. { /*0x0675*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  297. { /*0x0676*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  298. { /*0x0677*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  299. { /*0x0678*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  300. { /*0x0679*/ 0xFB66, 0xFB68, 0xFB69, 0xFB67, },
  301. { /*0x067A*/ 0xFB5E, 0xFB60, 0xFB61, 0xFB5F, },
  302. { /*0x067B*/ 0xFB52, 0xFB54, 0xFB55, 0xFB53, },
  303. { /*0x067C*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  304. { /*0x067D*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  305. { /*0x067E*/ 0xFB56, 0xFB58, 0xFB59, 0xFB57, },
  306. { /*0x067F*/ 0xFB62, 0xFB64, 0xFB65, 0xFB63, },
  307. { /*0x0680*/ 0xFB5A, 0xFB5C, 0xFB5D, 0xFB5B, },
  308. { /*0x0681*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  309. { /*0x0682*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  310. { /*0x0683*/ 0xFB76, 0xFB78, 0xFB79, 0xFB77, },
  311. { /*0x0684*/ 0xFB72, 0xFB74, 0xFB75, 0xFB73, },
  312. { /*0x0685*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  313. { /*0x0686*/ 0xFB7A, 0xFB7C, 0xFB7D, 0xFB7B, },
  314. { /*0x0687*/ 0xFB7E, 0xFB80, 0xFB81, 0xFB7F, },
  315. { /*0x0688*/ 0xFB88, 0x0000, 0x0000, 0xFB89, },
  316. { /*0x0689*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  317. { /*0x068A*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  318. { /*0x068B*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  319. { /*0x068C*/ 0xFB84, 0x0000, 0x0000, 0xFB85, },
  320. { /*0x068D*/ 0xFB82, 0x0000, 0x0000, 0xFB83, },
  321. { /*0x068E*/ 0xFB86, 0x0000, 0x0000, 0xFB87, },
  322. { /*0x068F*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  323. { /*0x0690*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  324. { /*0x0691*/ 0xFB8C, 0x0000, 0x0000, 0xFB8D, },
  325. { /*0x0692*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  326. { /*0x0693*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  327. { /*0x0694*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  328. { /*0x0695*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  329. { /*0x0696*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  330. { /*0x0697*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  331. { /*0x0698*/ 0xFB8A, 0x0000, 0x0000, 0xFB8B, },
  332. { /*0x0699*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  333. { /*0x069A*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  334. { /*0x069B*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  335. { /*0x069C*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  336. { /*0x069D*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  337. { /*0x069E*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  338. { /*0x069F*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  339. { /*0x06A0*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  340. { /*0x06A1*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  341. { /*0x06A2*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  342. { /*0x06A3*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  343. { /*0x06A4*/ 0xFB6A, 0xFB6C, 0xFB6D, 0xFB6B, },
  344. { /*0x06A5*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  345. { /*0x06A6*/ 0xFB6E, 0xFB70, 0xFB71, 0xFB6F, },
  346. { /*0x06A7*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  347. { /*0x06A8*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  348. { /*0x06A9*/ 0xFB8E, 0xFB90, 0xFB91, 0xFB8F, },
  349. { /*0x06AA*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  350. { /*0x06AB*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  351. { /*0x06AC*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  352. { /*0x06AD*/ 0xFBD3, 0xFBD5, 0xFBD6, 0xFBD4, },
  353. { /*0x06AE*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  354. { /*0x06AF*/ 0xFB92, 0xFB94, 0xFB95, 0xFB93, },
  355. { /*0x06B0*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  356. { /*0x06B1*/ 0xFB9A, 0xFB9C, 0xFB9D, 0xFB9B, },
  357. { /*0x06B2*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  358. { /*0x06B3*/ 0xFB96, 0xFB98, 0xFB99, 0xFB97, },
  359. { /*0x06B4*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  360. { /*0x06B5*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  361. { /*0x06B6*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  362. { /*0x06B7*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  363. { /*0x06B8*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  364. { /*0x06B9*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  365. { /*0x06BA*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  366. { /*0x06BB*/ 0xFBA0, 0xFBA2, 0xFBA3, 0xFBA1, },
  367. { /*0x06BC*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  368. { /*0x06BD*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  369. { /*0x06BE*/ 0xFBAA, 0xFBAC, 0xFBAD, 0xFBAB, },
  370. { /*0x06BF*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  371. { /*0x06C0*/ 0xFBA4, 0x0000, 0x0000, 0xFBA5, },
  372. { /*0x06C1*/ 0xFBA6, 0xFBA8, 0xFBA9, 0xFBA7, },
  373. { /*0x06C2*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  374. { /*0x06C3*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  375. { /*0x06C4*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  376. { /*0x06C5*/ 0xFBE0, 0x0000, 0x0000, 0xFBE1, },
  377. { /*0x06C6*/ 0xFBD9, 0x0000, 0x0000, 0xFBDA, },
  378. { /*0x06C7*/ 0xFBD7, 0x0000, 0x0000, 0xFBD8, },
  379. { /*0x06C8*/ 0xFBDB, 0x0000, 0x0000, 0xFBDC, },
  380. { /*0x06C9*/ 0xFBE2, 0x0000, 0x0000, 0xFBE3, },
  381. { /*0x06CA*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  382. { /*0x06CB*/ 0xFBDE, 0x0000, 0x0000, 0xFBDF, },
  383. { /*0x06CC*/ 0xFBFC, 0xFBFE, 0xFBFF, 0xFBFD, },
  384. { /*0x06CD*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  385. { /*0x06CE*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  386. { /*0x06CF*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  387. { /*0x06D0*/ 0xFBE4, 0xFBE6, 0xFBE7, 0xFBE5, },
  388. { /*0x06D1*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  389. { /*0x06D2*/ 0xFBAE, 0x0000, 0x0000, 0xFBAF, },
  390. { /*0x06D3*/ 0xFBB0, 0x0000, 0x0000, 0xFBB1, },
  391. };
  392. #define SHAPED_TABLE2_START 0xFEF5
  393. #define SHAPED_TABLE2_TOP 0xFEFB
  394. /*
  395. * The second table is for special ligatures
  396. */
  397. static const chr_shpjoin_t shaped_table2[] =
  398. {
  399. { /*0xFEF5*/ 0xFEF5, 0x0000, 0x0000, 0xFEF6, }, /* LAM_ALEF_MADDA */
  400. { /*0xFEF6*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  401. { /*0xFEF7*/ 0xFEF7, 0x0000, 0x0000, 0xFEF8, }, /* LAM_ALEF_HAMZA_ABOVE */
  402. { /*0xFEF8*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  403. { /*0xFEF9*/ 0xFEF9, 0x0000, 0x0000, 0xFEFA, }, /* LAM_ALEF_HAMZA_BELOW */
  404. { /*0xFEFA*/ 0x0000, 0x0000, 0x0000, 0x0000, }, /* dummy filler */
  405. { /*0xFEFB*/ 0xFEFB, 0x0000, 0x0000, 0xFEFC, }, /* LAM_ALEF */
  406. };
  407. #define assignShape(chr) ( ((chr) >= SHAPED_TABLE_START && (chr) <= SHAPED_TABLE_TOP)? \
  408. &shaped_table[(chr)-SHAPED_TABLE_START] : \
  409. ((chr) >= SHAPED_TABLE2_START && (chr) <= SHAPED_TABLE2_TOP)? \
  410. &shaped_table2[(chr)-SHAPED_TABLE2_START] : NULL)
  411. #define assignShapeUtf(txt, i) ( (utf8_len_map[(unsigned char)((txt)[(i)])] > 1)? \
  412. doAssignShapeUtf((txt)+(i)) : NULL)
  413. static const chr_shpjoin_t *
  414. doAssignShapeUtf(const char *txt)
  415. {
  416. unsigned short fs;
  417. utf8_to_utf16((const unsigned char *) txt,
  418. utf8_len_map[(unsigned char) txt[0]], &fs);
  419. return assignShape(fs);
  420. }
  421. static void
  422. storeUc_2_Utf8(char *dest, int *psz, unsigned short wch)
  423. {
  424. int cb = uc16_to_utf8(&wch, 1, dest + (*psz));
  425. *psz = *psz + cb;
  426. }
  427. static void
  428. store_Utf8(char *dest, int *psz, const char *txt)
  429. {
  430. int cb = utf8_len_map[(unsigned char) txt[0]];
  431. memcpy(dest + (*psz), txt, cb);
  432. *psz = *psz + cb;
  433. }
  434. /*
  435. * Note that text is currently left to right
  436. */
  437. static unsigned short *
  438. arabicJoin_UC16(const unsigned short *text, int len, unsigned long *pAttrib)
  439. {
  440. int i;
  441. unsigned short *new_str;
  442. const chr_shpjoin_t *prev = NULL;
  443. const chr_shpjoin_t *curr = NULL;
  444. const chr_shpjoin_t *next = NULL;
  445. unsigned long attrib = 0;
  446. new_str = (unsigned short *) malloc((1 + len) * sizeof(unsigned short));
  447. if (new_str == NULL)
  448. return NULL;
  449. for (i = 0; i < len; i++) {
  450. if ((curr = assignShape(text[i])) != NULL) {
  451. if (i < len - 1)
  452. next = assignShape(text[i + 1]);
  453. else
  454. next = NULL;
  455. if (next) {
  456. if (prev) {
  457. if (!prev->initial || !prev->medial)
  458. new_str[i] = curr->initial ?
  459. curr->initial : curr->isolated;
  460. else
  461. new_str[i] = curr->medial ?
  462. curr->medial : curr->final;
  463. } else {
  464. new_str[i] = curr->initial ?
  465. curr->initial : curr->isolated;
  466. }
  467. } else {
  468. if (prev) {
  469. if (!prev->initial || !prev->medial)
  470. new_str[i] = curr->isolated;
  471. else
  472. new_str[i] = curr->final ?
  473. curr->final : curr->isolated;
  474. } else {
  475. new_str[i] = curr->isolated;
  476. }
  477. }
  478. attrib |= (FTK_TEXT_ATTR_SHAPED | FTK_TEXT_ATTR_EXTENDED);
  479. } else {
  480. new_str[i] = text[i];
  481. if (text[i] <= 0xFF)
  482. attrib |= FTK_TEXT_ATTR_STANDARD;
  483. else
  484. attrib |= FTK_TEXT_ATTR_EXTENDED;
  485. }
  486. prev = curr;
  487. }
  488. new_str[i] = 0;
  489. if (pAttrib)
  490. *pAttrib = attrib;
  491. return new_str;
  492. }
  493. /*
  494. * Note that text is currently left to right
  495. */
  496. char *
  497. arabicJoin_UTF8(const char *text, int len, int *pNewLen,
  498. unsigned long *pAttrib)
  499. {
  500. int i, sz;
  501. char *new_str;
  502. const chr_shpjoin_t *prev = NULL;
  503. const chr_shpjoin_t *curr = NULL;
  504. const chr_shpjoin_t *next = NULL;
  505. unsigned long attrib = 0;
  506. /* Note that shaping may result in three UTF-8 bytes, due to 06xx -> FBxx translation*/
  507. /* two times the original buffer should be enough...*/
  508. new_str = (char *) malloc((1 + 2 * len) * sizeof(char));
  509. if (new_str == NULL)
  510. return NULL;
  511. sz = 0;
  512. for (i = 0; i < len;) {
  513. int b = utf8_len_map[(unsigned char) text[i]];
  514. if ((curr = assignShapeUtf(text, i)) != NULL) {
  515. if (i < len - b)
  516. next = assignShapeUtf(text, i + b);
  517. else
  518. next = NULL;
  519. if (next) {
  520. if (prev) {
  521. if (!prev->initial || !prev->medial)
  522. storeUc_2_Utf8(new_str, &sz,
  523. (curr->initial ? curr->initial :
  524. curr->isolated));
  525. else
  526. storeUc_2_Utf8(new_str, &sz,
  527. (curr->medial ? curr->medial :
  528. curr->final));
  529. } else {
  530. storeUc_2_Utf8(new_str, &sz, (curr->initial ?
  531. curr->initial : curr-> isolated));
  532. }
  533. } else {
  534. if (prev) {
  535. if (!prev->initial || !prev->medial)
  536. storeUc_2_Utf8(new_str, &sz, curr->isolated);
  537. else
  538. storeUc_2_Utf8(new_str, &sz,
  539. (curr->final ? curr->final :
  540. curr->isolated));
  541. } else {
  542. storeUc_2_Utf8(new_str, &sz, curr->isolated);
  543. }
  544. }
  545. attrib |= (FTK_TEXT_ATTR_SHAPED | FTK_TEXT_ATTR_EXTENDED);
  546. } else {
  547. store_Utf8(new_str, &sz, text + i);
  548. if ((unsigned char) text[i] < 0xC0)
  549. attrib |= FTK_TEXT_ATTR_STANDARD;
  550. else
  551. attrib |= FTK_TEXT_ATTR_EXTENDED;
  552. }
  553. i += b;
  554. prev = curr;
  555. }
  556. new_str[sz] = 0;
  557. if (pNewLen)
  558. *pNewLen = sz;
  559. if (pAttrib)
  560. *pAttrib = attrib;
  561. #ifdef DEBUG_TEXT_SHAPING
  562. #endif
  563. return new_str;
  564. }
  565. unsigned short *
  566. doCharShape_UC16(const unsigned short *text, int len, int *pNewLen,
  567. unsigned long *pAttrib)
  568. {
  569. unsigned short *conv = arabicJoin_UC16(text, len, pAttrib);
  570. if (pNewLen)
  571. *pNewLen = len;
  572. return conv;
  573. }
  574. char *
  575. doCharShape_UTF8(const char *text, int len, int *pNewLen, unsigned long *pAttrib)
  576. {
  577. return arabicJoin_UTF8(text, len, pNewLen, pAttrib);
  578. }
  579. #else /* HAVE_SHAPEJOINING_SUPPORT */
  580. /* DUMMY FUNCTIONS */
  581. unsigned short *
  582. doCharShape_UC16(const unsigned short *text, int len, int *pNewLen,
  583. unsigned long *pAttrib)
  584. {
  585. unsigned short *conv = malloc((len + 1) * sizeof(unsigned short));
  586. if (conv == NULL)
  587. return NULL;
  588. memcpy(conv, text, len * sizeof(unsigned short));
  589. conv[len] = 0;
  590. if (pNewLen)
  591. *pNewLen = len;
  592. if (pAttrib)
  593. *pAttrib = 0;
  594. return conv;
  595. }
  596. char *
  597. doCharShape_UTF8(const char *text, int len, int *pNewLen, unsigned long *pAttrib)
  598. {
  599. char *conv = malloc((len + 1) * sizeof(char));
  600. if (conv == NULL)
  601. return NULL;
  602. memcpy(conv, text, len * sizeof(char));
  603. conv[len] = 0;
  604. if (pNewLen)
  605. *pNewLen = len;
  606. if (pAttrib)
  607. *pAttrib = 0;
  608. return conv;
  609. }
  610. #endif /* HAVE_SHAPEJOINING_SUPPORT */
  611. #define HAVE_FRIBIDI_SUPPORT 1
  612. #if HAVE_FRIBIDI_SUPPORT
  613. #include <fribidi/fribidi.h>
  614. char *
  615. doCharBidi_UTF8(const char *text, int len, int *v2lPos, char *pDirection,
  616. unsigned long *pAttrib)
  617. {
  618. FriBidiChar *ftxt, *fvirt;
  619. FriBidiChar localBuff[128];
  620. FriBidiCharType basedir;
  621. int cc;
  622. int isLocal = 0;
  623. char *new_str;
  624. int new_len;
  625. new_str = (char *) malloc(len + 1);
  626. if (new_str == NULL)
  627. return NULL;
  628. /* len may be greather than real char count, but it's ok.
  629. if will fit in localBuff, we use it to improve speed */
  630. if (len < sizeof(localBuff) / sizeof(localBuff[0]) / 2) {
  631. ftxt = localBuff;
  632. fvirt = localBuff +
  633. sizeof(localBuff) / sizeof(localBuff[0]) / 2;
  634. isLocal = 1;
  635. } else {
  636. ftxt = (FriBidiChar *) malloc((len + 1) * sizeof(FriBidiChar));
  637. fvirt = (FriBidiChar *) malloc((len + 1) * sizeof(FriBidiChar));
  638. }
  639. if (ftxt == NULL)
  640. return NULL;
  641. if (fvirt == NULL) {
  642. free(ftxt);
  643. return NULL;
  644. }
  645. cc = fribidi_utf8_to_unicode((char *) text, len, ftxt);
  646. basedir = FRIBIDI_TYPE_N;
  647. fribidi_log2vis(ftxt, cc, &basedir, fvirt, v2lPos, NULL, pDirection);
  648. new_len = fribidi_unicode_to_utf8(fvirt, cc, new_str);
  649. if (pAttrib) {
  650. if (basedir & FRIBIDI_MASK_RTL)
  651. *pAttrib |= FTK_TEXT_ATTR_RTOL;
  652. }
  653. if (!isLocal) {
  654. free(fvirt);
  655. free(ftxt);
  656. }
  657. new_str[new_len] = 0;
  658. return new_str;
  659. }
  660. unsigned short *
  661. doCharBidi_UC16(const unsigned short *text, int len, int *v2lPos,
  662. char *pDirection, unsigned long *pAttrib)
  663. {
  664. FriBidiChar *ftxt, *fvirt;
  665. FriBidiChar localBuff[128];
  666. FriBidiCharType basedir;
  667. int cc;
  668. int isLocal = 0;
  669. unsigned short *new_str;
  670. new_str = (unsigned short *) malloc((len + 1) * sizeof(unsigned short));
  671. if (new_str == NULL)
  672. return NULL;
  673. /* len may be greather than real char count, but it's ok.
  674. if will fit in localBuff, we use it to improve speed */
  675. if (len < sizeof(localBuff) / sizeof(localBuff[0]) / 2) {
  676. ftxt = localBuff;
  677. fvirt = localBuff +
  678. sizeof(localBuff) / sizeof(localBuff[0]) / 2;
  679. isLocal = 1;
  680. } else {
  681. ftxt = (FriBidiChar *) malloc((len + 1) * sizeof(FriBidiChar));
  682. fvirt = (FriBidiChar *) malloc((len + 1) * sizeof(FriBidiChar));
  683. }
  684. if (ftxt == NULL)
  685. return NULL;
  686. if (fvirt == NULL) {
  687. free(ftxt);
  688. return NULL;
  689. }
  690. for (cc = 0; cc < len; cc++)
  691. ftxt[cc] = text[cc];
  692. basedir = FRIBIDI_TYPE_N;
  693. fribidi_log2vis(ftxt, cc, &basedir, fvirt, v2lPos, NULL, pDirection);
  694. for (cc = 0; cc < len; cc++)
  695. new_str[cc] = (unsigned short) fvirt[cc];
  696. new_str[cc] = 0;
  697. if (pAttrib) {
  698. if (basedir & FRIBIDI_MASK_RTL)
  699. *pAttrib |= FTK_TEXT_ATTR_RTOL;
  700. }
  701. if (!isLocal) {
  702. free(fvirt);
  703. free(ftxt);
  704. }
  705. return new_str;
  706. }
  707. #else
  708. /* DUMMY FUNCTIONS */
  709. char *
  710. doCharBidi_UTF8(const char *text, int len, int *v2lPos, char *pDirection,
  711. unsigned long *pAttrib)
  712. {
  713. int i;
  714. unsigned short *conv = malloc((len + 1) * sizeof(unsigned short));
  715. if (conv == NULL)
  716. return NULL;
  717. memcpy(conv, text, len * sizeof(unsigned short));
  718. conv[len] = 0;
  719. if (v2lPos)
  720. for (i = 0; i < len; i++)
  721. v2lPos[i] = i;
  722. if (pDirection)
  723. memset(pDirection, 0, len * sizeof(pDirection[0]));
  724. return (char *) conv;
  725. }
  726. unsigned short *
  727. doCharBidi_UC16(const unsigned short *text, int len, int *v2lPos,
  728. char *pDirection, unsigned long *pAttrib)
  729. {
  730. int i;
  731. char *conv = malloc((len + 1) * sizeof(char));
  732. if (conv == NULL)
  733. return NULL;
  734. memcpy(conv, text, len * sizeof(char));
  735. conv[len] = 0;
  736. if (v2lPos)
  737. for (i = 0; i < len; i++)
  738. v2lPos[i] = i;
  739. if (pDirection)
  740. memset(pDirection, 0, len * sizeof(pDirection[0]));
  741. return (unsigned short *) conv;
  742. }
  743. #endif /* HAVE_FRIBIDI_SUPPORT */
  744. struct _FtkTextLayout
  745. {
  746. int pos;
  747. int len;
  748. size_t width;
  749. FtkFont* font;
  750. char* text;
  751. int line_len;
  752. int line_pos;
  753. char* bidi_line;
  754. unsigned long line_attr;
  755. FtkWrapMode wrap_mode;
  756. int v2l_v_line[FTK_LINE_CHAR_NR+1];
  757. int v2l_l_line[8 * FTK_LINE_CHAR_NR+1];
  758. };
  759. FtkTextLayout* ftk_text_layout_create(void)
  760. {
  761. FtkTextLayout* thiz = FTK_NEW(FtkTextLayout);
  762. return thiz;
  763. }
  764. Ret ftk_text_layout_set_font(FtkTextLayout* thiz, FtkFont* font)
  765. {
  766. return_val_if_fail(thiz != NULL && font != NULL, RET_FAIL);
  767. thiz->font = font;
  768. return RET_OK;
  769. }
  770. Ret ftk_text_layout_set_width(FtkTextLayout* thiz, size_t width)
  771. {
  772. return_val_if_fail(thiz != NULL && width > 0, RET_FAIL);
  773. thiz->width = width;
  774. return RET_OK;
  775. }
  776. Ret ftk_text_layout_set_text(FtkTextLayout* thiz, const char* text, int len)
  777. {
  778. unsigned long attr = 0;
  779. return_val_if_fail(thiz != NULL && text != NULL, RET_FAIL);
  780. if(thiz->text != NULL)
  781. {
  782. free(thiz->text);
  783. thiz->text = NULL;
  784. }
  785. thiz->pos = 0;
  786. thiz->len = len < 0 ? strlen(text) : len;
  787. thiz->text = doCharShape_UTF8(text, thiz->len, &thiz->len, &attr);
  788. return RET_OK;
  789. }
  790. Ret ftk_text_layout_set_wrap_mode(FtkTextLayout* thiz, FtkWrapMode wrap_mode)
  791. {
  792. return_val_if_fail(thiz != NULL, RET_FAIL);
  793. thiz->wrap_mode = wrap_mode;
  794. return RET_OK;
  795. }
  796. Ret ftk_text_layout_init(FtkTextLayout* thiz, const char* text, int len, FtkFont* font, size_t width)
  797. {
  798. return_val_if_fail(thiz != NULL && text != NULL && font != NULL && width > 0, RET_FAIL);
  799. thiz->pos = 0;
  800. thiz->font = font;
  801. thiz->width = width;
  802. ftk_text_layout_set_text(thiz, text, len);
  803. return RET_OK;
  804. }
  805. Ret ftk_text_layout_skip_to(FtkTextLayout* thiz, int pos)
  806. {
  807. return_val_if_fail(thiz != NULL && pos >= 0 && pos < thiz->len, RET_FAIL);
  808. thiz->pos = pos;
  809. return RET_OK;
  810. }
  811. Ret ftk_text_layout_get_visual_line(FtkTextLayout* thiz, FtkTextLine* line)
  812. {
  813. int i = 0;
  814. int extent = 0;
  815. unsigned long attr = 0;
  816. const char* end = NULL;
  817. return_val_if_fail(thiz != NULL && line != NULL, RET_FAIL);
  818. if(thiz->pos >= thiz->len && thiz->line_pos >= thiz->line_len)
  819. {
  820. return RET_EOF;
  821. }
  822. line->pos_v2l = thiz->v2l_v_line;
  823. line->attr = FTK_TEXT_ATTR_NORMAL;
  824. if(thiz->line_pos >= thiz->line_len)
  825. {
  826. int line_len = 0;
  827. const char* line_start = thiz->text + thiz->pos;
  828. const char* line_end = line_start;
  829. thiz->line_pos = 0;
  830. while((line_end - thiz->text) <= thiz->len)
  831. {
  832. if(*line_end == '\n' || *line_end == '\0') break;
  833. line_end++;
  834. }
  835. line_len = line_end - line_start;
  836. thiz->pos += line_len;
  837. if(thiz->bidi_line != NULL)
  838. {
  839. free(thiz->bidi_line);
  840. }
  841. thiz->bidi_line = doCharBidi_UTF8(line_start, line_len, thiz->v2l_l_line, NULL, &attr);
  842. thiz->line_len = strlen(thiz->bidi_line);
  843. thiz->line_attr = attr;
  844. }
  845. line->text = thiz->bidi_line + thiz->line_pos;
  846. end = ftk_font_calc_str_visible_range(thiz->font, line->text, 0, -1, thiz->width, &extent);
  847. line->len = end - line->text;
  848. line->extent = extent;
  849. line->attr = thiz->line_attr;
  850. if(thiz->line_attr & FTK_TEXT_ATTR_RTOL)
  851. {
  852. line->xoffset = thiz->width - extent;
  853. for(i = 0; i < line->len && i < FTK_LINE_CHAR_NR; i++)
  854. {
  855. line->pos_v2l[i] = thiz->v2l_v_line[thiz->line_pos + i] + thiz->pos - thiz->line_len;
  856. }
  857. }
  858. else
  859. {
  860. line->xoffset = 0;
  861. for(i = 0; i < line->len && i < FTK_LINE_CHAR_NR; i++)
  862. {
  863. line->pos_v2l[i] = thiz->pos - thiz->line_len + 1;
  864. }
  865. }
  866. ftk_logd("%s: line_pos=%d line_len=%d line.len=%d attr=%x\n", __func__, thiz->line_pos, thiz->line_len, line->len, attr);
  867. thiz->line_pos += line->len;
  868. for(i = line->len - 1; i >= 0; i--)
  869. {
  870. if(line->text[i] == '\r' || line->text[i] == '\n')
  871. line->len--;
  872. }
  873. return RET_OK;
  874. }
  875. void ftk_text_layout_destroy(FtkTextLayout* thiz)
  876. {
  877. if(thiz != NULL)
  878. {
  879. FTK_FREE(thiz);
  880. }
  881. return;
  882. }