1 /* 2 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 3 * 4 * This is part of HarfBuzz, an OpenType Layout engine library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 */ 24 25 #include "harfbuzz-shaper.h" 26 #include "harfbuzz-shaper-private.h" 27 28 #include <assert.h> 29 30 static const HB_UChar16 ReplacementCharacter = 0xfffd; 31 32 typedef struct { 33 unsigned char shape; 34 unsigned char justification; 35 } HB_ArabicProperties; 36 37 typedef enum { 38 XIsolated, 39 XFinal, 40 XInitial, 41 XMedial, 42 /* intermediate state */ 43 XCausing 44 } ArabicShape; 45 46 /* 47 // these groups correspond to the groups defined in the Unicode standard. 48 // Some of these groups are equal with regards to both joining and line breaking behaviour, 49 // and thus have the same enum value 50 // 51 // I'm not sure the mapping of syriac to arabic enums is correct with regards to justification, but as 52 // I couldn't find any better document I'll hope for the best. 53 */ 54 typedef enum { 55 /* NonJoining */ 56 ArabicNone, 57 ArabicSpace, 58 /* Transparent */ 59 Transparent, 60 /* Causing */ 61 Center, 62 Kashida, 63 64 /* Arabic */ 65 /* Dual */ 66 Beh, 67 Noon, 68 Meem = Noon, 69 Heh = Noon, 70 KnottedHeh = Noon, 71 HehGoal = Noon, 72 SwashKaf = Noon, 73 Yeh, 74 Hah, 75 Seen, 76 Sad = Seen, 77 Tah, 78 Kaf = Tah, 79 Gaf = Tah, 80 Lam = Tah, 81 Ain, 82 Feh = Ain, 83 Qaf = Ain, 84 /* Right */ 85 Alef, 86 Waw, 87 Dal, 88 TehMarbuta = Dal, 89 Reh, 90 HamzaOnHehGoal, 91 YehWithTail = HamzaOnHehGoal, 92 YehBarre = HamzaOnHehGoal, 93 94 /* Syriac */ 95 /* Dual */ 96 Beth = Beh, 97 Gamal = Ain, 98 Heth = Noon, 99 Teth = Hah, 100 Yudh = Noon, 101 Kaph = Noon, 102 Lamadh = Lam, 103 Mim = Noon, 104 Nun = Noon, 105 Semakh = Noon, 106 FinalSemakh = Noon, 107 SyriacE = Ain, 108 Pe = Ain, 109 ReversedPe = Hah, 110 Qaph = Noon, 111 Shin = Noon, 112 Fe = Ain, 113 114 /* Right */ 115 Alaph = Alef, 116 Dalath = Dal, 117 He = Dal, 118 SyriacWaw = Waw, 119 Zain = Alef, 120 YudhHe = Waw, 121 Sadhe = HamzaOnHehGoal, 122 Taw = Dal, 123 124 /* Compiler bug? Otherwise ArabicGroupsEnd would be equal to Dal + 1. */ 125 Dummy = HamzaOnHehGoal, 126 ArabicGroupsEnd 127 } ArabicGroup; 128 129 static const unsigned char arabic_group[0x150] = { 130 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 131 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 132 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 133 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 134 135 Transparent, Transparent, Transparent, Transparent, 136 Transparent, Transparent, ArabicNone, ArabicNone, 137 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 138 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 139 140 ArabicNone, ArabicNone, Alef, Alef, 141 Waw, Alef, Yeh, Alef, 142 Beh, TehMarbuta, Beh, Beh, 143 Hah, Hah, Hah, Dal, 144 145 Dal, Reh, Reh, Seen, 146 Seen, Sad, Sad, Tah, 147 Tah, Ain, Ain, ArabicNone, 148 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 149 150 /* 0x640 */ 151 Kashida, Feh, Qaf, Kaf, 152 Lam, Meem, Noon, Heh, 153 Waw, Yeh, Yeh, Transparent, 154 Transparent, Transparent, Transparent, Transparent, 155 156 Transparent, Transparent, Transparent, Transparent, 157 Transparent, Transparent, Transparent, Transparent, 158 Transparent, ArabicNone, ArabicNone, ArabicNone, 159 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 160 161 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 162 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 163 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 164 ArabicNone, ArabicNone, Beh, Qaf, 165 166 Transparent, Alef, Alef, Alef, 167 ArabicNone, Alef, Waw, Waw, 168 Yeh, Beh, Beh, Beh, 169 Beh, Beh, Beh, Beh, 170 171 /* 0x680 */ 172 Beh, Hah, Hah, Hah, 173 Hah, Hah, Hah, Hah, 174 Dal, Dal, Dal, Dal, 175 Dal, Dal, Dal, Dal, 176 177 Dal, Reh, Reh, Reh, 178 Reh, Reh, Reh, Reh, 179 Reh, Reh, Seen, Seen, 180 Seen, Sad, Sad, Tah, 181 182 Ain, Feh, Feh, Feh, 183 Feh, Feh, Feh, Qaf, 184 Qaf, Gaf, SwashKaf, Gaf, 185 Kaf, Kaf, Kaf, Gaf, 186 187 Gaf, Gaf, Gaf, Gaf, 188 Gaf, Lam, Lam, Lam, 189 Lam, Noon, Noon, Noon, 190 Noon, Noon, KnottedHeh, Hah, 191 192 /* 0x6c0 */ 193 TehMarbuta, HehGoal, HamzaOnHehGoal, HamzaOnHehGoal, 194 Waw, Waw, Waw, Waw, 195 Waw, Waw, Waw, Waw, 196 Yeh, YehWithTail, Yeh, Waw, 197 198 Yeh, Yeh, YehBarre, YehBarre, 199 ArabicNone, TehMarbuta, Transparent, Transparent, 200 Transparent, Transparent, Transparent, Transparent, 201 Transparent, ArabicNone, ArabicNone, Transparent, 202 203 Transparent, Transparent, Transparent, Transparent, 204 Transparent, ArabicNone, ArabicNone, Transparent, 205 Transparent, ArabicNone, Transparent, Transparent, 206 Transparent, Transparent, Dal, Reh, 207 208 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 209 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 210 ArabicNone, ArabicNone, Seen, Sad, 211 Ain, ArabicNone, ArabicNone, KnottedHeh, 212 213 /* 0x700 */ 214 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 215 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 216 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 217 ArabicNone, ArabicNone, ArabicNone, ArabicNone, 218 219 Alaph, Transparent, Beth, Gamal, 220 Gamal, Dalath, Dalath, He, 221 SyriacWaw, Zain, Heth, Teth, 222 Teth, Yudh, YudhHe, Kaph, 223 224 Lamadh, Mim, Nun, Semakh, 225 FinalSemakh, SyriacE, Pe, ReversedPe, 226 Sadhe, Qaph, Dalath, Shin, 227 Taw, Beth, Gamal, Dalath, 228 229 Transparent, Transparent, Transparent, Transparent, 230 Transparent, Transparent, Transparent, Transparent, 231 Transparent, Transparent, Transparent, Transparent, 232 Transparent, Transparent, Transparent, Transparent, 233 234 Transparent, Transparent, Transparent, Transparent, 235 Transparent, Transparent, Transparent, Transparent, 236 Transparent, Transparent, Transparent, ArabicNone, 237 ArabicNone, Zain, Kaph, Fe, 238 }; 239 240 static ArabicGroup arabicGroup(unsigned short uc) 241 { 242 if (uc >= 0x0600 && uc < 0x750) 243 return (ArabicGroup) arabic_group[uc-0x600]; 244 else if (uc == 0x200d) 245 return Center; 246 else if (HB_GetUnicodeCharCategory(uc) == HB_Separator_Space) 247 return ArabicSpace; 248 else 249 return ArabicNone; 250 } 251 252 253 /* 254 Arabic shaping obeys a number of rules according to the joining classes (see Unicode book, section on 255 arabic). 256 257 Each unicode char has a joining class (right, dual (left&right), center (joincausing) or transparent). 258 transparent joining is not encoded in HB_UChar16::joining(), but applies to all combining marks and format marks. 259 260 Right join-causing: dual + center 261 Left join-causing: dual + right + center 262 263 Rules are as follows (for a string already in visual order, as we have it here): 264 265 R1 Transparent characters do not affect joining behaviour. 266 R2 A right joining character, that has a right join-causing char on the right will get form XRight 267 (R3 A left joining character, that has a left join-causing char on the left will get form XLeft) 268 Note: the above rule is meaningless, as there are no pure left joining characters defined in Unicode 269 R4 A dual joining character, that has a left join-causing char on the left and a right join-causing char on 270 the right will get form XMedial 271 R5 A dual joining character, that has a right join causing char on the right, and no left join causing char on the left 272 will get form XRight 273 R6 A dual joining character, that has a left join causing char on the left, and no right join causing char on the right 274 will get form XLeft 275 R7 Otherwise the character will get form XIsolated 276 277 Additionally we have to do the minimal ligature support for lam-alef ligatures: 278 279 L1 Transparent characters do not affect ligature behaviour. 280 L2 Any sequence of Alef(XRight) + Lam(XMedial) will form the ligature Alef.Lam(XLeft) 281 L3 Any sequence of Alef(XRight) + Lam(XLeft) will form the ligature Alef.Lam(XIsolated) 282 283 The state table below handles rules R1-R7. 284 */ 285 286 typedef enum { 287 JNone, 288 JCausing, 289 JDual, 290 JRight, 291 JTransparent 292 } Joining; 293 294 static const Joining joining_for_group[ArabicGroupsEnd] = { 295 /* NonJoining */ 296 JNone, /* ArabicNone */ 297 JNone, /* ArabicSpace */ 298 /* Transparent */ 299 JTransparent, /* Transparent */ 300 /* Causing */ 301 JCausing, /* Center */ 302 JCausing, /* Kashida */ 303 /* Dual */ 304 JDual, /* Beh */ 305 JDual, /* Noon */ 306 JDual, /* Yeh */ 307 JDual, /* Hah */ 308 JDual, /* Seen */ 309 JDual, /* Tah */ 310 JDual, /* Ain */ 311 /* Right */ 312 JRight, /* Alef */ 313 JRight, /* Waw */ 314 JRight, /* Dal */ 315 JRight, /* Reh */ 316 JRight /* HamzaOnHehGoal */ 317 }; 318 319 320 typedef struct { 321 ArabicShape form1; 322 ArabicShape form2; 323 } JoiningPair; 324 325 static const JoiningPair joining_table[5][4] = 326 /* None, Causing, Dual, Right */ 327 { 328 { { XIsolated, XIsolated }, { XIsolated, XCausing }, { XIsolated, XInitial }, { XIsolated, XIsolated } }, /* XIsolated */ 329 { { XFinal, XIsolated }, { XFinal, XCausing }, { XFinal, XInitial }, { XFinal, XIsolated } }, /* XFinal */ 330 { { XIsolated, XIsolated }, { XInitial, XCausing }, { XInitial, XMedial }, { XInitial, XFinal } }, /* XInitial */ 331 { { XFinal, XIsolated }, { XMedial, XCausing }, { XMedial, XMedial }, { XMedial, XFinal } }, /* XMedial */ 332 { { XIsolated, XIsolated }, { XIsolated, XCausing }, { XIsolated, XMedial }, { XIsolated, XFinal } }, /* XCausing */ 333 }; 334 335 336 /* 337 According to http://www.microsoft.com/middleeast/Arabicdev/IE6/KBase.asp 338 339 1. Find the priority of the connecting opportunities in each word 340 2. Add expansion at the highest priority connection opportunity 341 3. If more than one connection opportunity have the same highest value, 342 use the opportunity closest to the end of the word. 343 344 Following is a chart that provides the priority for connection 345 opportunities and where expansion occurs. The character group names 346 are those in table 6.6 of the UNICODE 2.0 book. 347 348 349 PrioritY Glyph Condition Kashida Location 350 351 Arabic_Kashida User inserted Kashida The user entered a Kashida in a position. After the user 352 (Shift+j or Shift+[E with hat]) Thus, it is the highest priority to insert an inserted kashida 353 automatic kashida. 354 355 Arabic_Seen Seen, Sad Connecting to the next character. After the character. 356 (Initial or medial form). 357 358 Arabic_HaaDal Teh Marbutah, Haa, Dal Connecting to previous character. Before the final form 359 of these characters. 360 361 Arabic_Alef Alef, Tah, Lam, Connecting to previous character. Before the final form 362 Kaf and Gaf of these characters. 363 364 Arabic_BaRa Reh, Yeh Connected to medial Beh Before preceding medial Baa 365 366 Arabic_Waw Waw, Ain, Qaf, Feh Connecting to previous character. Before the final form of 367 these characters. 368 369 Arabic_Normal Other connecting Connecting to previous character. Before the final form 370 characters of these characters. 371 372 373 374 This seems to imply that we have at most one kashida point per arabic word. 375 376 */ 377 378 static void getArabicProperties(const unsigned short *chars, int len, HB_ArabicProperties *properties) 379 { 380 /* qDebug("arabicSyriacOpenTypeShape: properties:"); */ 381 int lastPos = 0; 382 int lastGroup = ArabicNone; 383 int i = 0; 384 385 ArabicGroup group = arabicGroup(chars[0]); 386 Joining j = joining_for_group[group]; 387 ArabicShape shape = joining_table[XIsolated][j].form2; 388 properties[0].justification = HB_NoJustification; 389 390 for (i = 1; i < len; ++i) { 391 /* #### fix handling for spaces and punktuation */ 392 properties[i].justification = HB_NoJustification; 393 394 group = arabicGroup(chars[i]); 395 j = joining_for_group[group]; 396 397 if (j == JTransparent) { 398 properties[i].shape = XIsolated; 399 continue; 400 } 401 402 properties[lastPos].shape = joining_table[shape][j].form1; 403 shape = joining_table[shape][j].form2; 404 405 switch(lastGroup) { 406 case Seen: 407 if (properties[lastPos].shape == XInitial || properties[lastPos].shape == XMedial) 408 properties[i-1].justification = HB_Arabic_Seen; 409 break; 410 case Hah: 411 if (properties[lastPos].shape == XFinal) 412 properties[lastPos-1].justification = HB_Arabic_HaaDal; 413 break; 414 case Alef: 415 if (properties[lastPos].shape == XFinal) 416 properties[lastPos-1].justification = HB_Arabic_Alef; 417 break; 418 case Ain: 419 if (properties[lastPos].shape == XFinal) 420 properties[lastPos-1].justification = HB_Arabic_Waw; 421 break; 422 case Noon: 423 if (properties[lastPos].shape == XFinal) 424 properties[lastPos-1].justification = HB_Arabic_Normal; 425 break; 426 case ArabicNone: 427 break; 428 429 default: 430 assert(FALSE); 431 } 432 433 lastGroup = ArabicNone; 434 435 switch(group) { 436 case ArabicNone: 437 case Transparent: 438 /* ### Center should probably be treated as transparent when it comes to justification. */ 439 case Center: 440 break; 441 case ArabicSpace: 442 properties[i].justification = HB_Arabic_Space; 443 break; 444 case Kashida: 445 properties[i].justification = HB_Arabic_Kashida; 446 break; 447 case Seen: 448 lastGroup = Seen; 449 break; 450 451 case Hah: 452 case Dal: 453 lastGroup = Hah; 454 break; 455 456 case Alef: 457 case Tah: 458 lastGroup = Alef; 459 break; 460 461 case Yeh: 462 case Reh: 463 if (properties[lastPos].shape == XMedial && arabicGroup(chars[lastPos]) == Beh) 464 properties[lastPos-1].justification = HB_Arabic_BaRa; 465 break; 466 467 case Ain: 468 case Waw: 469 lastGroup = Ain; 470 break; 471 472 case Noon: 473 case Beh: 474 case HamzaOnHehGoal: 475 lastGroup = Noon; 476 break; 477 case ArabicGroupsEnd: 478 assert(FALSE); 479 } 480 481 lastPos = i; 482 } 483 properties[lastPos].shape = joining_table[shape][JNone].form1; 484 485 486 /* 487 for (int i = 0; i < len; ++i) 488 qDebug("arabic properties(%d): uc=%x shape=%d, justification=%d", i, chars[i], properties[i].shape, properties[i].justification); 489 */ 490 } 491 492 static Joining getNkoJoining(unsigned short uc) 493 { 494 if (uc < 0x7ca) 495 return JNone; 496 if (uc <= 0x7ea) 497 return JDual; 498 if (uc <= 0x7f3) 499 return JTransparent; 500 if (uc <= 0x7f9) 501 return JNone; 502 if (uc == 0x7fa) 503 return JCausing; 504 return JNone; 505 } 506 507 static void getNkoProperties(const unsigned short *chars, int len, HB_ArabicProperties *properties) 508 { 509 int lastPos = 0; 510 int i = 0; 511 512 Joining j = getNkoJoining(chars[0]); 513 ArabicShape shape = joining_table[XIsolated][j].form2; 514 properties[0].justification = HB_NoJustification; 515 516 for (i = 1; i < len; ++i) { 517 properties[i].justification = (HB_GetUnicodeCharCategory(chars[i]) == HB_Separator_Space) ? 518 ArabicSpace : ArabicNone; 519 520 j = getNkoJoining(chars[i]); 521 522 if (j == JTransparent) { 523 properties[i].shape = XIsolated; 524 continue; 525 } 526 527 properties[lastPos].shape = joining_table[shape][j].form1; 528 shape = joining_table[shape][j].form2; 529 530 531 lastPos = i; 532 } 533 properties[lastPos].shape = joining_table[shape][JNone].form1; 534 535 536 /* 537 for (int i = 0; i < len; ++i) 538 qDebug("nko properties(%d): uc=%x shape=%d, justification=%d", i, chars[i], properties[i].shape, properties[i].justification); 539 */ 540 } 541 542 /* 543 // The unicode to unicode shaping codec. 544 // does only presentation forms B at the moment, but that should be enough for 545 // simple display 546 */ 547 static const hb_uint16 arabicUnicodeMapping[256][2] = { 548 /* base of shaped forms, and number-1 of them (0 for non shaping, 549 1 for right binding and 3 for dual binding */ 550 551 /* These are just the glyphs available in Unicode, 552 some characters are in R class, but have no glyphs in Unicode. */ 553 554 { 0x0600, 0 }, /* 0x0600 */ 555 { 0x0601, 0 }, /* 0x0601 */ 556 { 0x0602, 0 }, /* 0x0602 */ 557 { 0x0603, 0 }, /* 0x0603 */ 558 { 0x0604, 0 }, /* 0x0604 */ 559 { 0x0605, 0 }, /* 0x0605 */ 560 { 0x0606, 0 }, /* 0x0606 */ 561 { 0x0607, 0 }, /* 0x0607 */ 562 { 0x0608, 0 }, /* 0x0608 */ 563 { 0x0609, 0 }, /* 0x0609 */ 564 { 0x060A, 0 }, /* 0x060A */ 565 { 0x060B, 0 }, /* 0x060B */ 566 { 0x060C, 0 }, /* 0x060C */ 567 { 0x060D, 0 }, /* 0x060D */ 568 { 0x060E, 0 }, /* 0x060E */ 569 { 0x060F, 0 }, /* 0x060F */ 570 571 { 0x0610, 0 }, /* 0x0610 */ 572 { 0x0611, 0 }, /* 0x0611 */ 573 { 0x0612, 0 }, /* 0x0612 */ 574 { 0x0613, 0 }, /* 0x0613 */ 575 { 0x0614, 0 }, /* 0x0614 */ 576 { 0x0615, 0 }, /* 0x0615 */ 577 { 0x0616, 0 }, /* 0x0616 */ 578 { 0x0617, 0 }, /* 0x0617 */ 579 { 0x0618, 0 }, /* 0x0618 */ 580 { 0x0619, 0 }, /* 0x0619 */ 581 { 0x061A, 0 }, /* 0x061A */ 582 { 0x061B, 0 }, /* 0x061B */ 583 { 0x061C, 0 }, /* 0x061C */ 584 { 0x061D, 0 }, /* 0x061D */ 585 { 0x061E, 0 }, /* 0x061E */ 586 { 0x061F, 0 }, /* 0x061F */ 587 588 { 0x0620, 0 }, /* 0x0620 */ 589 { 0xFE80, 0 }, /* 0x0621 HAMZA */ 590 { 0xFE81, 1 }, /* 0x0622 R ALEF WITH MADDA ABOVE */ 591 { 0xFE83, 1 }, /* 0x0623 R ALEF WITH HAMZA ABOVE */ 592 { 0xFE85, 1 }, /* 0x0624 R WAW WITH HAMZA ABOVE */ 593 { 0xFE87, 1 }, /* 0x0625 R ALEF WITH HAMZA BELOW */ 594 { 0xFE89, 3 }, /* 0x0626 D YEH WITH HAMZA ABOVE */ 595 { 0xFE8D, 1 }, /* 0x0627 R ALEF */ 596 { 0xFE8F, 3 }, /* 0x0628 D BEH */ 597 { 0xFE93, 1 }, /* 0x0629 R TEH MARBUTA */ 598 { 0xFE95, 3 }, /* 0x062A D TEH */ 599 { 0xFE99, 3 }, /* 0x062B D THEH */ 600 { 0xFE9D, 3 }, /* 0x062C D JEEM */ 601 { 0xFEA1, 3 }, /* 0x062D D HAH */ 602 { 0xFEA5, 3 }, /* 0x062E D KHAH */ 603 { 0xFEA9, 1 }, /* 0x062F R DAL */ 604 605 { 0xFEAB, 1 }, /* 0x0630 R THAL */ 606 { 0xFEAD, 1 }, /* 0x0631 R REH */ 607 { 0xFEAF, 1 }, /* 0x0632 R ZAIN */ 608 { 0xFEB1, 3 }, /* 0x0633 D SEEN */ 609 { 0xFEB5, 3 }, /* 0x0634 D SHEEN */ 610 { 0xFEB9, 3 }, /* 0x0635 D SAD */ 611 { 0xFEBD, 3 }, /* 0x0636 D DAD */ 612 { 0xFEC1, 3 }, /* 0x0637 D TAH */ 613 { 0xFEC5, 3 }, /* 0x0638 D ZAH */ 614 { 0xFEC9, 3 }, /* 0x0639 D AIN */ 615 { 0xFECD, 3 }, /* 0x063A D GHAIN */ 616 { 0x063B, 0 }, /* 0x063B */ 617 { 0x063C, 0 }, /* 0x063C */ 618 { 0x063D, 0 }, /* 0x063D */ 619 { 0x063E, 0 }, /* 0x063E */ 620 { 0x063F, 0 }, /* 0x063F */ 621 622 { 0x0640, 0 }, /* 0x0640 C TATWEEL // ### Join Causing, only one glyph */ 623 { 0xFED1, 3 }, /* 0x0641 D FEH */ 624 { 0xFED5, 3 }, /* 0x0642 D QAF */ 625 { 0xFED9, 3 }, /* 0x0643 D KAF */ 626 { 0xFEDD, 3 }, /* 0x0644 D LAM */ 627 { 0xFEE1, 3 }, /* 0x0645 D MEEM */ 628 { 0xFEE5, 3 }, /* 0x0646 D NOON */ 629 { 0xFEE9, 3 }, /* 0x0647 D HEH */ 630 { 0xFEED, 1 }, /* 0x0648 R WAW */ 631 { 0x0649, 3 }, /* 0x0649 ALEF MAKSURA // ### Dual, glyphs not consecutive, handle in code. */ 632 { 0xFEF1, 3 }, /* 0x064A D YEH */ 633 { 0x064B, 0 }, /* 0x064B */ 634 { 0x064C, 0 }, /* 0x064C */ 635 { 0x064D, 0 }, /* 0x064D */ 636 { 0x064E, 0 }, /* 0x064E */ 637 { 0x064F, 0 }, /* 0x064F */ 638 639 { 0x0650, 0 }, /* 0x0650 */ 640 { 0x0651, 0 }, /* 0x0651 */ 641 { 0x0652, 0 }, /* 0x0652 */ 642 { 0x0653, 0 }, /* 0x0653 */ 643 { 0x0654, 0 }, /* 0x0654 */ 644 { 0x0655, 0 }, /* 0x0655 */ 645 { 0x0656, 0 }, /* 0x0656 */ 646 { 0x0657, 0 }, /* 0x0657 */ 647 { 0x0658, 0 }, /* 0x0658 */ 648 { 0x0659, 0 }, /* 0x0659 */ 649 { 0x065A, 0 }, /* 0x065A */ 650 { 0x065B, 0 }, /* 0x065B */ 651 { 0x065C, 0 }, /* 0x065C */ 652 { 0x065D, 0 }, /* 0x065D */ 653 { 0x065E, 0 }, /* 0x065E */ 654 { 0x065F, 0 }, /* 0x065F */ 655 656 { 0x0660, 0 }, /* 0x0660 */ 657 { 0x0661, 0 }, /* 0x0661 */ 658 { 0x0662, 0 }, /* 0x0662 */ 659 { 0x0663, 0 }, /* 0x0663 */ 660 { 0x0664, 0 }, /* 0x0664 */ 661 { 0x0665, 0 }, /* 0x0665 */ 662 { 0x0666, 0 }, /* 0x0666 */ 663 { 0x0667, 0 }, /* 0x0667 */ 664 { 0x0668, 0 }, /* 0x0668 */ 665 { 0x0669, 0 }, /* 0x0669 */ 666 { 0x066A, 0 }, /* 0x066A */ 667 { 0x066B, 0 }, /* 0x066B */ 668 { 0x066C, 0 }, /* 0x066C */ 669 { 0x066D, 0 }, /* 0x066D */ 670 { 0x066E, 0 }, /* 0x066E */ 671 { 0x066F, 0 }, /* 0x066F */ 672 673 { 0x0670, 0 }, /* 0x0670 */ 674 { 0xFB50, 1 }, /* 0x0671 R ALEF WASLA */ 675 { 0x0672, 0 }, /* 0x0672 */ 676 { 0x0673, 0 }, /* 0x0673 */ 677 { 0x0674, 0 }, /* 0x0674 */ 678 { 0x0675, 0 }, /* 0x0675 */ 679 { 0x0676, 0 }, /* 0x0676 */ 680 { 0x0677, 0 }, /* 0x0677 */ 681 { 0x0678, 0 }, /* 0x0678 */ 682 { 0xFB66, 3 }, /* 0x0679 D TTEH */ 683 { 0xFB5E, 3 }, /* 0x067A D TTEHEH */ 684 { 0xFB52, 3 }, /* 0x067B D BEEH */ 685 { 0x067C, 0 }, /* 0x067C */ 686 { 0x067D, 0 }, /* 0x067D */ 687 { 0xFB56, 3 }, /* 0x067E D PEH */ 688 { 0xFB62, 3 }, /* 0x067F D TEHEH */ 689 690 { 0xFB5A, 3 }, /* 0x0680 D BEHEH */ 691 { 0x0681, 0 }, /* 0x0681 */ 692 { 0x0682, 0 }, /* 0x0682 */ 693 { 0xFB76, 3 }, /* 0x0683 D NYEH */ 694 { 0xFB72, 3 }, /* 0x0684 D DYEH */ 695 { 0x0685, 0 }, /* 0x0685 */ 696 { 0xFB7A, 3 }, /* 0x0686 D TCHEH */ 697 { 0xFB7E, 3 }, /* 0x0687 D TCHEHEH */ 698 { 0xFB88, 1 }, /* 0x0688 R DDAL */ 699 { 0x0689, 0 }, /* 0x0689 */ 700 { 0x068A, 0 }, /* 0x068A */ 701 { 0x068B, 0 }, /* 0x068B */ 702 { 0xFB84, 1 }, /* 0x068C R DAHAL */ 703 { 0xFB82, 1 }, /* 0x068D R DDAHAL */ 704 { 0xFB86, 1 }, /* 0x068E R DUL */ 705 { 0x068F, 0 }, /* 0x068F */ 706 707 { 0x0690, 0 }, /* 0x0690 */ 708 { 0xFB8C, 1 }, /* 0x0691 R RREH */ 709 { 0x0692, 0 }, /* 0x0692 */ 710 { 0x0693, 0 }, /* 0x0693 */ 711 { 0x0694, 0 }, /* 0x0694 */ 712 { 0x0695, 0 }, /* 0x0695 */ 713 { 0x0696, 0 }, /* 0x0696 */ 714 { 0x0697, 0 }, /* 0x0697 */ 715 { 0xFB8A, 1 }, /* 0x0698 R JEH */ 716 { 0x0699, 0 }, /* 0x0699 */ 717 { 0x069A, 0 }, /* 0x069A */ 718 { 0x069B, 0 }, /* 0x069B */ 719 { 0x069C, 0 }, /* 0x069C */ 720 { 0x069D, 0 }, /* 0x069D */ 721 { 0x069E, 0 }, /* 0x069E */ 722 { 0x069F, 0 }, /* 0x069F */ 723 724 { 0x06A0, 0 }, /* 0x06A0 */ 725 { 0x06A1, 0 }, /* 0x06A1 */ 726 { 0x06A2, 0 }, /* 0x06A2 */ 727 { 0x06A3, 0 }, /* 0x06A3 */ 728 { 0xFB6A, 3 }, /* 0x06A4 D VEH */ 729 { 0x06A5, 0 }, /* 0x06A5 */ 730 { 0xFB6E, 3 }, /* 0x06A6 D PEHEH */ 731 { 0x06A7, 0 }, /* 0x06A7 */ 732 { 0x06A8, 0 }, /* 0x06A8 */ 733 { 0xFB8E, 3 }, /* 0x06A9 D KEHEH */ 734 { 0x06AA, 0 }, /* 0x06AA */ 735 { 0x06AB, 0 }, /* 0x06AB */ 736 { 0x06AC, 0 }, /* 0x06AC */ 737 { 0xFBD3, 3 }, /* 0x06AD D NG */ 738 { 0x06AE, 0 }, /* 0x06AE */ 739 { 0xFB92, 3 }, /* 0x06AF D GAF */ 740 741 { 0x06B0, 0 }, /* 0x06B0 */ 742 { 0xFB9A, 3 }, /* 0x06B1 D NGOEH */ 743 { 0x06B2, 0 }, /* 0x06B2 */ 744 { 0xFB96, 3 }, /* 0x06B3 D GUEH */ 745 { 0x06B4, 0 }, /* 0x06B4 */ 746 { 0x06B5, 0 }, /* 0x06B5 */ 747 { 0x06B6, 0 }, /* 0x06B6 */ 748 { 0x06B7, 0 }, /* 0x06B7 */ 749 { 0x06B8, 0 }, /* 0x06B8 */ 750 { 0x06B9, 0 }, /* 0x06B9 */ 751 { 0xFB9E, 1 }, /* 0x06BA R NOON GHUNNA */ 752 { 0xFBA0, 3 }, /* 0x06BB D RNOON */ 753 { 0x06BC, 0 }, /* 0x06BC */ 754 { 0x06BD, 0 }, /* 0x06BD */ 755 { 0xFBAA, 3 }, /* 0x06BE D HEH DOACHASHMEE */ 756 { 0x06BF, 0 }, /* 0x06BF */ 757 758 { 0xFBA4, 1 }, /* 0x06C0 R HEH WITH YEH ABOVE */ 759 { 0xFBA6, 3 }, /* 0x06C1 D HEH GOAL */ 760 { 0x06C2, 0 }, /* 0x06C2 */ 761 { 0x06C3, 0 }, /* 0x06C3 */ 762 { 0x06C4, 0 }, /* 0x06C4 */ 763 { 0xFBE0, 1 }, /* 0x06C5 R KIRGHIZ OE */ 764 { 0xFBD9, 1 }, /* 0x06C6 R OE */ 765 { 0xFBD7, 1 }, /* 0x06C7 R U */ 766 { 0xFBDB, 1 }, /* 0x06C8 R YU */ 767 { 0xFBE2, 1 }, /* 0x06C9 R KIRGHIZ YU */ 768 { 0x06CA, 0 }, /* 0x06CA */ 769 { 0xFBDE, 1 }, /* 0x06CB R VE */ 770 { 0xFBFC, 3 }, /* 0x06CC D FARSI YEH */ 771 { 0x06CD, 0 }, /* 0x06CD */ 772 { 0x06CE, 0 }, /* 0x06CE */ 773 { 0x06CF, 0 }, /* 0x06CF */ 774 775 { 0xFBE4, 3 }, /* 0x06D0 D E */ 776 { 0x06D1, 0 }, /* 0x06D1 */ 777 { 0xFBAE, 1 }, /* 0x06D2 R YEH BARREE */ 778 { 0xFBB0, 1 }, /* 0x06D3 R YEH BARREE WITH HAMZA ABOVE */ 779 { 0x06D4, 0 }, /* 0x06D4 */ 780 { 0x06D5, 0 }, /* 0x06D5 */ 781 { 0x06D6, 0 }, /* 0x06D6 */ 782 { 0x06D7, 0 }, /* 0x06D7 */ 783 { 0x06D8, 0 }, /* 0x06D8 */ 784 { 0x06D9, 0 }, /* 0x06D9 */ 785 { 0x06DA, 0 }, /* 0x06DA */ 786 { 0x06DB, 0 }, /* 0x06DB */ 787 { 0x06DC, 0 }, /* 0x06DC */ 788 { 0x06DD, 0 }, /* 0x06DD */ 789 { 0x06DE, 0 }, /* 0x06DE */ 790 { 0x06DF, 0 }, /* 0x06DF */ 791 792 { 0x06E0, 0 }, /* 0x06E0 */ 793 { 0x06E1, 0 }, /* 0x06E1 */ 794 { 0x06E2, 0 }, /* 0x06E2 */ 795 { 0x06E3, 0 }, /* 0x06E3 */ 796 { 0x06E4, 0 }, /* 0x06E4 */ 797 { 0x06E5, 0 }, /* 0x06E5 */ 798 { 0x06E6, 0 }, /* 0x06E6 */ 799 { 0x06E7, 0 }, /* 0x06E7 */ 800 { 0x06E8, 0 }, /* 0x06E8 */ 801 { 0x06E9, 0 }, /* 0x06E9 */ 802 { 0x06EA, 0 }, /* 0x06EA */ 803 { 0x06EB, 0 }, /* 0x06EB */ 804 { 0x06EC, 0 }, /* 0x06EC */ 805 { 0x06ED, 0 }, /* 0x06ED */ 806 { 0x06EE, 0 }, /* 0x06EE */ 807 { 0x06EF, 0 }, /* 0x06EF */ 808 809 { 0x06F0, 0 }, /* 0x06F0 */ 810 { 0x06F1, 0 }, /* 0x06F1 */ 811 { 0x06F2, 0 }, /* 0x06F2 */ 812 { 0x06F3, 0 }, /* 0x06F3 */ 813 { 0x06F4, 0 }, /* 0x06F4 */ 814 { 0x06F5, 0 }, /* 0x06F5 */ 815 { 0x06F6, 0 }, /* 0x06F6 */ 816 { 0x06F7, 0 }, /* 0x06F7 */ 817 { 0x06F8, 0 }, /* 0x06F8 */ 818 { 0x06F9, 0 }, /* 0x06F9 */ 819 { 0x06FA, 0 }, /* 0x06FA */ 820 { 0x06FB, 0 }, /* 0x06FB */ 821 { 0x06FC, 0 }, /* 0x06FC */ 822 { 0x06FD, 0 }, /* 0x06FD */ 823 { 0x06FE, 0 }, /* 0x06FE */ 824 { 0x06FF, 0 } /* 0x06FF */ 825 }; 826 827 /* the arabicUnicodeMapping does not work for U+0649 ALEF MAKSURA, this table does */ 828 static const hb_uint16 alefMaksura[4] = {0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9}; 829 830 /* 831 // this is a bit tricky. Alef always binds to the right, so the second parameter descibing the shape 832 // of the lam can be either initial of medial. So initial maps to the isolated form of the ligature, 833 // medial to the final form 834 */ 835 static const hb_uint16 arabicUnicodeLamAlefMapping[6][4] = { 836 { 0xfffd, 0xfffd, 0xfef5, 0xfef6 }, /* 0x622 R Alef with Madda above */ 837 { 0xfffd, 0xfffd, 0xfef7, 0xfef8 }, /* 0x623 R Alef with Hamza above */ 838 { 0xfffd, 0xfffd, 0xfffd, 0xfffd }, /* 0x624 // Just to fill the table ;-) */ 839 { 0xfffd, 0xfffd, 0xfef9, 0xfefa }, /* 0x625 R Alef with Hamza below */ 840 { 0xfffd, 0xfffd, 0xfffd, 0xfffd }, /* 0x626 // Just to fill the table ;-) */ 841 { 0xfffd, 0xfffd, 0xfefb, 0xfefc } /* 0x627 R Alef */ 842 }; 843 844 static int getShape(hb_uint8 cell, int shape) 845 { 846 /* the arabicUnicodeMapping does not work for U+0649 ALEF MAKSURA, handle this here */ 847 int ch = (cell != 0x49) 848 ? (shape ? arabicUnicodeMapping[cell][0] + shape : 0x600+cell) 849 : alefMaksura[shape] ; 850 return ch; 851 } 852 853 854 /* 855 Two small helper functions for arabic shaping. 856 */ 857 static HB_UChar16 prevChar(const HB_UChar16 *str, int pos) 858 { 859 /*qDebug("leftChar: pos=%d", pos); */ 860 const HB_UChar16 *ch = str + pos - 1; 861 pos--; 862 while(pos > -1) { 863 if(HB_GetUnicodeCharCategory(*ch) != HB_Mark_NonSpacing) 864 return *ch; 865 pos--; 866 ch--; 867 } 868 return ReplacementCharacter; 869 } 870 871 static HB_UChar16 nextChar(const HB_UChar16 *str, hb_uint32 len, hb_uint32 pos) 872 { 873 const HB_UChar16 *ch = str + pos + 1; 874 pos++; 875 while(pos < len) { 876 /*qDebug("rightChar: %d isLetter=%d, joining=%d", pos, ch.isLetter(), ch.joining()); */ 877 if(HB_GetUnicodeCharCategory(*ch) != HB_Mark_NonSpacing) 878 return *ch; 879 /* assume it's a transparent char, this might not be 100% correct */ 880 pos++; 881 ch++; 882 } 883 return ReplacementCharacter; 884 } 885 886 static void shapedString(const HB_UChar16 *uc, hb_uint32 stringLength, hb_uint32 from, hb_uint32 len, HB_UChar16 *shapeBuffer, int *shapedLength, 887 HB_Bool reverse, HB_GlyphAttributes *attributes, unsigned short *logClusters) 888 { 889 HB_ArabicProperties *properties; 890 hb_int32 f = from; 891 hb_uint32 l = len; 892 const HB_UChar16 *ch; 893 HB_UChar16 *data; 894 int clusterStart; 895 hb_uint32 i; 896 HB_STACKARRAY(HB_ArabicProperties, props, len + 2); 897 properties = props; 898 899 assert(stringLength >= from + len); 900 901 if(len == 0) { 902 *shapedLength = 0; 903 return; 904 } 905 906 if (from > 0) { 907 --f; 908 ++l; 909 ++properties; 910 } 911 if (f + l < stringLength) 912 ++l; 913 getArabicProperties(uc+f, l, props); 914 915 ch = uc + from; 916 data = shapeBuffer; 917 clusterStart = 0; 918 919 for (i = 0; i < len; i++) { 920 hb_uint8 r = *ch >> 8; 921 int gpos = data - shapeBuffer; 922 923 if (r != 0x06) { 924 if (r == 0x20) { 925 if (*ch == 0x200c || *ch == 0x200d) 926 /* remove ZWJ and ZWNJ */ 927 goto skip; 928 } 929 if (reverse) 930 *data = HB_GetMirroredChar(*ch); 931 else 932 *data = *ch; 933 } else { 934 hb_uint8 c = *ch & 0xff; 935 int pos = i + from; 936 int shape = properties[i].shape; 937 /* qDebug("mapping U+%x to shape %d glyph=0x%x", ch->unicode(), shape, getShape(c, shape)); */ 938 /* take care of lam-alef ligatures (lam right of alef) */ 939 hb_uint16 map; 940 switch (c) { 941 case 0x44: { /* lam */ 942 const HB_UChar16 pch = nextChar(uc, stringLength, pos); 943 if ((pch >> 8) == 0x06) { 944 switch (pch & 0xff) { 945 case 0x22: 946 case 0x23: 947 case 0x25: 948 case 0x27: 949 /* qDebug(" lam of lam-alef ligature"); */ 950 map = arabicUnicodeLamAlefMapping[(pch & 0xff) - 0x22][shape]; 951 goto next; 952 default: 953 break; 954 } 955 } 956 break; 957 } 958 case 0x22: /* alef with madda */ 959 case 0x23: /* alef with hamza above */ 960 case 0x25: /* alef with hamza below */ 961 case 0x27: /* alef */ 962 if (prevChar(uc, pos) == 0x0644) { 963 /* have a lam alef ligature */ 964 /*qDebug(" alef of lam-alef ligature"); */ 965 goto skip; 966 } 967 default: 968 break; 969 } 970 map = getShape(c, shape); 971 next: 972 *data = map; 973 } 974 /* ##### Fixme */ 975 /*glyphs[gpos].attributes.zeroWidth = zeroWidth; */ 976 if (HB_GetUnicodeCharCategory(*ch) == HB_Mark_NonSpacing) { 977 attributes[gpos].mark = TRUE; 978 /* qDebug("glyph %d (char %d) is mark!", gpos, i); */ 979 } else { 980 attributes[gpos].mark = FALSE; 981 clusterStart = data - shapeBuffer; 982 } 983 attributes[gpos].clusterStart = !attributes[gpos].mark; 984 attributes[gpos].combiningClass = HB_GetUnicodeCharCombiningClass(*ch); 985 attributes[gpos].justification = properties[i].justification; 986 /* qDebug("data[%d] = %x (from %x)", gpos, (uint)data->unicode(), ch->unicode());*/ 987 data++; 988 skip: 989 ch++; 990 logClusters[i] = clusterStart; 991 } 992 *shapedLength = data - shapeBuffer; 993 994 HB_FREE_STACKARRAY(props); 995 } 996 997 #ifndef NO_OPENTYPE 998 999 static const HB_OpenTypeFeature arabic_features[] = { 1000 { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty }, 1001 { HB_MAKE_TAG('i', 's', 'o', 'l'), IsolProperty }, 1002 { HB_MAKE_TAG('f', 'i', 'n', 'a'), FinaProperty }, 1003 { HB_MAKE_TAG('m', 'e', 'd', 'i'), MediProperty }, 1004 { HB_MAKE_TAG('i', 'n', 'i', 't'), InitProperty }, 1005 { HB_MAKE_TAG('r', 'l', 'i', 'g'), RligProperty }, 1006 { HB_MAKE_TAG('c', 'a', 'l', 't'), CaltProperty }, 1007 { HB_MAKE_TAG('l', 'i', 'g', 'a'), LigaProperty }, 1008 { HB_MAKE_TAG('d', 'l', 'i', 'g'), DligProperty }, 1009 { HB_MAKE_TAG('c', 's', 'w', 'h'), CswhProperty }, 1010 /* mset is used in old Win95 fonts that don't have a 'mark' positioning table. */ 1011 { HB_MAKE_TAG('m', 's', 'e', 't'), MsetProperty }, 1012 {0, 0} 1013 }; 1014 1015 static const HB_OpenTypeFeature syriac_features[] = { 1016 { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty }, 1017 { HB_MAKE_TAG('i', 's', 'o', 'l'), IsolProperty }, 1018 { HB_MAKE_TAG('f', 'i', 'n', 'a'), FinaProperty }, 1019 { HB_MAKE_TAG('f', 'i', 'n', '2'), FinaProperty }, 1020 { HB_MAKE_TAG('f', 'i', 'n', '3'), FinaProperty }, 1021 { HB_MAKE_TAG('m', 'e', 'd', 'i'), MediProperty }, 1022 { HB_MAKE_TAG('m', 'e', 'd', '2'), MediProperty }, 1023 { HB_MAKE_TAG('i', 'n', 'i', 't'), InitProperty }, 1024 { HB_MAKE_TAG('r', 'l', 'i', 'g'), RligProperty }, 1025 { HB_MAKE_TAG('c', 'a', 'l', 't'), CaltProperty }, 1026 { HB_MAKE_TAG('l', 'i', 'g', 'a'), LigaProperty }, 1027 { HB_MAKE_TAG('d', 'l', 'i', 'g'), DligProperty }, 1028 {0, 0} 1029 }; 1030 1031 static HB_Bool arabicSyriacOpenTypeShape(HB_ShaperItem *item, HB_Bool *ot_ok) 1032 { 1033 const HB_UChar16 *uc; 1034 const int nglyphs = item->num_glyphs; 1035 hb_int32 f; 1036 hb_uint32 l; 1037 HB_ArabicProperties *properties; 1038 HB_DECLARE_STACKARRAY(HB_ArabicProperties, props) 1039 HB_DECLARE_STACKARRAY(hb_uint32, apply) 1040 HB_Bool shaped; 1041 int i = 0; 1042 1043 *ot_ok = TRUE; 1044 1045 if (!HB_ConvertStringToGlyphIndices(item)) 1046 return FALSE; 1047 HB_HeuristicSetGlyphAttributes(item); 1048 1049 HB_INIT_STACKARRAY(HB_ArabicProperties, props, item->item.length + 2); 1050 HB_INIT_STACKARRAY(hb_uint32, apply, item->num_glyphs); 1051 1052 uc = item->string + item->item.pos; 1053 1054 properties = props; 1055 f = 0; 1056 l = item->item.length; 1057 if (item->item.pos > 0) { 1058 --f; 1059 ++l; 1060 ++properties; 1061 } 1062 if (f + l + item->item.pos < item->stringLength) { 1063 ++l; 1064 } 1065 if (item->item.script == HB_Script_Nko) 1066 getNkoProperties(uc+f, l, props); 1067 else 1068 getArabicProperties(uc+f, l, props); 1069 1070 for (i = 0; i < (int)item->num_glyphs; i++) { 1071 apply[i] = 0; 1072 1073 if (properties[i].shape == XIsolated) 1074 apply[i] |= MediProperty|FinaProperty|InitProperty; 1075 else if (properties[i].shape == XMedial) 1076 apply[i] |= IsolProperty|FinaProperty|InitProperty; 1077 else if (properties[i].shape == XFinal) 1078 apply[i] |= IsolProperty|MediProperty|InitProperty; 1079 else if (properties[i].shape == XInitial) 1080 apply[i] |= IsolProperty|MediProperty|FinaProperty; 1081 1082 item->attributes[i].justification = properties[i].justification; 1083 } 1084 1085 HB_FREE_STACKARRAY(props); 1086 1087 shaped = HB_OpenTypeShape(item, apply); 1088 1089 HB_FREE_STACKARRAY(apply); 1090 1091 if (!shaped) { 1092 *ot_ok = FALSE; 1093 return FALSE; 1094 } 1095 return HB_OpenTypePosition(item, nglyphs, /*doLogClusters*/TRUE); 1096 } 1097 1098 #endif 1099 1100 /* #### stil missing: identify invalid character combinations */ 1101 HB_Bool HB_ArabicShape(HB_ShaperItem *item) 1102 { 1103 int slen; 1104 HB_Bool haveGlyphs; 1105 HB_STACKARRAY(HB_UChar16, shapedChars, item->item.length); 1106 1107 assert(item->item.script == HB_Script_Arabic || item->item.script == HB_Script_Syriac 1108 || item->item.script == HB_Script_Nko); 1109 1110 #ifndef NO_OPENTYPE 1111 1112 if (HB_SelectScript(item, item->item.script == HB_Script_Arabic ? arabic_features : syriac_features)) { 1113 HB_Bool ot_ok; 1114 if (arabicSyriacOpenTypeShape(item, &ot_ok)) { 1115 HB_FREE_STACKARRAY(shapedChars); 1116 return TRUE; 1117 } 1118 if (ot_ok) { 1119 HB_FREE_STACKARRAY(shapedChars); 1120 return FALSE; 1121 /* fall through to the non OT code*/ 1122 } 1123 } 1124 #endif 1125 1126 if (item->item.script != HB_Script_Arabic) { 1127 HB_FREE_STACKARRAY(shapedChars); 1128 return HB_BasicShape(item); 1129 } 1130 1131 shapedString(item->string, item->stringLength, item->item.pos, item->item.length, shapedChars, &slen, 1132 item->item.bidiLevel % 2, 1133 item->attributes, item->log_clusters); 1134 1135 haveGlyphs = item->font->klass 1136 ->convertStringToGlyphIndices(item->font, 1137 shapedChars, slen, 1138 item->glyphs, &item->num_glyphs, 1139 item->item.bidiLevel % 2); 1140 1141 HB_FREE_STACKARRAY(shapedChars); 1142 1143 if (!haveGlyphs) 1144 return FALSE; 1145 1146 HB_HeuristicPosition(item); 1147 return TRUE; 1148 } 1149 1150 1151